黑马C++_基于STL的演讲比赛管理系统

基于STL的演讲比赛管理系统

  • 演讲比赛需求
  • 程序功能
  • 源代码
    • 主函数
    • 头文件
    • 函数实现cpp文件

B站黑马C++中的STL案例

演讲比赛需求

学校就行一场演讲比赛,共有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. 文件清空
};

函数实现cpp文件

#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");
}

你可能感兴趣的:(C++,c++,开发语言)