演讲比赛流程管理系统

1 演讲比赛程序要求

1.1 比赛规则

  • 学校举行一场演讲比赛,共有12个人参加,比赛共两轮,第一轮为淘汰赛,第二轮为决赛。
  • 每名选手都有对应的编号,如10001 ~ 10012
  • 比赛方式:分组比赛,每组6个人
  • 第一轮分为两个小组,整体按照选手编号进行抽签,根据抽签顺序演讲
  • 十个评委分别给每名选手打分,去除最高分和最低分,求的平均分为本轮选手的成绩
  • 当小组演讲完后,淘汰组内排名最后的三个选手,前三名晋级,进入下一轮的比赛
  • 第二轮为决赛,前三名胜出
  • 每轮比赛过后需要显示晋级选手的信息

1.2 程序功能

  • 开始演讲比赛:完成整届比赛的流程,每个比赛阶段需要给用户一个提示,用户按任意键后继续下一个阶段
  • 查看往届记录:查看之前比赛前三名结果,每次比赛都会记录到文件中,文件用.csv后缀名保存
  • 清空比赛记录:将文件中数据清空
  • 退出比赛程序:可以退出当前程序

1.3 程序效果图

image-20220313155347334

2 项目创建

创建项目步骤如下

  • 创建新项目
  • 添加文件

2.1 创建项目

创建项目步骤如下:

  • 创建新项目
  • 添加文件

2.1 创建项目

打开Visual studio后,点击创建新项目,创建新的C++项目

image-20220123124340461 image-20220123125134404 image-20220123125917692

2.2 创建文件

右键源文件,选择添加->新建项

image-20220123130442955

给C++文件起个名称,然后点击添加即可。

image-20220123130813668

3 创建管理类

功能描述

  • 提供菜单界面与用户交互
  • 对演讲比赛流程进行控制
  • 与文件的读写交互

3.1 创建文件

  • 在头文件和源文件的文件夹下分别创建speechManager.hspeechManager.cpp文件

image-20220312141057724

3.2 头文件实现

speechManager.h中设计管理类

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#pragma once
#include<iostream>
using namespace std;

//设计演讲比赛的管理类
class SpeechManager {
public:
//构造函数
SpeechManager();

//析构函数
~SpeechManager();
};

3.3 源文件实现

speechManager.cpp中将构造函数和析构函数实现

代码如下:

1
2
3
4
5
6
7
8
9
#include"speechManager.h"

//构造函数
SpeechManager::SpeechManager() {
}

//析构函数
SpeechManager::~SpeechManager() {
}

4 菜单功能

功能描述:与用户的沟通界面

4.1 添加成员函数

在管理类speechManager.h中添加成员函数void show_Menu();

1
2
//显示菜单
void show_Menu();

4.2 菜单功能实现

  • 在管理类speechManager.cpp中实现show_Menu()函数
1
2
3
4
5
6
7
8
9
10
11
//显示菜单
void SpeechManager::show_Menu() {
cout << "************************************" << endl;
cout << "******** 欢迎参加演讲比赛 ********" << endl;
cout << "******** 1.开始演讲比赛 ********" << endl;
cout << "******** 2.查看往届记录 ********" << endl;
cout << "******** 3.清空比赛记录 ********" << endl;
cout << "******** 0.退出比赛记录 ********" << endl;
cout << "************************************" << endl;
cout << endl;
}

4.3 测试菜单功能

  • 演讲比赛流程管理系统.cpp中测试菜单功能

代码:

1
2
SpeechManager sm;
sm.show_Menu();

运行效果图:

image-20220312144514775

5 退出功能

功能描述:实现退出程序

5.1 提供功能接口

  • 在main函数中提供分支选择,提供每个功能接口

代码:

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
#include<iostream>
using namespace std;
#include"speechManager.h"

int main() {
SpeechManager sm;
int choice = 0; //用来存储用户的选项

while (true) {
sm.show_Menu();
cout << "请输入您的选择:" << endl;
cin >> choice;

switch (choice)
{
case 1: //开始比赛
break;
case 2: //查看记录
break;
case 3: //清空记录
break;
case 0: //退出系统
break;
default:
system("cls"); //清屏
break;
}
}

system("pause");
return 0;
}

5.2 实现退出功能

speechManager.h中提供退出系统的成员函数void exitSystem();

speechManager.h中提供具体的功能实现

1
2
3
4
5
6
//退出系统
void SpeechManager::exitSystem() {
cout << "欢迎下次使用" << endl;
system("pause");
exit(0);
}

5.3 测试功能

在main函数分支 0 选项中,调用退出程序的接口

1
2
3
case 0: //退出系统
sm.exitSystem();
break;

效果如图:

image-20220312150528020

6 演讲比赛功能

6.1 功能分析

比赛流程:

抽签→开始演讲比赛→显示第一轮比赛结果→

抽签→开始演讲比赛→显示前三名结果→保存分数

6.2 创建选手类

选手类中的属性包含:选手姓名、分数

头文件中创建speaker.h文件,并添加代码:

1
2
3
4
5
6
7
8
9
10
#pragma once
#include<iostream>
using namespace std;

//选手类
class Speaker {
public:
string m_Name; //姓名
double m_Score[2]; //分数,最多有两轮得分
};

6.3 比赛

6.3.1 成员属性添加

speechManager.h中添加属性

1
2
3
4
5
6
7
8
9
10
11
//成员属性
//保存第一轮比赛选手的编号
vector<int>v1;
//第一轮晋级选手编号容器
vector<int>v2;
//胜出的前三名选手编号容器
vector<int>vVictory;
//存放编号以及对应具体选手的容器
map<int, Speaker>m_Speaker;
//存放比赛的轮数
int m_Index;

6.3.2 初始化属性

speechManager.h中提供开始比赛的成员函数void initSpeech();

1
2
//初始化容器和属性
void initSpeech();

在speechManager.cpp中实现void initSpeech();

1
2
3
4
5
6
7
8
9
10
11
//初始化容器和属性
void SpeechManager::initSpeech() {
//容器都置空
this->v1.clear();
this->v2.clear();
this->vVictory.clear();
this->m_Speaker.clear();

//初始化比赛轮数
this->m_Index = 1;
}

SpeechManager构造函数中调用void initSpeech();

1
2
3
4
5
//构造函数
SpeechManager::SpeechManager() {
//初始化容器和属性
this->initSpeech();
}

6.3.3 创建选手

speechManager.h中提供开始比赛的成员函数void createSpeaker();

1
2
//创建12名选手
void createSpeaker();

speechManager.cpp中实现void createSpeaker();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void SpeechManager::createSpeaker() {
string nameSeed = "ABCDEFGHIJKL";
for (int i = 0; i < nameSeed.size(); i++) {
string name = "选手";
name += nameSeed[i];

Speaker sp;
sp.m_Name = name;
for (int j = 0; j < 2; j++) {
sp.m_Score[j] = 0;
}

//创建选手编号,并且放入到v1容器中
this->v1.push_back(i + 1001);
//选手编号以及对应的选手 放入到map容器中
this->m_Speaker.insert(make_pair(i + 1001, sp));
}
}

speechManager.cpp中对SpeechManager类中调用void createSpeaker();

1
2
3
4
5
6
7
//构造函数
SpeechManager::SpeechManager() {
//初始化容器和属性
this->initSpeech();
//创建12名选手
this->createSpeaker();
}

测试,在main函数中,可以在创建完管理对象后,使用下列代码测试12名选手初始状态

1
2
3
4
5
//测试代码:
//测试12名选手的创建
for (map<int, Speaker>::iterator it = sm.m_Speaker.begin(); it != sm.m_Speaker.end(); it++) {
cout << "选手编号:" << it->first << " 姓名:" << it->second.m_Name << " 分数:" << it->second.m_Score[0] << endl;
}

测试效果图:

image-20220312183901650

测试完毕后,可以将测试代码删除或注释。

6.3.4 开始比赛成员函数添加

speechManager.h中提供开始比赛的成员函数void startSpeech();

该函数功能时主要控制比赛的流程

1
2
//开始比赛 - 比赛流程
void startSpeech();

在speechManager.cpp中将startSpeech的空实现先写入

1
2
3
4
5
6
7
8
9
10
11
12
13
//开始比赛
void SpeechManager::startSpeech() {
//第一轮比赛
//1.抽签
speechDraw();
//2.比赛
//3.显示晋级结果
//第二轮比赛
//1.抽签
//2.比赛
//3.显示最终结果
//4.保存分数
}

6.3.5 抽签

功能描述

正式比赛前,所有选手的比赛顺序需要打乱,只需要将存放选手编号的容器打乱次序即可

speechManager.h中提供抽签的成员函数void speechManager();

1
2
//抽签
void speechDraw();

在speechManager.cpp中实现成员函数void speechDraw();

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
//抽签
void SpeechManager::speechDraw() {
cout << "第 " << this->m_Index << " 轮比赛选手正在抽签" << endl;
cout << "--------------------------------------" << endl;
cout << "抽签后演讲顺序如下:" << endl;

if (this->m_Index == 1) {
//第一轮比赛
random_shuffle(v1.begin(), v1.end());
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
else {
//第二轮比赛
random_shuffle(v2.begin(), v2.end());
for (vector<int>::iterator it = v2.begin(); it != v2.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
cout << "--------------------------------------" << endl;
system("pause");
cout << endl;
}

在startSpeech比赛流程控制的函数中,调用抽签函数

image-20220312190246239

在main函数中,分支 1 选项中,调用开始比赛的接口

image-20220312190413410

测试效果图:

image-20220312191833223

6.3.6 开始比赛

在speechManager.h中提供比赛的成员函数void speechContest();

1
2
//比赛
void speechContest();

在speechManager.cpp中实现成员函数void speechContest();

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
60
61
62
63
64
void SpeechManager::speechContest() {
cout << "第 " << this->m_Index << " 轮比赛开始:" << endl;
//准备临时的容器存放小组的容器
multimap<double, int, greater<double>>groupScore;
int num = 0;//记录人员的个数

vector<int>v_Src;//比赛选手的容器
if (this->m_Index == 1) {
v_Src = v1;
}
else {
v_Src = v2;
}

//遍历所有选手进行比赛
for (vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++) {
num++;
//评委打分
deque<double>d;
for (int i = 0; i < 10; i++) {
double score = (rand() % 401 + 600) / 10.f; //600~1000
//cout << score << " ";
d.push_back(score);
}
//cout << endl;
sort(d.begin(), d.end(), greater<double>());//从大到小排序
d.pop_front();//去除最高分
d.pop_back();//去除最低分
double sum = accumulate(d.begin(), d.end(), 0.0f);//总分
double avg = sum / (double)d.size();//平均分

//打印平均分
//cout << "编号:" << *it << " 姓名:" << this->m_Speaker[*it].m_Name << " 获取平均分:" << avg << endl;

//将平均分放入到map容器中
this->m_Speaker[*it].m_Score[this->m_Index - 1] = avg;

//将打分数放入到临时小组容器中
groupScore.insert(make_pair(avg, *it));//key是得分,value是具体选手的编号
//每6人取出前三名
if (num % 6 == 0) {
cout << "第" << num / 6 << "小组比赛名次:" << endl;
for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end(); it++) {
cout << "编号:" << it->second
<< " 姓名:" << this->m_Speaker[it->second].m_Name
<< " 成绩:" << this->m_Speaker[it->second].m_Score[this->m_Index - 1] << endl;
}
//取走前三名
int count = 0;
for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end() && count < 3; it++) {
if (this->m_Index == 1) {
v2.push_back((*it).second);
}
else {
vVictory.push_back((*it).second);
}
}
groupScore.clear();//小组容器清空
cout << endl;
}
}
cout << "第" << this->m_Index << "轮比赛完毕!" << endl;
system("pause");
}

6.3.7 显示比赛分数

speechMananger.h中提供显示分数的成员函数void showScore();

1
2
//显示比赛结果
void showScore();

speechManager.cpp中实现成员函数void showScore();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//显示比赛结果
void SpeechManager::showScore() {
cout << "第" << this->m_Index << "轮晋级选手信息如下:" << endl;
vector<int>v;
if (this->m_Index == 1) {
v = v2;
}
else {
v = vVictory;
}
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << "选手编号:" << *it << " 姓名:" << this->m_Speaker[*it].m_Name
<< " 得分:" << this->m_Speaker[*it].m_Score[this->m_Index - 1] << endl;
}
cout << endl;
system("pause");
system("cls");
this->show_Menu();
}

在startSpeech比赛流程控制的函数中,调用显示比赛分数函数

image-20220313113009813

运行结果:

image-20220313113113137

6.3.8 第二轮比赛

第二轮比赛流程同第一轮,只是比赛的轮是+1,其余流程不变

startSpeech比赛流程控制的函数中,加入第二轮的流程

image-20220313113702890

测试,将整个比赛流程跑一遍

image-20220313113857138

6.4 保存分数

功能描述:将每次演讲比赛的得分记录到文件中

功能实现:在speechManager.h中添加保存记录的成员函数void saveRecord();

1
2
//保存记录
void saveRecord();

在speechManager.cpp中实现成员函数void saveRecord();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//保存记录
void SpeechManager::saveRecord() {
ofstream ofs;
ofs.open("speech.csv", ios==out | ios==app);//用追加的方式写文件

//将每个选手的数据写入到文件中
for (vector<int>::iterator it = vVictory.begin(); it != vVictory.end(); it++) {
ofs << *it << "," << this->m_Speaker[*it].m_Score[1] << ",";
}
ofs << endl;

//关闭
ofs.close();
cout << "记录已经保存" << endl;
}

在startSpeech比赛流程控制的函数中,最后调用保存记录分数函数

image-20220313124457335

测试效果:

image-20220313124542790

利用记事本打开speech.csv,里面保存了前三名选手的编号以及得分

image-20220313124857565

至此,整个演讲比赛功能制作完毕。

7 查看记录

7.1 读取记录分数

speechManager.h中添加保存记录的成员函数void loadRecord();

添加判断文件是否为空的标志bool fileIsEmpty;

添加往届记录的容器map<int, vector<string>> m_Record;

1
2
3
4
5
6
//读取记录
void loadRecord();
//文件为空的标志
bool fileIsEmpty;
//存放往届记录的容器
map<int, vector<string>> m_Record;

在speechManager.cpp中实现成员函数void loadRecord();

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
//读取记录
void SpeechManager::loadRecord() {
ifstream ifs("speech.csv", ios::in);//读文件
if (!ifs.is_open()) {
this->fileIsEmpty = true;
cout << "文件不存在" << endl;
ifs.close();
return;
}
//文件清空的情况
char ch;
ifs >> ch;
if (ifs.eof()) {
cout << "文件为空" << endl;
this->fileIsEmpty = true;
ifs.close();
return;
}

//文件不为空
this->fileIsEmpty = false;

ifs.putback(ch);//将上面读取的单个字符放回

string data;
while (ifs >> data) {
cout << data << endl;
}
ifs.close();
}

speechManager构造函数中调用获取往届记录。

image-20220313132101702

7.2 查看记录功能

在speechManager.h中添加保存记录的成员函数void showRecord();

1
2
//显示往届记录
void showRecord();

在speechManager.cpp中实现成员函数void showRecord();

1
2
3
4
5
6
7
8
9
10
11
//显示往届记录
void SpeechManager::showRecord() {
for (int i = 0; this->m_Record.size(); i++) {
cout << "第" << i + 1 << "届" <<
"冠军编号:" << this->m_Record[i][0] << " 得分:" << this->m_Record[i][1] << " "
"季军编号:" << this->m_Record[i][2] << " 得分:" << this->m_Record[i][3] << " "
"亚军编号:" << this->m_Record[i][4] << " 得分:" << this->m_Record[i][5] << endl;
}
system("pause");
system("cls");
}

7.3 测试功能

在main函数分支 2 选项中,调用查看记录的接口

image-20220313140332781

7.4 bug解决

目前程序中有几处bug未解决:

  1. 查看往届记录,若问价不存在或为空,并未提示

解决方式:在showRecord函数中,开始判断文件状态

image-20220313141139884

  1. 若记录为空或不存在,比完赛后依然提示记录为空

解决方式:saveRecord中更新文件为空的标志

image-20220313141453502

  1. 比完赛后查不到本届比赛的记录,没有实时更新

解决方式:比赛完毕后,所有数据重置

image-20220313142009085

  1. 在初始化时,没有初始化记录容器

解决方式:initSpeech中添加初始化记录容器

image-20220313145234536

  1. 每次记录都是一样的

解决方式:在main函数一开始添加随机数种子

1
srand((unsigned int)time(NULL));

所有bug解决后测试:

image-20220313150652485

8 清空记录

8.1 清空记录功能实现

speechManager.h中添加保存记录的成员函数void clearRecord();

1
2
//清空记录
void clearRecord();

speechManager.cpp中实现成员函数void clearRecord();

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::clearRecord() {
cout << "确认清空?" << endl;
cout << "1.确认" << endl;
cout << "2.返回" << endl;

int select = 0;
cin >> select;

if (select == 1) {
//打开模式 ios::trunc 如果存在删除文件并重新创建
ofstream ofs("speech.csv", ios::trunc);
ofs.close();

//初始化属性
this->initSpeech();
//创建选手
this->createSpeaker();
//获取往届记录
this->loadRecord();

cout << "清空成功!" << endl;
}
system("pause");
system("cls");
}

8.2 测试清空

在main函数分支 3 选项中,调用清空比赛记录的接口

image-20220313151825067

运行程序,测试清空记录:

image-20220313151918085

speech.csv中记录为空:

image-20220313152002983

至此,演讲比赛流程管理系统结束。

9 所有程序

基于STL的演讲比赛流程管理系统.cpp

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
#include<iostream>
using namespace std;
#include<string>
#include<ctime>
#include"speechManager.h"

int main() {
srand((unsigned int)time(NULL));
SpeechManager sm;

//测试代码:
////测试12名选手的创建
//for (map<int, Speaker>::iterator it = sm.m_Speaker.begin(); it != sm.m_Speaker.end(); it++) {
// cout << "选手编号:" << it->first << " 姓名:" << it->second.m_Name << " 分数:" << it->second.m_Score[0] << endl;
//}

int choice = 0; //用来存储用户的选项

while (true) {
sm.show_Menu();
cout << "请输入您的选择:" << endl;
cin >> choice;

switch (choice)
{
case 1: //开始比赛
sm.startSpeech();
break;
case 2: //查看记录
sm.showRecord();
break;
case 3: //清空记录
sm.clearRecord();
break;
case 0: //退出系统
sm.exitSystem();
break;
default:
system("cls"); //清屏
break;
}
}

system("pause");
return 0;
}

speaker.h

1
2
3
4
5
6
7
8
9
10
#pragma once
#include<iostream>
using namespace std;

//选手类
class Speaker {
public:
string m_Name;//姓名
double m_Score[2]; //分数,最多有两轮得分
};

speechManager.h

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
60
61
62
63
64
65
66
67
68
69
70
71
72
#pragma once
#include<iostream>
using namespace std;
#include<vector>
#include<map>
#include<deque>
#include<algorithm>
#include<functional>
#include<numeric>
#include<string>
#include<fstream>
#include"speaker.h"

//设计演讲比赛的管理类
class SpeechManager {
public:
//构造函数
SpeechManager();
//显示菜单
void show_Menu();
//退出系统
void exitSystem();

//初始化容器和属性
void initSpeech();

//成员属性
//保存第一轮比赛选手的编号
vector<int>v1;
//第一轮晋级选手编号容器
vector<int>v2;
//胜出的前三名选手编号容器
vector<int>vVictory;
//存放编号以及对应具体选手的容器
map<int, Speaker>m_Speaker;
//存放比赛的轮数
int m_Index;

//创建12名选手
void createSpeaker();

//开始比赛 - 比赛流程
void startSpeech();

//抽签
void speechDraw();

//显示比赛结果
void showScore();

//比赛
void speechContest();

//保存记录
void saveRecord();

//读取记录
void loadRecord();
//文件为空的标志
bool fileIsEmpty;
//存放往届记录的容器
map<int, vector<string>> m_Record;

//显示往届记录
void showRecord();

//清空记录
void clearRecord();

//析构函数
~SpeechManager();
};

speechManager.cpp

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#include"speechManager.h"

//构造函数
SpeechManager::SpeechManager() {
//初始化容器和属性
this->initSpeech();
//创建12名选手
this->createSpeaker();
//获取往届记录
this->loadRecord();
}

//显示菜单
void SpeechManager::show_Menu() {
cout << "************************************" << endl;
cout << "******** 欢迎参加演讲比赛 ********" << endl;
cout << "******** 1.开始演讲比赛 ********" << endl;
cout << "******** 2.查看往届记录 ********" << endl;
cout << "******** 3.清空比赛记录 ********" << endl;
cout << "******** 0.退出比赛记录 ********" << endl;
cout << "************************************" << endl;
cout << endl;
}

//退出系统
void SpeechManager::exitSystem() {
cout << "欢迎下次使用" << endl;
system("pause");
exit(0);
}

//初始化容器和属性
void SpeechManager::initSpeech() {
//容器都置空
this->v1.clear();
this->v2.clear();
this->vVictory.clear();
this->m_Speaker.clear();

//初始化比赛轮数
this->m_Index = 1;
//初始化记录容器
this->m_Record.clear();
}

void SpeechManager::createSpeaker() {
string nameSeed = "ABCDEFGHIJKL";
for (int i = 0; i < nameSeed.size(); i++) {
string name = "选手";
name += nameSeed[i];

Speaker sp;
sp.m_Name = name;
for (int j = 0; j < 2; j++) {
sp.m_Score[j] = 0;
}

//创建选手编号,并且放入到v1容器中
this->v1.push_back(i + 1001);
//选手编号以及对应的选手 放入到map容器中
this->m_Speaker.insert(make_pair(i + 1001, sp));
}
}

//开始比赛
void SpeechManager::startSpeech() {
//第一轮比赛
//1.抽签
this->speechDraw();
//2.比赛
this->speechContest();
//3.显示晋级结果
this->showScore();
//第二轮比赛
this->m_Index++;
//1.抽签
this->speechDraw();
//2.比赛
this->speechContest();
//3.显示最终结果
this->showScore();
//4.保存分数
this->saveRecord();

//重置比赛
//初始化属性
this->initSpeech();
//创建选手
this->createSpeaker();
//获取往届记录
this->loadRecord();

cout << "本届比赛完毕!" << endl;
system("pause");
system("cls");
}

//抽签
void SpeechManager::speechDraw() {
cout << "第 " << this->m_Index << " 轮比赛选手正在抽签" << endl;
cout << "--------------------------------------" << endl;
cout << "抽签后演讲顺序如下:" << endl;

if (this->m_Index == 1) {
//第一轮比赛
random_shuffle(v1.begin(), v1.end());
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
else {
//第二轮比赛
random_shuffle(v2.begin(), v2.end());
for (vector<int>::iterator it = v2.begin(); it != v2.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
cout << "--------------------------------------" << endl;
system("pause");
cout << endl;
}

void SpeechManager::speechContest() {
cout << "第 " << this->m_Index << " 轮比赛开始:" << endl;
//准备临时的容器存放小组的容器
multimap<double, int, greater<double>>groupScore;
int num = 0;//记录人员的个数

vector<int>v_Src;//比赛选手的容器
if (this->m_Index == 1) {
v_Src = v1;
}
else {
v_Src = v2;
}

//遍历所有选手进行比赛
for (vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++) {
num++;
//评委打分
deque<double>d;
for (int i = 0; i < 10; i++) {
double score = (rand() % 401 + 600) / 10.f; //600~1000
//cout << score << " ";
d.push_back(score);
}
//cout << endl;
sort(d.begin(), d.end(), greater<double>());//从大到小排序
d.pop_front();//去除最高分
d.pop_back();//去除最低分
double sum = accumulate(d.begin(), d.end(), 0.0f);//总分
double avg = sum / (double)d.size();//平均分

//打印平均分
//cout << "编号:" << *it << " 姓名:" << this->m_Speaker[*it].m_Name << " 获取平均分:" << avg << endl;

//将平均分放入到map容器中
this->m_Speaker[*it].m_Score[this->m_Index - 1] = avg;

//将打分数放入到临时小组容器中
groupScore.insert(make_pair(avg, *it));//key是得分,value是具体选手的编号
//每6人取出前三名
if (num % 6 == 0) {
cout << "第" << num / 6 << "小组比赛名次:" << endl;
for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end(); it++) {
cout << "编号:" << it->second
<< " 姓名:" << this->m_Speaker[it->second].m_Name
<< " 成绩:" << this->m_Speaker[it->second].m_Score[this->m_Index - 1] << endl;
}
//取走前三名
int count = 0;
for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end() && count < 3; it++, count++) {
if (this->m_Index == 1) {
v2.push_back((*it).second);
}
else {
vVictory.push_back((*it).second);
}
}
groupScore.clear();//小组容器清空
cout << endl;
}
}
cout << "第" << this->m_Index << "轮比赛完毕!" << endl;
system("pause");
}

//显示比赛结果
void SpeechManager::showScore() {
cout << "第" << this->m_Index << "轮晋级选手信息如下:" << endl;
vector<int>v;
if (this->m_Index == 1) {
v = v2;
}
else {
v = vVictory;
}
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << "选手编号:" << *it << " 姓名:" << this->m_Speaker[*it].m_Name
<< " 得分:" << this->m_Speaker[*it].m_Score[this->m_Index - 1] << endl;
}
cout << endl;
system("pause");
system("cls");
this->show_Menu();
}

//保存记录
void SpeechManager::saveRecord() {
ofstream ofs;
ofs.open("speech.csv", ios==out | ios==app);//用追加的方式写文件

//将每个选手的数据写入到文件中
for (vector<int>::iterator it = vVictory.begin(); it != vVictory.end(); it++) {
ofs << *it << "," << this->m_Speaker[*it].m_Score[1] << ",";
}
ofs << endl;

//关闭
ofs.close();
cout << "记录已经保存" << endl;

//有记录了,文件不为空
this->fileIsEmpty = false;
}

//读取记录
void SpeechManager::loadRecord() {
ifstream ifs("speech.csv", ios::in);//读文件
if (!ifs.is_open()) {
this->fileIsEmpty = true;
//cout << "文件不存在" << endl;
ifs.close();
return;
}
//文件清空的情况
char ch;
ifs >> ch;
if (ifs.eof()) {
//cout << "文件为空" << endl;
this->fileIsEmpty = true;
ifs.close();
return;
}

//文件不为空
this->fileIsEmpty = false;

ifs.putback(ch);//将上面读取的单个字符放回

string data;
int index = 0;
while (ifs >> data) {
//cout << data << endl;
//1002,86.675,1009,81.3,1007,78.55,
vector<string>v;//为了存放6个string字符串
int pos = -1;//查到“,”位置的变量
int start = 0;
while (true) {
pos = data.find(",", start);
if (pos == -1) {
//没有找到的情况
break;
}
string temp = data.substr(start, pos - start);
//cout << temp << endl;
v.push_back(temp);
start = pos + 1;
}
this->m_Record.insert(make_pair(index, v));
index++;
}
ifs.close();

//for (map<int, vector<string>>::iterator it = m_Record.begin(); it != m_Record.end(); it++) {
// cout << it->first << "冠军编号:" << it->second[0]
// << " 分数:" << it->second[1] << endl;
//}
}

//显示往届记录
void SpeechManager::showRecord() {
if (this->fileIsEmpty) {
cout << "文件不存在,或记录为空!" << endl;
}
else {
for (int i = 0; i < this->m_Record.size(); i++) {
cout << "第" << i + 1 << "届" <<
"冠军编号:" << this->m_Record[i][0] << " 得分:" << this->m_Record[i][1] << " "
"季军编号:" << this->m_Record[i][2] << " 得分:" << this->m_Record[i][3] << " "
"亚军编号:" << this->m_Record[i][4] << " 得分:" << this->m_Record[i][5] << endl;
}
}
system("pause");
system("cls");
}

void SpeechManager::clearRecord() {
cout << "确认清空?" << endl;
cout << "1.确认" << endl;
cout << "2.返回" << endl;

int select = 0;
cin >> select;

if (select == 1) {
//打开模式 ios::trunc 如果存在删除文件并重新创建
ofstream ofs("speech.csv", ios::trunc);
ofs.close();

//初始化属性
this->initSpeech();
//创建选手
this->createSpeaker();
//获取往届记录
this->loadRecord();

cout << "清空成功!" << endl;
}
system("pause");
system("cls");
}

//析构函数
SpeechManager::~SpeechManager() {
}