Bootstrap

基于STL的演讲比赛流程管理系统(C++STL实战)

目录

1.演讲比赛程序需求

1.1比赛规则

1.2程序功能

2.项目创建

3.创建管理类

3.1创建文件

3.2头文件实现

3.3源文件实现

4.菜单功能

4.1添加成员函数

4.2菜单功能实现

4.3测试菜单功能

5.退出功能

5.1提供功能接口

5.2实现退出功能

6.演讲比赛功能

6.1功能分析

6.2创建选手类

6.3比赛

6.3.1成员属性添加

6.3.2初始化属性

6.3.3创建选手

6.3.4开始比赛成员函数添加

6.3.5抽签

6.3.6开始比赛

6.3.7显示比赛分数

6.3.8第二轮比赛

6.4保存分数

7.查看记录

7.1读取记录分数

7.2查看记录功能

7.4bug解决

8.清空记录


1.演讲比赛程序需求

1.1比赛规则

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

1.2程序功能

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

2.项目创建

3.创建管理类

功能描述:

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

3.1创建文件

  • 在头文件和源文件下分别创建speechManager.h和speechManager.cpp文件

3.2头文件实现

#pragma once
#include <iostream>
using namespace std;

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

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

	}
};

3.3源文件实现

#include"speechManager.h"
//构造函数
SpeechManager::SpeechManager()
{

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

}

4.菜单功能

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

4.1添加成员函数

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

//展示菜单
	void show_Menu();

4.2菜单功能实现

在管理类speechManager.cpp中实现成员函数void show_Menu();

//展示菜单
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测试菜单功能

#include <iostream>
using namespace std;
#include"speechManager.h"
int main()
{
	//创建管理类对象
	SpeechManager sm;
	sm.show_Menu();
	system("pause");
	return 0;
}

5.退出功能

功能实现:实现退出程序

5.1提供功能接口

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

代码:

#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.cpp中实现成员函数void exitSystem();

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

6.演讲比赛功能

6.1功能分析

比赛流程分析:

抽签——开始比赛——显示第一轮比赛结果——抽签——开始演讲比赛——显示前三名结果——保存分数

6.2创建选手类

  • 选手类中的属性包括:选手姓名 分数
  • 头文件中创建speaker.h文件并添加如下代码
#pragma once
#include <iostream>
using namespace std;
class Speaker
{
public:
	string m_name;
	double m_score[2];     //最多有两轮得分
};

6.3比赛

6.3.1成员属性添加

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

6.3.2初始化属性

在speechManager.h中声明初始化属性函数void initSpeaker();

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

在speechManager.cpp中实现初始化属性函数void initSpeaker();

//初始化容器和属性
void SpeechManager::initSpeech()
{
	//容器置空
	v1.clear();
	v2.clear();
	vVictory.clear();
	m_Speaker.clear();
	//初始化比赛轮数
	m_Index = 1;
}

在speechmanager.cpp构造函数中调用void initSpeech();

SpeechManager::SpeechManager()
{
	//初始化容器和属性
	initSpeech();
}

6.3.3创建选手

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

//初始化创建12名选手
	void creatSpeaker();

在speechManager.cpp中 实现开始比赛的成员函数void creatSpeaker();

//初始化创建12名选手
void SpeechManager::creatSpeaker()
{
	string nameSeed = "ABSDEFGHIJKL";
	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的容器中
		v1.push_back(i + 10001);
		//选手编号以及对应选手 放入到map容器中
		m_Speaker.insert(make_pair(i + 10001, sp));
	}
}

在speechmanager.cpp构造函数中调用void creatSpeaker();

//创建12名选手
	creatSpeaker();

在main函数中,测试

//测试12名选手创建
	for (map<int, Speaker>::iterator it = sm.m_Speaker.begin(); it != sm.m_Speaker.end(); it++)
	{
		cout << "编号:" << it->first << "\t姓名:" << it->second.m_name << "\t分数:" << it->second.m_score << endl;
	}

6.3.4开始比赛成员函数添加

  • 在speechManager.h中提供开始比赛的成员函数void startSpeech();
    	//开始比赛
    	void startSpeech();
  • 该函数的主要功能是控制比赛流程
  • 在speechManager.cpp中将startSpeech的空实现先写入
  • 将整个比赛的流程写入到函数中
//开始比赛 
void SpeechManager::startSpeech()
{
	//第一轮开始比赛
	//1.抽签
	speechDraw();
	//2.比赛

	//3.显示晋级结果

	//第二轮开始比赛

	//1.抽签

	//2.比赛

	//3.显示最终结果
}

6.3.5抽签

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

//抽签
	void speechDraw();

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

//开始比赛 
void SpeechManager::startSpeech()
{
	//第一轮开始比赛
	//1.抽签
	speechDraw();
	//2.比赛

	//3.显示晋级结果

	//第二轮开始比赛

	//1.抽签

	//2.比赛

	//3.显示最终结果
}
//抽签
void SpeechManager::speechDraw()
{
	cout << "第<<" << m_Index << ">>轮比赛选手正抽签" << endl;
	cout << "---------------------------------------------------" << endl;
	cout << "抽签后演讲顺序如下: " << endl;
	if (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 = v1.begin(); it != v1.end(); it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	cout << "---------------------------------------------------------" << endl;
	system("pause");
	cout << endl;
}

6.3.6开始比赛

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

//比赛
	void speechContest();

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

//比赛
void SpeechManager:: speechContest()
{
	cout << "--------第" << m_Index << "轮比赛正式开始————————" << endl;
	//准备临时容器 存放小组成绩
	multimap<double, int, greater<double>> groupScore;
	int num = 0;      //记录人员个数 6人一组
	vector<int> v_Src;      //比赛选手容器
	if (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;     //60-100
			//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 << "姓名:" << m_Speaker[*it].m_name << "  获取平均分:" << avg << endl;
		//将平均分放入到map容器中
		m_Speaker[*it].m_score[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 << "  姓名:" << m_Speaker[it->second].m_name << "  比赛成绩:" << m_Speaker[it->second].m_score[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 (m_Index == 1)
				{
					v2.push_back((*it).second);
				}
				else
				{
					vVictory.push_back((*it).second);
				}
			}

			groupScore.clear();   //小组比赛容器清空
			cout << endl;
		}
	}
	cout << "----------------第" << m_Index << "轮比赛完毕------------------" << endl;
	system("pause");
}

6.3.7显示比赛分数

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

//显示结果
	void showScore();

在speechManager.cpp中实现显示分数的成员函数void showScore();

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

6.3.8第二轮比赛

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

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

//第二轮开始比赛
	m_Index++;
	//1.抽签
	speechDraw();
	//2.比赛
	speechContest();
	//3.显示最终结果
	showScore();

6.4保存分数

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

功能实现:

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

	//保存记录
	void saveRecord();

在speechManager.cpp中实现保存记录的成员函数void saveRecord();

//保存记录
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 << "," << m_Speaker[*it].m_score[1] << ",";
	}
	ofs << endl;
	//关闭
	ofs.close();
	cout << "记录已经保存" << endl;
}

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

//4.保存分数到文件中
	saveRecord();
	cout << "本届比赛完毕!" << endl;
	system("pause");
	system("cls");

7.查看记录

7.1读取记录分数

  • 在speechManager.h中添加保存记录的成员函数 void loadRecord();
  • 添加判断文件是否为空的标志bool fileIsEmpty();
  • 添加往届记录的容器map<int,vector<string>>m_Record;

其中m_Record中的key代表第几届,value记录具体的信息


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

在speechManager.cpp中实现保存记录的成员函数 void loadRecord(); 

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

	ifs.putback(ch);   //将上面读取的单个字符放回来
	string data;
	int index = 0;
	while (ifs >> data)
	{
		vector<string>v;  //存放6个string字符串
		//cout << data << endl;
		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;
		}
		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;
	}*/
}

7.2查看记录功能

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

	//显示往届得分
	void showRecord();

在speechManager.cpp中实现显示记录的成员函数 void showRecord(); 

void SpeechManager::showRecord()
{
	for (int i = 0; i < m_Record.size(); i++)
	{
		cout << "第" << i + 1 << "届 "
			<< "冠军编号:" << m_Record[i][0] << " 得分:" << m_Record[i][1] << " "
			<< " 亚军编号:" << m_Record[i][2] << " 得分:" << m_Record[i][3] << " "
			<< "冠军编号:" << m_Record[i][4] << " 得分:" << m_Record[i][5] << endl;
	}
	system("pause");
	system("cls");
}

7.4bug解决

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

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

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

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

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

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

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

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

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

 5.加随机种子

8.清空记录

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

//清空记录
	void clearRecord();

在speechManager.cpp中实现保存记录的成员函数void clearRecord();

//清空记录
void SpeechManager::clearRecord()
{
	cout << "是否确定清空文件?" << endl;
	cout << "1.是" << endl;
	cout << "2.否" << endl;
	int select = 0;
	cin >> select;
	if (select == 1)
	{
		//确认清空
		ofstream ofs("speech.csv", ios::trunc);
		ofs.close();
		//初始化容器和属性
		initSpeech();
		//创建12名选手
		creatSpeaker();
		//加载往届记录
		loadRecord();
		cout << "清空成功!" << endl;
	}
	system("pause");
	system("cls");
}

;