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

目录

一、演讲比赛程序要求

        1、比赛规则

        2、程序功能

二、创建管理类

三、菜单功能

四、退出功能

五、演讲比赛功能

1、功能分析

2、创建选手类

3、进行比赛

4、保存分数

 六、查看比赛记录

1、读取记录分数

2、查看记录功能

3、bug解决

七、清空功能

 


一、演讲比赛程序要求

1、比赛规则

举办一场演讲比赛,共有12人参加,比赛共2轮,第一轮为淘汰赛,第二轮为决赛。

①每位选手都有对应的编号:如10001,10002...10012;A、B...、L

②比赛方式:分组比赛,每组6个人比赛一场,共2场

③第一轮比赛分为2个小组,整体按照选手编号进行抽签后顺序演讲

④十名评委分别给每位选手打分,去除最高分和最低分,取平均分为本轮选手的成绩

⑤当第一轮比赛结束后,每个小组的前三名晋级进入下一轮比赛,后三名淘汰

⑥第二轮决赛,六位选手前三名胜出,按成绩分为冠军亚军季军

⑦每轮比赛后显示晋级选手的信息


2、程序功能

①开始比赛功能:完成整届比赛的流程,比赛各个阶段需要给用户一个提示,用户按任意键后继续下一个阶段

②查看往届记录:查看之前比赛的前三名结果,包含姓名和成绩。每次比赛都会记录到文件中,以csv格式保存

③清空比赛记录:将文件中数据清空

④退出比赛程序:可以退出当前程序


二、创建管理类

功能:

①提供菜单界面与用户交互

②对演讲比赛流程进行控制

③与文件的读写交互


首先创建SpeachManager的头文件和源文件 

基于STL的 演讲比赛流程管理系统_第1张图片

 然后在头文件里实现管理类Manager,并带上构造函数和析构函数

基于STL的 演讲比赛流程管理系统_第2张图片

然后在源文件里空实现构造和析构函数,注意带作用域

 基于STL的 演讲比赛流程管理系统_第3张图片


三、菜单功能

功能:与用户交互的界面

首先在管理类中添加菜单显示接口show_menu();

基于STL的 演讲比赛流程管理系统_第4张图片

然后在源文件中实现 :注意带上作用域Manager::

void Manager::show_menu()
{
	cout << "******************************************" << endl;
	cout << "********** 欢迎使用演讲比赛系统 **********" << endl;
	cout << "**********    1、开始演讲比赛   **********" << endl;
	cout << "**********    2、查看往届记录   **********" << endl;
	cout << "**********    3、清空比赛记录   **********" << endl;
	cout << "**********    0、退出比赛系统   **********" << endl;
	cout << "******************************************" << endl;
}

然后在main函数中调用:我们先包含SpeachManager.h头文件,然后再根据管理类创建对象m

基于STL的 演讲比赛流程管理系统_第5张图片

调用:基于STL的 演讲比赛流程管理系统_第6张图片


四、退出功能

功能:退出系统

目前系统只有一个显示功能,而且不支持输入与选择,因此我们使用while(true)和switch语句来实现该功能

在头文件里声明exit_m();接口后在源文件中实现:

 基于STL的 演讲比赛流程管理系统_第7张图片

// 退出功能
void Manager::exit_m()
{
	cout << "欢迎下次使用!" << endl;
	exit(0);
}

 修改main函数,添加while(true)循环和switch语句

int main()
{
	Manager m;
	int input;
	while (true)
	{
		m.show_menu();
		cout << "请选择:" << endl;
		cin >> input;
		switch (input)
		{
			case 1:	// 开始比赛
				break;
			case 2: // 显示往届记录
				break;
			case 3: // 清空所有记录 
				break;
			case 0: // 退出系统
				m.exit_m();
			default:
				system("cls"); // 清屏
				break;
		}
	}
	return 0;
}

基于STL的 演讲比赛流程管理系统_第8张图片


五、演讲比赛功能

1、功能分析

比赛流程:基于STL的 演讲比赛流程管理系统_第9张图片


2、创建选手类

选手类speaker,应包含属性姓名name与分数score(分数有2轮)

在头文件中创建:

class speaker  // 选手类
{
public:
	string s_name;
	double s_score[2]; // 2轮得分,double使不会出现同分的情况
};

3、进行比赛

①添加成员属性

在管理类中添加各种属性:

    vector v1; // 存放第1轮比赛的选手,共12人
	vector v2; // 存放第2轮比赛的选手,共6人
	vector v3; // 存放比赛胜出的选手,共3人

	map m_speaker; // 存放编号以及对应的选手 容器
	int index; // 记录比赛的轮数

②初始化属性

头文件中生成初始化属性接口initSpeaker();在源文件中实现,并在构造函数中调用

// 初始化属性
void Manager::initSpeaker()
{
	// 全部清空并置1
	this->v1.clear();
	this->v2.clear();
	this->v3.clear();
	this->m_speaker.clear();
	this->index = 1;
}

 调用:

基于STL的 演讲比赛流程管理系统_第10张图片

③创建选手

首先在管理类中添加创建选手的接口createrSperker();

然后在源文件中实现

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

		speaker sp; // 创建一位选手
		sp.s_name = name; // 选手名字初始化
		for (int j = 0; j < 2; j++)
		{
			sp.s_score[j] = 0; // 选手分数初始化
		}
		// 为选手编号
		this->v1.push_back(i + 10001);
		// 将选手编号以及对应选手插入到map容器中,编号10001-100012
		this->m_speaker.insert(make_pair(i + 10001, sp));
	}
}

然后在构造函数中调用

基于STL的 演讲比赛流程管理系统_第11张图片

这样就完成了选手的创建,不过为了方便查看,我再实现一个查看map容器中元素的函数,打印出目前选手的信息

	for (map::iterator it = m.m_speaker.begin(); it != m.m_speaker.end(); it++)
	{
		cout << "选手编号:"<first<<"\t姓名:" << it->second.s_name << "\t分数:" << it->second.s_score[1] << endl;
	}

基于STL的 演讲比赛流程管理系统_第12张图片

④开始比赛成员函数添加

首先在管理类中添加开始比赛成员函数startSpeach();

 然后在源文件中空实现

// 开始比赛
void Manager::startSpeach()
{
	// 第一轮比赛
	//	1、抽签
	//	2、比赛
	//	3、显示比赛结果
	
	// 第二轮比赛
	//	1、抽签
	//	2、比赛
	//	3、显示比赛结果
}

⑤抽签

抽签分为2种:第一轮抽签与第二轮抽签

我们可以根据属性index来判断比赛进行的轮数,以给容器v1或是v2进行洗牌

我们先在管理类中加上抽签DrawSpeach();接口

然后在源文件中实现

void Manager::DrawSpeach()
{
	cout << "第" << this->index << "轮抽签正在进行" << endl;
	cout << "***************************************" << endl;
	Sleep(1000);
	cout << "抽签后演讲顺序如下" << endl;
	if (this->index == 1)
	{
		random_shuffle(v1.begin(), v1.end());
		for (vector::iterator it = v1.begin(); it != v1.end(); it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	else
	{
		random_shuffle(v2.begin(), v2.end());
		for (vector::iterator it = v2.begin(); it != v2.end(); it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	cout << "***************************************" << endl;
	system("pause");
	cout << endl;
}

最后在开始比赛stratSpeach接口中调用

基于STL的 演讲比赛流程管理系统_第13张图片

测试:

基于STL的 演讲比赛流程管理系统_第14张图片

⑥开始比赛

比赛流程代码可以分为4部分:

Ⅰ创建比赛的人员的容器v_person,并根据不同轮数将对应容器赋给v_perso

Ⅱ创建人数的计数num,遍历v_person里所有选手,创建deque容器,每个选手进行10名评委的打分并将分数插入到deque容器,排序后去除最高分和最低分,最后获取总分和平均分,并将平均分赋值给对应轮数的score[0/1]中

Ⅲ创建小组容器以存储对组,以平均分和编号创建对组,每6个选手为一组,输出这6名选手的姓名编号与成绩

Ⅳ取出前3名,如果是第1场比赛,则将前三名插入到v2容器,如果是第2场比赛,则插入到v3中,每6个清空一次

先在管理类中创建进行比赛Speach(); 接口

然后在源文件中实现

void Manager::Speach()
{
	cout << "------------" << "第" << this->index << "组比赛正式开始" << "-------------" << endl;
	multimap> Group; // 存储分数与选手编号,降序排列,放在最外面,防止进入循环创建不同的容器

	//	1、创建比赛的人员的容器v_person,并根据不同轮数将对应容器赋给v_person
	vectorv_person;
	if (this->index == 1)
	{
		v_person = v1;
	}
	else
	{
		v_person = v2;
	}

	//	2、创建人数的计数num,遍历v_person里所有选手,创建deque容器,每个选手进行10名评委的打分
	//	   排序后去除最高分和最低分,最后获取总分和平均分
	int num = 0;
	for (vector::iterator it = v_person.begin(); it != v_person.end(); it++)
	{
		// 评委打分
		dequed;
		for (int i = 0; i < 10; i++)
		{
			double score = (rand() % 401 + 600) / 10.f; // 随机数600-1000,除以10后保留1位小数,是60.0-100.0
			d.push_back(score); // 将分数插入到d中
		}
		sort(d.begin(), d.end(),greater()); // 降序 排序
		d.pop_back();	// 去除最低分
		d.pop_front();	// 去除最高分

		double sum = accumulate(d.begin(), d.end(),0); // 获取总分
		double avg = sum / d.size();	// 获取均值
		this->m_speaker[*it].s_score[this->index - 1] = avg; // 将均分存入到选手对应轮数的score里

		//	3、创建小组容器,以平均分和编号创建对组,每6个选手为一组,输出这6名选手的姓名编号与成绩
		Group.insert(make_pair(avg, *it)); // 将每位选手的均分和编号插入到Group容器中
		num++;	// 插入后人数++
		if (num % 6 == 0) // 每插入6个人,进入一次遍历输出,此时输出的已经排序
		{
			cout <<"第" << num / 6 << "组选手比赛名次:" << endl;
			for (multimap>::iterator it = Group.begin(); it != Group.end(); it++)
			{
				cout << "编号:" << it->second << "\t姓名:"
					<< this->m_speaker[it->second].s_name << "\t平均分:"
					<< this->m_speaker[it->second].s_score[this->index - 1] << endl;
			}

			//	4、取出前3名,如果是第1场比赛,则将前三名插入到v2容器,如果是第2场比赛,则插入到v3中,每6个清空一次
			int count = 0; // 使我们可以取出前三名:0、1、2
			for (multimap>::iterator it = Group.begin(); it != Group.end() && count < 3; it++, count++)
			{
				if (this->index == 1)
				{
					v2.push_back((*it).second);
				}
				else
				{
					v3.push_back((*it).second);
				}
			}
			Group.clear(); // 如果不清空,则下次会有上次遍历的值
			cout << endl;
		}
	}
	cout << "--------------"<<"第" << this->index << "轮比赛结束" <<"---------------" << endl;	 
}

最后在开始比赛stratSpeach接口中调用

基于STL的 演讲比赛流程管理系统_第15张图片

基于STL的 演讲比赛流程管理系统_第16张图片

⑦显示比赛分数

显示比赛晋级的选手,即每轮比赛的前三名

先在管理类中添加显示比赛结果的接口函数showSpeach();

然后在源文件中实现

void Manager::showSpeach()
{
	cout << "------------" << "第" << this->index << "轮选手晋级信息:" << "-------------" << endl;
	vectorv;
	if (this->index == 1)
	{
		v = v2;
	}
	else
	{
		v = v3;
	}
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "编号:" << *it << "\t姓名:"
			<< this->m_speaker[*it].s_name << "\t平均分:"
			<< this->m_speaker[*it].s_score[this->index - 1] << endl;
	}
	cout << endl;
	system("pause");
	system("cls");
}

 最后在开始比赛stratSpeach接口中调用

基于STL的 演讲比赛流程管理系统_第17张图片

基于STL的 演讲比赛流程管理系统_第18张图片

⑧第二轮比赛

把第一轮比赛流程的代码加到第二轮即可

基于STL的 演讲比赛流程管理系统_第19张图片

不过注意场次index要++

基于STL的 演讲比赛流程管理系统_第20张图片


4、保存分数

先在管理类中添加保存比赛结果的接口函数saveSpeach();

基于STL的 演讲比赛流程管理系统_第21张图片

然后在源文件中实现

void Manager::saveSpeach()
{
	ofstream ofs;
	ofs.open("Speach.csv", ios::out | ios::app);
	// 以输出和追加方式打开文件,后缀命名为csv
	// 将最终获胜的3人数据写入文件
	for (vector::iterator it = v3.begin(); it != v3.end(); it++)
	{
		ofs << *it <<"," <m_speaker[*it].s_score[1] << ",";
	}
	ofs << endl;
	ofs.close();
	cout << "文件已保存!" << endl;
}

基于STL的 演讲比赛流程管理系统_第22张图片

基于STL的 演讲比赛流程管理系统_第23张图片


 六、查看比赛记录

1、读取记录分数

先在管理类中添加读取记录分数的接口函数loadSpeach();以及记录文件是否为空的标识符fileISempty和存放往届记录的容器map> s_Load

基于STL的 演讲比赛流程管理系统_第24张图片

然后在源文件中实现:

 读取文件时,会有3种情况:

Ⅰ文件不存在

	ifstream ifs("Speach.csv", ios::in); // 读方式打开文件

	// 1、文件不存在
	if (!ifs.is_open())
	{
		this->fileISempty = true;
		cout << "文件不存在!" << endl;
		ifs.close();
		return;
	}

Ⅱ文件为空(或被清空)

	// 2、文件为空(被清空)
	char ch;
	ifs >> ch;
	if (ifs.eof())
	{
		cout << "文件为空!" << endl;
		this->fileISempty = true;
		ifs.close();
		return;
	}

Ⅲ 文件不为空

因为不同数据之间用逗号, 隔开,我们通过substr截取开头到逗号,中间的数据来分割每个数据

而下一个截取的开头就是上次截取结尾+1,结尾就是下一个逗号,的位置

然后将每个数据存放到一个vector容器中,最后将容器以对组插入到map容器

	// 3、文件不为空
	this->fileISempty = false;
	ifs.putback(ch);// 将上面截取的1个字符放回
	string data; // 存储文件中读取到的信息
	int session = 1; // 比赛的届数
	while (ifs >> data)
	{
		vectorv; // 存储选手编号以及分数的容器,直接都用string类型
		int pos = -1; // 查到,逗号的位置,将位置存储在pos
		int start = 0;// 起始位置
		while (true)
		{
			pos = data.find(",", start);// 从start 0开始查找 ,逗号 
		// 10003,80.375,10004,80,10007,79.375
		//  start 1  pos ,逗号所在的位置,中间要截取的就是pos-start
			if (pos == -1)
			{
				// 没找到
				break;
			}
			string tmp = data.substr(start, pos - start);
			v.push_back(tmp);
			start = pos + 1; // 让start移到pos+1的位置
		}
		this->s_Load.insert(make_pair(session, v)); // 将届数和选手信息插入到s_Load里
		session++;
	}

2、查看记录功能

先在管理类中添加查看记录分数的接口函数showRecord();

 然后在源文件中实现:判断完文件不为空后,直接遍历输出即可

void Manager::showRecord()
{
	if (this->fileISempty)
	{
		cout << "文件为空或不存在!" << endl;
	}
	else
	{
		for (map>::iterator it = s_Load.begin(); it != s_Load.end(); it++)
		{
			cout << "第" << it->first << "届 "
				<< "\t冠军编号为:" << it->second[0] << "\t分数为:" << it->second[1] << endl
				<< "\t亚军编号为:" << it->second[2] << "\t分数为:" << it->second[3] << endl
				<< "\t季军编号为:" << it->second[4] << "\t分数为:" << it->second[5] << endl;
			Sleep(40);
		}
	}
	Sleep(500);
	system("pause");
	system("cls");
}

基于STL的 演讲比赛流程管理系统_第25张图片


3、bug解决

当Speach.csv中没有数据时,我们进行一场比赛,结束后数据会存放到文件中,但这时直接运行2查看记录分数时仍然会提示文件为空

基于STL的 演讲比赛流程管理系统_第26张图片

 进行比赛

基于STL的 演讲比赛流程管理系统_第27张图片

再次使用2,仍然为空

基于STL的 演讲比赛流程管理系统_第28张图片

解决:我们每次保存文件时,都应在最后使fileISempty为false

基于STL的 演讲比赛流程管理系统_第29张图片

 这样就解决了

Ⅱ不过就上面解决后,我们继续执行代码,重复操作

基于STL的 演讲比赛流程管理系统_第30张图片

会发现程序没有任何输出,这是因为数据没有实时更新

解决:我们需要再次初始化属性、创建选手并获取往届记录

即将构造函数中的函数在进行比赛的接口Speach(0;中调用

基于STL的 演讲比赛流程管理系统_第31张图片        

 基于STL的 演讲比赛流程管理系统_第32张图片

 Ⅲ 初始化时,没有初始化记录容器s_Load

会导致我们怎么清空容器,容器都存在数据

解决:在初始化接口initSpeaker();中初始化记录容器

基于STL的 演讲比赛流程管理系统_第33张图片


 七、清空功能

先在管理类中添加清空文件的接口函数destroyRecord();

然后在源文件中实现

void Manager:: destoryRecord()
{
	cout << "是否确认清空?" << endl;
	cout << "确认:1" << endl;
	cout << "取消:0" << endl;
	cout << "请输入:" << endl;
	int input;
	cin >> input;

	if (input == 1)
	{
		ofstream ofs("Speach.csv", ios::trunc);
		// trunc:如果文件存在,删除并重新创建
		ofs.close();

		// 然后将属性初始化
		this->initSpeaker(); // 初始化
		this->createSpeaker(); // 创建选手
		this->loadSpeach(); // 获取往届记录
		cout << "清空成功!" << endl;
	}
	system("pause");
	system("cls");
}

最后在main函数中调用

基于STL的 演讲比赛流程管理系统_第34张图片

 测试:

基于STL的 演讲比赛流程管理系统_第35张图片

 基于STL的 演讲比赛流程管理系统_第36张图片

基于STL的 演讲比赛流程管理系统_第37张图片

 至此该项目全部完成

你可能感兴趣的:(C++,c++)