本文通過設計演講比賽流程管理系統,全面介紹了使用C++面向對象編程思想開發項目應用的過程,涵蓋了需求分析、系統架構設計、類的提取,以及採用多種STL容器配合演算法的具體實現。文中詳細展示了構建選手類、管理類,設計菜單界面與用戶交互、實現兩輪比賽流程的抽簽、評分模塊,並能夠完成記錄文件的讀寫與管理 ...
演講比賽流程管理系統
1. 演講比賽程式需求
1.1 比賽規則
-
學校舉行一場演講比賽,共有12個人參加。比賽共兩輪,第一輪為淘汰賽,第二輪為決賽
-
每名選手都有對應的編號,如 10001 ~ 10012
-
比賽方式:分組比賽,每組6個人
-
第一輪分為兩個小組,整體按照選手編號進行抽簽後順序演講
-
10個評委分別給每名選手打分,去除最高分和最低分,求得平均分為本輪選手的成績
-
當小組演講完後,淘汰組內排名最後的三個選手,前三名晉級,進入下一輪的比賽
-
第二輪為決賽,前三名勝出
-
每輪比賽過後需要顯示晉級選手的信息
1.2 程式功能
- 開始演講比賽:完成整屆比賽的流程,每個比賽階段需要給用戶一個提示,用戶按任意鍵後繼續下一個階段
- 查看往屆記錄:查看之前比賽前三名結果,每次比賽都會記錄到文件中,文件用.csv尾碼名保存
- 清空比賽記錄:將文件中數據清空
- 退出比賽程式:可以退出當前程式
2. 創建管理類
功能描述:
-
提供菜單界面與用戶交互
-
對演講比賽流程進行控制
-
與文件的讀寫交互
2.1創建文件
在頭文件和源文件的文件夾下分別創建 speechManager.h
和 speechManager.cpp
文件
2.2 頭文件實現
在 speechManager.h
中設計管理類
代碼如下:
#pragma once
class SpeechManager
{
public:
//構造函數
SpeechManager();
//析構函數
~SpeechManager();
};
2.3 源文件實現
在 speechManager.cpp
中將構造和析構函數空實現補全
#include "speechManager.h"
SpeechManager::SpeechManager()
{
}
SpeechManager::~SpeechManager()
{
}
至此演講管理類以創建完畢
3. 菜單功能
功能描述:與用戶的溝通界面
3.1 添加成員函數
在管理類 speechManager.h
中添加成員函數 void show_Menu();
//菜單界面
void show_Menu();
3.2 菜單功能實現
在管理類 speechManager.cpp
中實現 show_Menu()
函數
void SpeechManager::show_Menu()
{
std::cout << "********************************************" << std::endl;
std::cout << "************* 歡迎參加演講比賽 ************" << std::endl;
std::cout << "************* 1.開始演講比賽 *************" << std::endl;
std::cout << "************* 2.查看往屆記錄 *************" << std::endl;
std::cout << "************* 3.清空比賽記錄 *************" << std::endl;
std::cout << "************* 0.退出比賽程式 *************" << std::endl;
std::cout << "********************************************" << std::endl;
std::cout << std::endl;
}
3.3 測試菜單功能
在演講比賽流程管理系統.cpp中測試菜單功能
代碼:
#include <iostream>
#include "speechManager.h"
int main()
{
SpeechManager spm;
spm.show_Menu();
return 0;
}
菜單界面搭建完畢
4. 退出功能
4.1 提供功能介面
在main函數中提供分支選擇,提供每個功能介面
代碼:
#include <iostream>
#include "speechManager.h"
int main()
{
SpeechManager spm;
int choise = 0;
while (true)
{
spm.show_Menu();
std::cout << "請輸入選項: ";
std::cin >> choise;
switch (choise)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 0:
spm.exitSystem();
break;
default:
break;
}
}
return 0;
}
4.2 實現退出功能
在 speechManager.h
中提供退出系統的成員函數 void exitSystem();
//退出界面
void exitSystem();
在 speechManager.cpp
中提供具體的功能實現
void SpeechManager::exitSystem()
{
std::cout << "~歡迎下次使用~" << std::endl;
system("pause");
exit(0);
}
4.3測試功能
在main函數分支 0 選項中,調用退出程式的介面
#include <iostream>
#include "speechManager.h"
int main()
{
SpeechManager spm;
int choise = 0;
while (true)
{
spm.show_Menu();
std::cout << "請輸入選項: ";
std::cin >> choise;
switch (choise)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 0:
spm.exitSystem();
break;
default:
break;
}
}
return 0;
}
5. 演講比賽功能
5.1 功能分析
比賽流程分析:
抽簽 → 開始演講比賽 → 顯示第一輪比賽結果 →
抽簽 → 開始演講比賽 → 顯示前三名結果 → 保存分數
5.2 創建選手類
選手類中的屬性包含:選手姓名、分數
頭文件中創建 speaker.h
文件,並添加代碼:
#pragma once
#include <iostream>
class Speaker
{
public:
std::string m_Name; //選手姓名
double m_Score[2]; //選手分數,至多存放兩輪
};
5.3 比賽
5.3.1 成員屬性添加
在 speechManager.h
中添加屬性
//容器1: 存放12位選手的編號
std::vector<int> v1;
//容器2: 存放6位選手的編號
std::vector<int> v2;
//容器3: 存放3位選手的編號
std::vector<int> v_Victory;
//容器4: 存放Speaker的編號和對應的選手
std::map<int, Speaker> m_Speaker;
//比賽輪數
int m_Round;
5.3.2 初始化屬性
在 speechManager.h
中提供開始比賽的的成員函數 void initSpeech();
void initSpeaker();
在 speechManager.cpp
中實現開始比賽的的成員函數 void initSpeech();
void SpeechManager::initSpeaker()
{
//清空容器
this->v1.clear();
this->v2.clear();
this->v_Victory.clear();
this->m_Speaker.clear();
//第一輪比賽
this->m_Round = 1;
}
在 SpeechManager
構造函數中調用void initSpeech();
SpeechManager::SpeechManager()
{
//初始化
this->initSpeaker();
}
5.3.3 創建選手
在 speechManager.h
中提供開始比賽的的成員函數 void createSpeaker();
//創建選手
void createSpeaker();
在 speechManager.cpp
中實現開始比賽的的成員函數 void createSpeaker();
void SpeechManager::createSpeaker()
{
std::string nameSeed = "ABCDEFGHIJKL";
for (int i = 0; i < nameSeed.size(); i++)
{
//初始化選手中的屬性
Speaker sp;
sp.m_Name = "選手";
sp.m_Name += nameSeed[i];
for (int j = 0; j < 2; j++)
{
sp.m_Score[j] = 0;
}
//將初始化後的選手放入容器中
this->v1.push_back(i + 1000);
this->m_Speaker.insert(std::pair<int, Speaker>(i + 1000, sp));
}
}
SpeechManager
類的 構造函數中調用 void createSpeaker();
SpeechManager::SpeechManager()
{
//初始化
this->initSpeaker();
//創建選手
this->createSpeaker();
}
測試 在main函數中,可以在創建完管理對象後,使用下列代碼測試12名選手初始狀態
for (std::map<int, Speaker>::iterator it = spm.m_Speaker.begin(); it != spm.m_Speaker.end(); it++)
{
std::cout
<< it->first << " "
<< it->second.m_Name << " "
<< (*it).second.m_Score[0] << std::endl;
}
5.3.4 開始比賽成員函數添加
在 speechManager.h
中提供開始比賽的的成員函數 void startSpeech();
該函數功能是主要控制比賽的流程
//開始比賽 - 比賽流程式控制制
void startSpeech();
在 speechManager.cpp
中將 startSpeech
的空實現先寫入
我們可以先將整個比賽的流程 寫到函數中
void SpeechManager::startSpeech()
{
//第一輪比賽
//1、抽簽
//2、比賽
//3、顯示晉級結果
//第二輪比賽
//1、抽簽
//2、比賽
//3、顯示最終結果
//4、保存分數
}
5.3.5 抽簽
功能描述:
正式比賽前,所有選手的比賽順序需要打亂,我們只需要將存放選手編號的容器 打亂次序即可
在 speechManager.h
中提供抽簽的的成員函數 void speechDraw();
//抽簽
void speechDraw();
在 speechManager.cpp
中實現成員函數 void speechDraw();
void SpeechManager::speechDraw()
{
std::cout << "第" << this->m_Round << "輪比賽開始抽簽" << std::endl;
std::cout << "=*=*=*=*=*=*=*=*=" << std::endl;
std::cout << "抽簽後演講順序如下: " << std::endl;
if (this->m_Round == 1)
{
std::random_shuffle(this->v1.begin(), this->v1.end());
for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
else
{
std::random_shuffle(this->v2.begin(), this->v2.end());
for (std::vector<int>::iterator it = v2.begin(); it != v2.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
std::cout << "=*=*=*=*=*=*=*=*=" << std::endl;
system("pause");
std::cout << std::endl;
}
在 startSpeech
比賽流程式控制制的函數中,調用抽簽函數
void SpeechManager::startSpeech()
{
//第一輪比賽
//1、抽簽
this->speechDraw();
//2、比賽
//3、顯示晉級結果
//第二輪比賽
//1、抽簽
//2、比賽
//3、顯示最終結果
//4、保存分數
}
5.3.6 開始比賽
在 speechManager.h
中提供比賽的的成員函數 void speechContest();
//打分
void speechContest();
在 speechManager.cpp
中實現成員函數 void speechContest();
void SpeechManager::speechContest()
{
std::cout << "==========第" << this->m_Round << "輪比賽開始==========" << std::endl;
//定義一個臨時存放需要比賽的選手的容器
std::vector<int> v_Src;
if (this->m_Round == 1)
{
v_Src = v1;
}
else
{
v_Src = v2;
}
//定義一個臨時存放平均分的容器
std::multimap<double, int, std::greater<int>> groupScore;
//定義一個分組變數,記錄人數
//目的是讓每6個選手為1組
int grouping = 0;
//取出需要參賽的選手的編號
for (std::vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
{
++grouping;
//定義評委打分容器,為每一組中的每一位選手打分
//選用deque容器是因為饞它的pop_back和pop_front
std::deque<double> scoring;
for (std::vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
{
double score = (rand() % 601 + 400) / 10.0f; //(0+600~400+600) / 10 = 60~100
scoring.push_back(score);
//std::cout << score << " ";
}
//std::cout << std::endl;
//打分結束後需要計算平均分
std::sort(scoring.begin(), scoring.end(), std::greater<double>());
scoring.pop_front(); //去掉一個最低分
scoring.pop_back(); //去掉一個最高分
double avg = std::accumulate(scoring.begin(), scoring.end(), 0.0f) / (double)scoring.size();
//直接把平均分插入到m_Speaker的m_Score[m_Round-1]里,第一輪里12個人都有分數
//Speaker sp = this->m_Speaker[*it];
//sp.m_Score[this->m_Round - 1] = avg;
this->m_Speaker[*it].m_Score[this->m_Round - 1] = avg;
//將平均分放入到臨時的multimap容器里
//其中multimap的鍵值對為 <平均分, 選手編號>
groupScore.insert(std::multimap<double, int, std::greater<int>>::value_type(avg, *it));
//如果是第6個人或第12個人,做一次分組
if (grouping % 6 == 0)
{
std::cout << "第" << grouping / 6 << "小組比賽名次如下:" << std::endl;
for (std::multimap<double, int, std::greater<int>>::iterator it = groupScore.begin();
it != groupScore.end(); it++)
{
std::cout
<< "選手編號: " << it->second << " "
<< "選手姓名: " << this->m_Speaker[it->second].m_Name << " "
<< "選手分數: " << this->m_Speaker[it->second].m_Score[this->m_Round - 1]
<< std::endl;
}
int count_WinSpeaker = 0;
//取每組的前三個成績排名靠前的
for (std::multimap<double, int, std::greater<int>>::iterator it = groupScore.begin();
it != groupScore.end() && count_WinSpeaker < 3;
++it, ++count_WinSpeaker)
{
if (this->m_Round == 1)
{
v2.push_back(it->second);
}
else
{
v_Victory.push_back(it->second);
}
++count_WinSpeaker;
}
//每分6個人清空一次容器
groupScore.clear();
//美觀代碼
if (grouping == 6) { std::cout << std::endl; }
}
}
std::cout << "==========第" << this->m_Round << "輪比賽結束==========" << std::endl;
++this->m_Round;
system("pause");
}
在 startSpeech
比賽流程式控制制的函數中,調用比賽函數
void SpeechManager::startSpeech()
{
//第一輪比賽
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示晉級結果
//第二輪比賽
//1、抽簽
//2、比賽
//3、顯示最終結果
//4、保存分數
}
5.3.7 顯示比賽分數
在 speechManager.h
中提供比賽的的成員函數 void showScore();
//顯示分數
void showScore();
在 speechManager.cpp
中實現成員函數 void showScore();
void SpeechManager::showScore()
{
std::cout << "==========第" << this->m_Round << "輪比賽名次==========" << std::endl;
std::vector<int> v;
if (this->m_Round == 1)
{
v = v2;
}
else
{
v = v_Victory;
}
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
std::cout
<< "選手編號: " << *it << " "
<< "選手姓名: " << this->m_Speaker[*it].m_Name << " "
<< "選手分數: " << this->m_Speaker[*it].m_Score[this->m_Round - 1]
<< std::endl;
}
system("pause");
system("cls");
}
運行代碼,測試效果
5.3.8 第二輪比賽
第二輪比賽流程同第一輪,只是比賽的輪是+1,其餘流程不變
在 startSpeech
比賽流程式控制制的函數中,加入第二輪的流程
void SpeechManager::startSpeech()
{
//第一輪比賽
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示晉級結果
this->showScore();
//第二輪比賽
++this->m_Round;
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示最終結果
this->showScore();
//4、保存分數
}
5.4 保存分數
功能描述:將每次演講比賽的得分記錄到文件中
功能實現:
在 speechManager.h
中添加保存記錄的成員函數 void saveRecord();
//保存比賽分數
void saveRecord();
在 speechManager.cpp
中實現成員函數 void saveRecord();
void SpeechManager::saveRecord()
{
std::ofstream ofs("speech.csv", std::ios::out | std::ios::app);
for (std::vector<int>::iterator it = v_Victory.begin(); it != v_Victory.end(); it++)
{
ofs << *it << "," << this->m_Speaker[*it].m_Score[1] << ",";
}
ofs << std::endl;
std::cout << "保存分數完成" << std::endl;
std::cout << "本屆比賽正式結束!" << std::endl;
this->fileIsEmpty = false;
system("pause");
system("cls");
}
在 startSpeech
比賽流程式控制制的函數中,最後調用保存記錄分數函數
void SpeechManager::startSpeech()
{
//第一輪比賽
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示晉級結果
this->showScore();
//第二輪比賽
++this->m_Round;
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示最終結果
this->showScore();
//4、保存分數
this->saveRecord();
}
至此,整個演講比賽功能製作完畢!
6. 查看記錄
6.1 讀取記錄分數
-
在
speechManager.h
中添加保存記錄的成員函數void loadRecord();
-
添加判斷文件是否為空的標誌
bool fileIsEmpty;
-
添加往屆記錄的容器
map<int, vector<string>> m_Record;
其中
m_Record
中的key
代表第幾屆,value
記錄具體的信息
在 SpeechManager
構造函數中調用獲取往屆記錄函數
//讀取記錄
void loadRecord();
//文件為空的標誌
bool fileIsEmpty;
//往屆記錄
map<int, vector<string>> m_Record;
在 speechManager.cpp
中實現成員函數 void loadRecord();
void SpeechManager::loadRecord()
{
std::ifstream ifs("speech.csv", std::ios::in);
if (!ifs.is_open())
{
//std::cout << "文件不存在" << std::endl;
this->fileIsEmpty = true;
ifs.close();
return;
}
char ch;
ifs >> ch;
if (ifs.eof())
{
//std::cout << "文件為空" << std::endl;
this->fileIsEmpty = true;
ifs.close();
return;
}
//文件不為空
this->fileIsEmpty = false;
ifs.putback(ch);
std::string data;
int round = 0;
while (ifs >> data)
{
//定義獲取往屆比賽信息的容器
std::vector<std::string> v;
int pos = -1; //,號的標誌位
int start = 0;
while (true)
{
//尋找 以","號分割的字元串,找不到就結束
pos = data.find(",", start);
if (pos == -1)
{
break;
}
//substr(起始位置, 結束位置)
std::string temp = data.substr(start, pos - start);
start = pos + 1;
v.push_back(temp);
}
//將往屆的冠軍數據插入到容器中
this->m_Record.insert(std::map<int, std::vector<std::string>>::value_type(round, v));
++round;
}
ifs.close();
}
在 speechManager
構造函數中調用獲取往屆記錄函數
SpeechManager::SpeechManager()
{
//初始化
this->initSpeaker();
//創建選手
this->createSpeaker();
//查看往屆記錄
this->loadRecord();
}
6.2 查看記錄功能
在 speechManager.h
中添加保存記錄的成員函數 void showRecord();
//顯示往屆得分
void showRecord();
在 speechManager.cpp
中實現成員函數 void showRecord();
void SpeechManager::showRecord()
{
if (this->fileIsEmpty)
{
std::cout << "文件不存在,記錄為空" << std::endl;
}
else
{
for (int i = 0; i < this->m_Record.size(); i++)
{
std::cout
<< "=========第" << i + 1 << "屆=========" << "\n"
<< "冠軍編號: " << this->m_Record[i][0] << " 得分: " << this->m_Record[i][1] << "\n"
<< "亞軍編號: " << this->m_Record[i][2] << " 得分: " << this->m_Record[i][3] << "\n"
<< "季軍編號: " << this->m_Record[i][4] << " 得分: " << this->m_Record[i][5] << "\n"
<< "========================" << "\n"
<< std::endl;
}
}
system("pause");
system("cls");
}
6.3 bug解決
目前程式中有幾處bug未解決:
-
查看往屆記錄,若文件不存在或為空,並未提示
解決方式:在
showRecord
函數中,開始判斷文件狀態並加以判斷
-
若記錄為空或不存在,比完賽後依然提示記錄為空
解決方式:
saveRecord
中更新文件為空的標誌
-
比完賽後查不到本屆比賽的記錄,沒有實時更新
解決方式:比賽完畢後,所有數據重置
-
在初始化時,沒有初始化記錄容器
解決方式:
initSpeech
中添加 初始化記錄容器
每次記錄都是一樣的
解決方式:在main函數一開始 添加隨機數種子
srand((unsigned int)time(NULL));
7. 清空記錄
7.1 清空記錄功能實現
在 speechManager.h
中添加保存記錄的成員函數 void clearRecord();
//清空記錄
void clearRecord();
在 speechManager.cpp
中實現成員函數 void clearRecord();
void SpeechManager::clearRecord()
{
int choise = 0;
std::cout << "確定要清空全部的數據嗎?" << std::endl;
std::cout << "1.確定 ------ 0.返回" << std::endl;
std::cin >> choise;
if (choise == 1)
{
std::ofstream ofs("speech.csv", std::ios::trunc);
this->initSpeaker();
this->createSpeaker();
this->loadRecord();
std::cout << "清空完成!" << std::endl;
}
std::cout << "取消清空操作" << std::endl;
system("pause");
system("cls");
}
至此本案例結束!
源代碼及文件結構
├─頭文件
│ speaker.h
│ speechManager.h
│
├─源文件
│ main.cpp
│ speechManager.cpp
1. 演講者類 - Speaker
speaker.h
#pragma once
#include <iostream>
class Speaker
{
public:
std::string m_Name; //選手姓名
double m_Score[2]; //選手分數,至多存放兩輪
};
2. 演講比賽管理類 - SpeechManager
speechManager.h
#pragma once
#include <iostream>
#include <vector>
#include <map>
#include <deque>
#include <algorithm>
#include <numeric>
#include <functional>
#include <fstream>
#include "speaker.h"
class SpeechManager
{
public:
//容器1: 存放12位選手的編號
std::vector<int> v1;
//容器2: 存放6位選手的編號
std::vector<int> v2;
//容器3: 存放3位選手的編號
std::vector<int> v_Victory;
//容器4: 存放Speaker的編號和對應的選手
std::map<int, Speaker> m_Speaker;
//文件為空的標誌
bool fileIsEmpty;
//往屆記錄
std::map<int, std::vector<std::string>> m_Record;
//比賽輪數
int m_Round;
//構造函數
SpeechManager();
//菜單界面
void show_Menu();
//初始化容器
void initSpeaker();
//創建選手
void createSpeaker();
//抽簽
void speechDraw();
//打分
void speechContest();
//顯示分數
void showScore();
//保存比賽分數
void saveRecord();
//讀取記錄
void loadRecord();
//讀取往屆信息
void showRecord();
//開始比賽
void startSpeech();
//清空文件
void clearRecord();
//退出界面
void exitSystem();
//析構函數
~SpeechManager();
};
speechManager.cpp
#include "speechManager.h"
SpeechManager::SpeechManager()
{
//初始化
this->initSpeaker();
//創建選手
this->createSpeaker();
//查看往屆記錄
this->loadRecord();
}
void SpeechManager::show_Menu()
{
std::cout << "********************************************" << std::endl;
std::cout << "************* 歡迎參加演講比賽 ************" << std::endl;
std::cout << "************* 1.開始演講比賽 *************" << std::endl;
std::cout << "************* 2.查看往屆記錄 *************" << std::endl;
std::cout << "************* 3.清空比賽記錄 *************" << std::endl;
std::cout << "************* 0.退出比賽程式 *************" << std::endl;
std::cout << "********************************************" << std::endl;
std::cout << std::endl;
}
void SpeechManager::initSpeaker()
{
//清空容器
this->v1.clear();
this->v2.clear();
this->v_Victory.clear();
this->m_Speaker.clear();
this->m_Record.clear();
//第一輪比賽
this->m_Round = 1;
}
void SpeechManager::exitSystem()
{
std::cout << "~歡迎下次使用~" << std::endl;
system("pause");
exit(0);
}
void SpeechManager::createSpeaker()
{
std::string nameSeed = "ABCDEFGHIJKL";
for (int i = 0; i < nameSeed.size(); i++)
{
//初始化選手中的屬性
Speaker sp;
sp.m_Name = "選手";
sp.m_Name += nameSeed[i];
for (int j = 0; j < 2; j++)
{
sp.m_Score[j] = 0;
}
//將初始化後的選手放入容器中
this->v1.push_back(i + 1000);
this->m_Speaker.insert(std::pair<int, Speaker>(i + 1000, sp));
}
}
void SpeechManager::speechDraw()
{
std::cout << "第" << this->m_Round << "輪比賽開始抽簽" << std::endl;
std::cout << "=*=*=*=*=*=*=*=*=" << std::endl;
std::cout << "抽簽後演講順序如下: " << std::endl;
if (this->m_Round == 1)
{
std::random_shuffle(this->v1.begin(), this->v1.end());
for (std::vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
else
{
std::random_shuffle(this->v2.begin(), this->v2.end());
for (std::vector<int>::iterator it = v2.begin(); it != v2.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
std::cout << "=*=*=*=*=*=*=*=*=" << std::endl;
system("pause");
std::cout << std::endl;
}
void SpeechManager::speechContest()
{
std::cout << "==========第" << this->m_Round << "輪比賽開始==========" << std::endl;
//定義一個臨時存放需要比賽的選手的容器
std::vector<int> v_Src;
if (this->m_Round == 1)
{
v_Src = v1;
}
else
{
v_Src = v2;
}
//定義一個臨時存放平均分的容器
std::multimap<double, int, std::greater<int>> groupScore;
//定義一個分組變數,記錄人數
//目的是讓每6個選手為1組
int grouping = 0;
//取出需要參賽的選手的編號
for (std::vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
{
++grouping;
//定義評委打分容器,為每一組中的每一位選手打分
//選用deque容器是因為饞它的pop_back和pop_front
std::deque<double> scoring;
for (std::vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
{
double score = (rand() % 601 + 400) / 10.0f; //(0+600~400+600) / 10 = 60~100
scoring.push_back(score);
//std::cout << score << " ";
}
//std::cout << std::endl;
//打分結束後需要計算平均分
std::sort(scoring.begin(), scoring.end(), std::greater<double>());
scoring.pop_front(); //去掉一個最低分
scoring.pop_back(); //去掉一個最高分
double avg = std::accumulate(scoring.begin(), scoring.end(), 0.0f) / (double)scoring.size();
//直接把平均分插入到m_Speaker的m_Score[m_Round-1]里,第一輪里12個人都有分數
//Speaker sp = this->m_Speaker[*it];
//sp.m_Score[this->m_Round - 1] = avg;
this->m_Speaker[*it].m_Score[this->m_Round - 1] = avg;
//將平均分放入到臨時的multimap容器里
//其中multimap的鍵值對為 <平均分, 選手編號>
groupScore.insert(std::multimap<double, int, std::greater<int>>::value_type(avg, *it));
//如果是第6個人或第12個人,做一次分組
if (grouping % 6 == 0)
{
std::cout << "第" << grouping / 6 << "小組比賽名次如下:" << std::endl;
for (std::multimap<double, int, std::greater<int>>::iterator it = groupScore.begin();
it != groupScore.end(); it++)
{
std::cout
<< "選手編號: " << it->second << " "
<< "選手姓名: " << this->m_Speaker[it->second].m_Name << " "
<< "選手分數: " << this->m_Speaker[it->second].m_Score[this->m_Round - 1]
<< std::endl;
}
int count_WinSpeaker = 0;
//取每組的前三個成績排名靠前的
for (std::multimap<double, int, std::greater<int>>::iterator it = groupScore.begin();
it != groupScore.end() && count_WinSpeaker < 3;
++it, ++count_WinSpeaker)
{
if (this->m_Round == 1)
{
v2.push_back(it->second);
}
else
{
v_Victory.push_back(it->second);
}
}
//每分6個人清空一次容器
groupScore.clear();
//美觀代碼
if (grouping == 6) { std::cout << std::endl; }
}
}
std::cout << "==========第" << this->m_Round << "輪比賽結束==========" << std::endl;
system("pause");
}
void SpeechManager::showScore()
{
std::cout << "==========第" << this->m_Round << "輪比賽名次==========" << std::endl;
std::vector<int> v;
if (this->m_Round == 1)
{
v = v2;
}
else
{
v = v_Victory;
}
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
std::cout
<< "選手編號: " << *it << " "
<< "選手姓名: " << this->m_Speaker[*it].m_Name << " "
<< "選手分數: " << this->m_Speaker[*it].m_Score[this->m_Round - 1]
<< std::endl;
}
system("pause");
system("cls");
this->show_Menu();
}
void SpeechManager::saveRecord()
{
std::ofstream ofs("speech.csv", std::ios::out | std::ios::app);
for (std::vector<int>::iterator it = v_Victory.begin(); it != v_Victory.end(); it++)
{
ofs << *it << "," << this->m_Speaker[*it].m_Score[1] << ",";
}
ofs << std::endl;
std::cout << "保存分數完成" << std::endl;
std::cout << "本屆比賽正式結束!" << std::endl;
this->fileIsEmpty = false;
system("pause");
system("cls");
}
void SpeechManager::loadRecord()
{
std::ifstream ifs("speech.csv", std::ios::in);
if (!ifs.is_open())
{
//std::cout << "文件不存在" << std::endl;
this->fileIsEmpty = true;
ifs.close();
return;
}
char ch;
ifs >> ch;
if (ifs.eof())
{
//std::cout << "文件為空" << std::endl;
this->fileIsEmpty = true;
ifs.close();
return;
}
//文件不為空
this->fileIsEmpty = false;
ifs.putback(ch);
std::string data;
int round = 0;
while (ifs >> data)
{
//定義獲取往屆比賽信息的容器
std::vector<std::string> v;
int pos = -1; //,號的標誌位
int start = 0;
while (true)
{
//尋找 以","號分割的字元串,找不到就結束
pos = data.find(",", start);
if (pos == -1)
{
break;
}
//substr(起始位置, 結束位置)
std::string temp = data.substr(start, pos - start);
start = pos + 1;
v.push_back(temp);
}
//將往屆的冠軍數據插入到容器中
this->m_Record.insert(std::map<int, std::vector<std::string>>::value_type(round, v));
++round;
}
ifs.close();
}
void SpeechManager::showRecord()
{
if (this->fileIsEmpty)
{
std::cout << "文件不存在,記錄為空" << std::endl;
}
else
{
for (int i = 0; i < this->m_Record.size(); i++)
{
std::cout
<< "=========第" << i + 1 << "屆=========" << "\n"
<< "冠軍編號: " << this->m_Record[i][0] << " 得分: " << this->m_Record[i][1] << "\n"
<< "亞軍編號: " << this->m_Record[i][2] << " 得分: " << this->m_Record[i][3] << "\n"
<< "季軍編號: " << this->m_Record[i][4] << " 得分: " << this->m_Record[i][5] << "\n"
<< "========================" << "\n"
<< std::endl;
}
}
system("pause");
system("cls");
}
void SpeechManager::startSpeech()
{
for (int i = 0; i < 2; i++)
{
//1、抽簽
this->speechDraw();
//2、比賽
this->speechContest();
//3、顯示晉級結果
this->showScore();
//第二輪比賽
++this->m_Round;
}
//4、保存分數
this->saveRecord();
//當重覆進行插入操作時會報錯,因為初始化只有一次
//當插入次數多了之後,容器溢出
//所以每一次都需要初始化
this->initSpeaker();
this->createSpeaker();
//重置比賽,獲取記錄
//載入往屆記錄
this->loadRecord();
}
void SpeechManager::clearRecord()
{
int choise = 0;
std::cout << "確定要清空全部的數據嗎?" << std::endl;
std::cout << "1.確定 ------ 0.返回" << std::endl;
std::cin >> choise;
if (choise == 1)
{
std::ofstream ofs("speech.csv", std::ios::trunc);
this->initSpeaker();
this->createSpeaker();
this->loadRecord();
std::cout << "清空完成!" << std::endl;
}
std::cout << "取消清空操作" << std::endl;
system("pause");
system("cls");
}
SpeechManager::~SpeechManager()
{
}
3. Main函數主體
main.cpp
#include <iostream>
#include <algorithm>
#include "speechManager.h"
int main()
{
SpeechManager spm;
int choise = 0;
srand((unsigned int)time(NULL));
while (true)
{
spm.show_Menu();
std::cout << "請輸入選項: " << std::endl;
std::cin >> choise;
switch (choise)
{
case 1: //開始比賽
spm.startSpeech();
break;
case 2: //查看往屆比賽記錄
spm.showRecord();
break;
case 3: //清空文件
spm.clearRecord();
break;
case 0:
spm.exitSystem();
break;
default:
system("cls");
break;
}
}
return 0;
}