C++演讲比赛管理系统 发表于 2025-07-31
| 字数总计: 2.4k | 阅读时长: 11分钟 | 阅读量:
需求 比赛规则:
学校举行一场演讲比赛,共有12个人参加,比赛共两轮,第一轮为淘汰赛,第二轮为决赛
每名选手都有对应的编号,如10001~10012
比赛方式:分组比赛,每组6个人
第一轮分为两个小组,整体按照选手编号进行抽签后顺序演讲
十个评委分别给每名选手打分,去除最高分和最低分,求的平均分为本轮选手的成绩
当小组演讲完后,淘汰组内排名最后的三个选手,前三名晋级,进入下一轮的比赛
第二轮为决赛,前三名胜出
每轮比赛过后需要显示晋级选手的信息
程序功能:
开始演讲比赛:完成整届比赛的流程,每个比塞阶段需要给用户一个提示,用户按任意键后继续下一个阶段
查看往届记录:查看之前比赛前三名结果,每次比赛都会记录到文件中,文件用.csv后缀名保存
清空比塞记录:将文件中数据清空
退出比赛程序:可以退出当前程序
框架 先创建speechManager类,将功能集成到类中
创建空构造和析构函数避免可能出现的报错
1 2 3 4 5 6 7 8 9 10 11 #ifndef SPEECHMANAGER_H #define SPEECHMANAGER_H #pragma once #include <iostream> using namespace std;class speechManager {public : speechManager (); ~speechManager (); }; #endif
speechManager类中添加属性
1 2 3 4 5 6 7 vector<int >one; vector<int >two; vector<int >victory; map<int ,Speaker> speaker; int Index; bool fileisempty; map<int ,vector<string>> record;
初始化代码写为一个函数,方便后续clear操作
1 2 3 4 5 6 7 8 void speechManager::init () { this ->one.clear (); this ->two.clear (); this ->victory.clear (); this ->speaker.clear (); this ->record.clear (); this ->Index = 1 ; }
菜单功能 1 2 3 4 5 6 7 8 void speechManager::showMenu () { cout<<"Welcome to Speech Manager" <<endl; cout<<"1. Start the speech contest" <<endl; cout<<"2. View the past record" <<endl; cout<<"3. Clear the record" <<endl; cout<<"0. Exit the system" <<endl; cout<<"Press any key to continue: " ; }
退出功能 1 2 3 4 5 void speechManager::exitSystem () { cout << "Welcome to the next use!" <<endl; system ("pause" ); exit (0 ); }
创建选手 先创建选手类,选手属性只有名字和得分,得分可能有两轮写为数组形式
1 2 3 4 5 6 7 class Speaker {public : Speaker () = default ; ~Speaker () = default ; string name; double score[2 ]{}; };
speechManager类中添加创建函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void speechManager::createSpeaker () { string name_tag = "ABCDEFGHIJKL" ; for (int i = 0 ;i<name_tag.size ();i++) { string name = "Speaker" ; name += name_tag[i]; Speaker sp; sp.name = name; this ->one.push_back (10001 +i); this ->speaker.insert (make_pair (10001 +i, sp)); } }
比赛 比赛流程为:第一轮抽签→评比分数→展示晋级→第二轮抽签→评比分数→展示成绩
然后将每部分实现即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void speechManager::startspeech () { this ->draw_lots (); this ->speechcontest (); this ->showscore (); this ->Index++; this ->draw_lots (); this ->speechcontest (); this ->showscore (); this ->saverecord (); cout << "The speech contest is over!" << endl; this ->reset (); system ("pause" ); system ("cls" ); }
抽签 把两轮的写到一个函数中,由Index来分类
抽签其实就是用shuffle函数打乱容器内元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void speechManager::draw_lots () { cout << "--------------------------" << endl; cout << "Drawing of lots for round " << this ->Index << endl; cout << "The order as follow: " <<endl; if (this ->Index == 1 ) { shuffle (this ->one.begin (), this ->one.end (), mt19937 (random_device ()())); for (int i = 0 ;i<this ->one.size ();i++) { cout << this ->one[i] << "\t" ; if (i == this ->one.size ()/2 -1 ) { cout << endl; } } cout << endl; } if (this ->Index == 2 ) { shuffle (this ->two.begin (), this ->two.end (), mt19937 (random_device ()())); for (const int & it : this ->two) cout << it << " " ; cout << endl; } cout << "--------------------------" << endl; system ("pause" ); }
评比分数 由于第一轮第二轮每组比赛的人数都是6,可以写到一起
创建两个临时容器,一个用来存储成绩和编号键值对(成绩作为key方便排序),另一个用来存储比赛人员的编号
根据Index的值来读取系统中存储的比赛人员编号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 void speechManager::speechcontest () { cout << "--------------------------" << endl; cout <<"Round " << this ->Index << " speech contest started!" <<endl; multimap<double ,int ,greater<>> groupscore; int num = 0 ; vector<int > v_Src; if (this ->Index == 1 ) v_Src = this ->one; if (this ->Index == 2 ) v_Src = this ->two; for (auto it = v_Src.begin (); it != v_Src.end (); it++) { num++; deque<double > d; for (int i =0 ; i<10 ; i++) { random_device rd; mt19937 gen (rd()) ; uniform_real_distribution<double > dist (60.0 , 100.0 ) ; double score = dist (gen); d.push_back (score); } sort (d.begin (), d.end ()); d.pop_front (); d.pop_back (); double avg = accumulate (d.begin (), d.end (), 0.0 ) / static_cast <double >(d.size ()); this ->speaker[*it].score[this ->Index-1 ] = avg; groupscore.insert (make_pair (avg, *it)); if (num%6 == 0 ) { cout << "Rank of group " << num/6 << ":" <<endl; for (auto & it : groupscore) { cout << it.second << "\t" ; cout << this ->speaker[it.second].name<< "\t" ; cout << this ->speaker[it.second].score[this ->Index-1 ] << endl; } int count = 0 ; for (auto it = groupscore.begin (); it != groupscore.end () && count < 3 ; it++, count++) { if (this ->Index==1 ) { this ->two.push_back (it->second); } if (this ->Index==2 ) { this ->victory.push_back (it->second); } } groupscore.clear (); cout << endl; } } cout <<"Round " << this ->Index << " speech contest complete!" <<endl; cout << "--------------------------" << endl; system ("pause" ); }
展示分数 第一轮晋级的取two容器中的内容,第二轮决赛的取victory容器中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void speechManager::showscore () { cout << "-------------------------" << endl; cout << "The " << this ->Index <<" round advanced contestants as follow: " <<endl; vector<int > v_Src; if (this ->Index == 1 ) { v_Src = this ->two; } if (this ->Index == 2 ) { v_Src = this ->victory; } for (int & it : v_Src) { cout << it << " " ; cout << this ->speaker[it].name<< "\t" ; cout << this ->speaker[it].score[this ->Index-1 ] << endl; } cout << "--------------------------" << endl; system ("pause" ); }
保存记录 添加头文件fstream,将结果写到csv文件中
1 2 3 4 5 6 7 8 9 10 11 #include <fstream> void speechManager::saverecord () { ofstream ofs; ofs.open ("speech.csv" , ios::out|ios::app); for (auto it : this ->victory) { ofs << it << "," << this ->speaker[it].score[1 ] << "," ; } ofs << endl; ofs.close (); cout << "---- record save! ----" << endl; }
查看记录 查看肯定要读取文件,这个时候又增加了标识符和新容器
1 2 bool fileisempty; map<int ,vector<string>> record;
读取文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void speechManager::loadrecord () { ifstream ifs; ifs.open ("speech.csv" , ios::in); if (!ifs.is_open ()) { this ->fileisempty = true ; cout << "File does not exist!" << endl; return ; } char ch; ifs >> ch; if (ifs.eof ()) { this ->fileisempty = true ; cout << "File is empty!" << endl; ifs.close (); return ; } fileisempty = false ; ifs.putback (ch); string data; int index = 1 ; while (ifs>>data) { vector<string> record; int pos = -1 ; int start = 0 ; while (true ) { pos = data.find ("," ,start); if (pos == -1 ) { break ; } string temp = data.substr (start, pos-start); start = pos+1 ; record.push_back (temp); } this ->record.insert (make_pair (index,record)); index++; } ifs.close (); }
先判断文件是否为空,不为空则读取其中内容,并按键值读出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void speechManager::showrecord () { if (this ->fileisempty) { cout << "File is empty or does exist!" << endl; system ("pause" ); system ("cls" ); } else { for (auto & it : this ->record) { cout << "Result of No." << it.first << " speech contest:" <<endl; for (int i = 0 ; i < it.second.size (); i++) { cout << it.second[i] << " " ; if (i%2 ==1 ) cout << endl; } } system ("pause" ); system ("cls" ); } }
清空记录 为了方便清空以及之前的一些刷新,新增reset函数
方便一些需要刷新内存的情况,比如完成一场比赛后如果不刷新会查询不到新的记录
1 2 3 4 5 6 7 8 void speechManager::reset () { this ->init (); this ->createSpeaker (); this ->loadrecord (); } speechManager::speechManager () { this ->reset (); }
清空操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void speechManager::clearrecord () { cout << "Sure about deletion?" << endl; cout << "1.yes\t2.no" << endl; int select; cin >> select; if (select == 1 ) { ofstream ofs ("speech.csv" ,ios::trunc) ; ofs.close (); this ->reset (); cout << "Success delete!" << endl; } else { cout << "User cancle" << endl; } system ("pause" ); system ("cls" ); }