学校就行一场演讲比赛,共有12人参加。比赛共两轮,第一轮淘汰赛,第二轮为决赛。
每名选手都有对应的编号,如10001-10012.
比赛方式:分组比赛,每组6个人
第一轮分为两个小组,整体按照选手编号进行抽签后顺序演讲。
十个评委分别给美名选手打分,去除最高分和最低分,求得的平均分为本轮选手得成绩
当小组演讲完后,淘汰组内排名最后得三个选手,前三名晋级,进入下一轮的比赛。
第二轮为决赛,前三名胜出
每轮比赛后需要显示晋级选手的信息。
开始演讲比赛:完成整届比赛的流程,每个比赛阶段需要给用户一个提示,用户按任意键后继续下一个阶段。
查看往届记录:查看之前比赛前三名结果,每次比赛都会记录到文件中,文件用.csv后缀名保存。(.csv可以用excel打开,也可以用文本文件打开。)
清空比赛记录:将文件中数据清空
退出比赛程序:可以退出当前程序
#include"speechManager.h"
#include
int main()
{
srand((unsigned int)time(NULL));
SpeechManager m;
int choice = -1;
// 测试12名选手的创建
/*for (map::iterator it = m.m_Speaker.begin(); it != m.m_Speaker.end(); it++)
{
cout << "编号:" << (*it).first << " "
<< "姓名:" << (*it).second.m_Name << " "
<< "得分:" << (*it).second.m_Score[0] << " "
<<(*it).second.m_Score[1] << endl;
}*/
while (true)
{
m.ShowMenu();
cout << "请输入您的选择:";
cin >> choice;
switch (choice)
{
case 0: // 退出系统
m.ExitSystem();
break;
case 1: // 开始比赛
m.startSpeech();
break;
case 2: // 查看记录
m.showRecord();
break;
case 3: // 退出系统
m.clearRecord();
break;
default: // 清屏
system("cls");
break;
}
}
return 0;
}
#pragma once
#include
using namespace std;
#include"speaker.h"
#include
#include
#include
#include
#include
#include
#include
#include
class SpeechManager
{
public:
SpeechManager(); // 1. 构造函数
~SpeechManager(); // 2. 析构函数
void ShowMenu(); // 3 .菜单功能
void ExitSystem(); // 4. 退出系统
// 5. 添加属性,记录比赛信息
vector<int> v1; // 存放第一轮参赛选手编号
vector<int> v2; // 存放第二轮参赛选手编号
vector<int> vVictory; // 存放前三名参赛选手编号
map<int, Speaker> m_Speaker; // 存放参赛选手编号和具体信息
int m_Index; // 记录比赛轮次
void InitSpeech(); // 成员属性初始化
void CreateSpeeker(); // 6. 添加参赛选手
void startSpeech(); // 7. 开始比赛
void speechDrew(); // 7.1 抽签
void speechContest(); // 7.2 比赛
void showScore(); // 7.3 比赛结果
void saveRecord(); // 8. 保存比赛结果
// 9. 读取记录
void loadRecord(); // 读取文件信息
bool fileIsEmpty; // 文件是否为空标志位
map<int, vector<string>> m_Record; // 存放往届比赛信息
void showRecord(); // 10. 查看记录
void clearRecord(); // 11. 文件清空
};
#include"speechManager.h"
// 1. 构造函数
SpeechManager::SpeechManager()
{
// 5.初始化成员属性
this->InitSpeech();
// 9.读取记录
this->loadRecord();
// 6.添加参赛选手
this->CreateSpeeker();
}
// 2. 析构函数
SpeechManager::~SpeechManager(){}
// 3. 菜单功能
void SpeechManager::ShowMenu()
{
cout << "***************************" << endl;
cout << "**** 欢迎参加演讲比赛! ****" << endl;
cout << "***** 1.开始演讲比赛 ******" << endl;
cout << "***** 2.查看往届记录 ******" << endl;
cout << "***** 3.清空比赛记录 ******" << endl;
cout << "***** 0.退出比赛程序 ******" << endl;
cout << "***************************" << endl;
cout << endl;
}
// 4. 退出系统
void SpeechManager::ExitSystem()
{
cout << endl << "欢迎下次使用!" << endl << endl;
system("pause"); // 按任意键继续
exit(0); // 退出系统
}
// 5. 成员属性初始化
void SpeechManager::InitSpeech()
{
// 容器置空
this->v1.clear();
this->v2.clear();
this->vVictory.clear();
this->m_Speaker.clear();
// 初始化比赛轮数
this->m_Index = 1;
// 存放记录容器的清空
this->m_Record.clear();
}
// 6. 添加参赛选手
void SpeechManager::CreateSpeeker()
{
string nameSeed = "ABCDEFGHIJKL";
for (int i = 0; i < 12; i++) // nameseed.Size()
{
// 选手基本信息 --- 姓名和得分
string name = "选手";
name += nameSeed[i];
Speaker sp;
sp.m_Name = name;
sp.m_Score[0] = sp.m_Score[1] = 0;
// 给选手编号,并存放到容器v1中
int num = (this->m_Record.size() + 1) * 10000;
this->v1.push_back(i + num + 1);
// 将选手的编号和基本信息保存
this->m_Speaker.insert(make_pair(i+ num + 1,sp));
}
}
// 7. 开始比赛
void SpeechManager::startSpeech()
{
cout << endl << "欢迎参加第 " << this->m_Record.size() + 1 << " 届演讲比赛!"
<< endl;
// 第一轮比赛
// 1.抽签
speechDrew();
// 2.比赛
speechContest();
// 3.显示比赛结果
showScore();
// 第二轮比赛
this->m_Index++;
// 1.抽签
speechDrew();
// 2.比赛
speechContest();
// 3.显示最终结果
showScore();
// 4.保存比赛结果
saveRecord();
// 5.重置和更新,为下一届比赛做准备
this->InitSpeech();
this->loadRecord();
this->CreateSpeeker();
cout << endl;
cout << "---------- 本届比赛结束! ----------" << endl << endl;
system("pause");
system("cls");
}
// 7.1 抽签
void SpeechManager::speechDrew()
{
cout << endl;
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 << endl;
system("pause"); // 按任意键之后进入下一个环节
}
// 7.2 比赛
void SpeechManager::speechContest()
{
cout << endl;
cout << "--------- 第" << this->m_Index << "轮比赛正式开始! ---------" << endl;
cout << endl;
// 临时容器,存放小组成绩
multimap<double, int, greater<double>> groupScore;
int num = 0; // 记录人员个数,分组时需要
// 以得分为key值,编号为value值,按照降序插入
// 1.确定当前参赛选手容器
vector<int> v_Src;
if (this->m_Index == 1)
v_Src = v1;
else
v_Src = v2;
// 比赛有两轮,根据m_Index确定除当前参赛人员信息
// 也可以通过传值的方式实现
// 2.遍历所有选手开始比赛,也就是打分
for (vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
{
num++; // 人数统计,用于后续的分组
// 1.10个评委打分
deque<double> d; // 存放每位评委的打分
for (int i = 0; i < 10; i++)
{
double score = (rand() % 401 + 600) / 10.f; // 产生小数随机数
// cout <<"\t"<< score << " "; // 打印成绩,用于测试
d.push_back(score);
}
//cout << endl;
// 2.求平均分
sort(d.begin(), d.end()); // 2.1 得分排序
d.pop_back(); // 2.2 去除最高分和最低分
d.pop_front();
double sum = accumulate(d.begin(), d.end(),0.0f); // 2.3 总分
double avg = sum / (double)d.size(); // 2.4 平均分
// 浮点数和整数相除,结果还是整型,所以需要强制类型转换
// 打印平均分 --- 测试
/*cout << "编号:" << *it << " "
<< "姓名:" << this->m_Speaker[*it].m_Name << " "
<< "得分:" << avg << endl;*/
// 3.将平均分放到map容器m_Speaker中
this->m_Speaker[*it].m_Score[this->m_Index-1] = avg;
// map容器用[key]访问到的是key值对应的value值
// 4.分组取前3名
// 4.1 先去回到开头创建一个存放小组成绩的临时容器
// 4.2 将打分数据存入到临时容器中
groupScore.insert(make_pair(avg, *it));
// 4.3 每6个人取前三名
if (num % 6 == 0) // num为6和12的时候会进入if语句,分别打印输出两组成绩
{
cout << "第"<<num/6<<"小组比赛结果:" << endl;
cout << "-----------------" << 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 << " "
<< "得分:" << it->first << endl;
}
// 取走前三名
int cnt = 0;
for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end() && cnt < 3; it++, cnt++)
{
//两轮比赛,每轮前三名存放的位置不同
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 << endl;;
system("pause");
}
// 7.3 比赛结果
void SpeechManager::showScore()
{
cout << endl;
cout << "--------- 第" << this->m_Index << "轮比赛晋级名单: ---------" << endl;
cout << 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->ShowMenu();
}
// 8. 保存结果
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;
cout << "---------- 记录已经保存! ----------" << endl << endl;
this->fileIsEmpty = false; // 更新文件部位空
}
// 9. 读取记录
void SpeechManager::loadRecord()
{
ifstream ifs("Speech.csv", ios::in);
if (!ifs.is_open()) // 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) // 逐行读取文件
{
// 解析
// 读取到一行用逗号分割的字符串,下一步就是分割
// 结合从邮箱中截取出用户名的案例
// 这里利用子串操作来截取信息,逗号做的分割,所以第一步是找到逗号的位置
vector<string> v; // 记录解析结果,即记录每届比赛结果的6个string字符串
int pos = -1; // 记录逗号位置
int start = 0; // 查找起始位置
while (true)
{
pos = data.find(",", start); // 从start开始查找,返回第一个逗号的位置
if (pos == -1) // find在找不到的情况下的返回值是-1
break; // 没有找到或者说找完了,就退出程序
// 获得第一个子串,存放到临时变量temp中
string tmp = data.substr(start, pos - start);
//cout << tmp << endl; // 测试
v.push_back(tmp); // 临时存放每一届的解析结果
start = pos + 1; // 更新查找起始位置
}
this->m_Record.insert(make_pair(index, v)); // 将解析结果存放到成员属性中
index++; // 每一行代表一届,一行信息解析结束之后,执行++操作
}
ifs.close();
}
// 10.查看记录
void SpeechManager::showRecord()
{
cout << endl;
if (this->fileIsEmpty)
{
cout << "文件为空或者文件不存在!" << endl << endl;
}
else
{
cout << "往届比赛获奖信息如下:" << endl << endl;
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 << endl;
}
}
system("pause");
system("cls");
}
// 11. 文件清空
void SpeechManager::clearRecord()
{
cout << endl << "是否确定清空文件?" << endl << endl
<< "1.是 2.否" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
// 确认清空
ofstream ofs("Speech.csv", ios::trunc); // 删除文件后重新创建,相当于是清空
ofs.close();
// 更新状态,即初始化
this->InitSpeech(); // 初始化成员属性
this->CreateSpeeker(); // 添加参赛选手
this->loadRecord(); // 读取往届记录
cout << endl << "清空成功!" << endl << endl;
}
system("pause");
system("cls");
}