C++ 演讲比赛流程管理系统

演讲比赛流程管理系统

一、 程序需求

1、 比赛规则

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

2、 程序功能

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

二、 创建管理类

功能描述:

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

1、 创建文件

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

同时,创建 演讲比赛流程管理系统.cpp 作为主要运行函数

2、 头文件实现

在 speechManager.h 中

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

// 设计管理类
class SpeechManager
{
public:
	SpeechManager();

	~SpeechManager();
};

3、 源文件实现

在 speechManager.cpp 中

#include "speechManager.h"

SpeechManager::SpeechManager() {}
SpeechManager::~SpeechManager() {}

三、 菜单功能

功能描述:

  • 与用户的沟通界面

1、 添加成员函数

在管理类 speechManager.h 中添加成员函数

// 菜单显示
void showMenu();

2、 实现函数

在 speechManager.cpp 中实现成员函数

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

3、 测试函数

在主要运行函数中添加

#include "speechManager.h"
#include <iostream>
using namespace std;

int main()
{
	SpeechManager sm;
	sm.showMenu();

	system("pause");
	return 0;
}

四、 退出功能

功能描述:

  • 实现退出功能

1、 提供功能接口

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

#include "speechManager.h"
#include <iostream>
using namespace std;

int main()
{
	// 实例化
	SpeechManager sm;
	while (true)
	{
		sm.showMenu();
		int choice;
		cout << "请输入你的选择:" << endl;
		cin >> choice;

		switch (choice)
		{
		case 0:  // 退出程序
			sm.exitSystem();
			break;
		case 1:  // 开始比赛
			break;
		case 2:  // 查看记录
			break;
		case 3:  // 清空记录
			break;
		default:
			cout << "请按照要求输入哦!" << endl;
			system("pause");
			system("cls");
			break;
		}
		
	}

	system("pause");
	return 0;
}

2、 添加成员函数

在 speechManager.h 中添加成员函数

// 退出程序
void exitSystem();

3、 实现函数

在 speechManager.cpp 中实现函数

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

五、 演讲比赛功能

1、 功能分析

比赛流程分析:

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

2、 创建选手类

  • 选手属性包含:选手姓名、分数

在 speechManager.h 中添加

class Speaker
{
public:
	string m_Name;  // 姓名
	double m_Score[2];  // 分数,存储两轮比赛的分数
};

注意:选手类要添加到 SpeechManager 类前面

3、 比赛

3.1 成员属性添加

  • 在 speechManager.h 中 的 SpeechManager类 添加属性
// 成员属性
// 比赛选手 容器 12人
vector<int> v1;
// 第二轮选手 容器 6人
vector<int> v2;
// 胜利前三名
vector<int> vVictory;

// 存放编号以及对应的 具体选手,容器
map<int, Speaker> m_Speaker;

// 记录比赛轮数
int m_Index;

3.2 初始化属性

  • 在 speechManager.h 中提供开始比赛的成员函数
// 初始化属性
void initSpeech();

3.3 函数实现

在 speechManager.cpp 中实现初始化属性

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

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

3.4 创建选手

在 speechManager.h SpeechManager 类中提供开始比赛的成员函数

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

在 speechManager.cpp 中实现函数

SpeechManager::SpeechManager() 
{
	// 初始化容器和属性
	this->initSpeech();
	// 创建12名选手
	this->createSpeaker();
}
void SpeechManager::createSpeaker()
{
	string nameSeed = "ABCDEFGHIJKL";
	for (int i = 0; i < nameSeed.size(); i++)
	{
		// 创建具体选手
		Speaker sp;
		sp.m_Name = "选手";
		sp.m_Name += nameSeed[i];
		for (int j = 0; j < 2; j++)
		{
			// 初始化分数
			sp.m_Score[j] = 0;
		}
		// 创建选手编号,并且放入 v1 容器中
		this->v1.push_back(i + 10001);
		// 将选手编号一一对应每个选手
		this->m_Speaker.insert(map<int, Speaker>::value_type(i + 10001, sp));
	}
}

3.5 开始比赛

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

	// 抽签

	// 比赛

	// 显示晋级结果

	// 第二轮比赛开始

	// 抽签

	// 比赛

	// 显示最终结果

	// 保存分数
}

3.6 抽签功能

在 speechManager.h 中添加抽签函数声明

// 抽签
void speechDraw();

在 speechManager.cpp 中实现抽签函数

void SpeechManager::speechDraw()
{
	string s(20, '-');
	cout << "第" << this->m_Index << "轮比赛开始" << endl
		<< s << endl
		<< "抽签结果如下:" << endl;
 	if (this->m_Index == 1)
	{
		// 第一轮比赛
		random_shuffle(this->v1.begin(), this->v1.end());
		for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	else
	{
		// 第二轮比赛
		random_shuffle(this->v2.begin(), this->v2.end());
		for (vector<int>::iterator it = v2.begin(); it != v2.end(); it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	cout << s << endl;
	system("pause");
	cout << endl;
}

3.7 比赛过程

在 speechManager.h 中提供比赛的成员函数

// 比赛
void speechContest();

在 speechManager.cpp 中实现成员函数

void SpeechManager::speechContest()
{
	string s(20, '-');
	cout << "第" << this->m_Index << "轮比赛正式开始" << endl
		<< s << endl;
	// 准备一个容器,存放小组数据,同时,降序排序
	multimap<double, int, greater<double>> mp;

	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++)
	{
		deque<double> d;  // 存放分数
		for (int i = 0; i < 10; i++)
		{
			double score = (rand() % 401 + 600) / 10.f;  // 600 ~1000  10.f代表小数,分数为百分制
			d.push_back(score);
		}
		sort(d.begin(), d.end(), greater<double>());  // 降序
		// 删除最高分和最低分
		d.pop_back();  
		d.pop_front();

		double sum = accumulate(d.begin(), d.end(), 0);  // 求和
		double avg = sum / (double)d.size();  // 平均分
		// 将平均分放入容器中
		this->m_Speaker[*it].m_Score[this->m_Index - 1] = avg;

		// 将数据放入到临时小组中
		mp.insert(make_pair(avg, *it));  // key 为得分
		// 每六人,去后三名
		if (mp.size() % 6 == 0)
		{
			cout << "第" << mp.size() / 6 << "组小组名次如下:" << endl;
			for (multimap<double, int, greater<double>>::iterator it = mp.begin(); it != mp.end(); it++)
			{
				cout << "编号:" << it->second 
					<< "  姓名:" << this->m_Speaker[it->second].m_Name 
					<< "  分数:" << this->m_Speaker[it->second].m_Score[0] << endl;
			}
			// 取走前三名,放入下一个容器
			int count = 0;
			for (multimap<double, int, greater<double>>::iterator it = mp.begin(); it != mp.end() && count < 3; it++, count++)
			{
				if (this->m_Index == 1)
				{
					v2.push_back((*it).second);
				}
				else
				{
					vVictory.push_back((*it).second);
				}
			}
			mp.clear();  // 重置数据
		}
	}
	cout << "第" << this->m_Index << "轮比赛结束!" << endl
		<< s << endl;
	system("pause");
}

number = (rand()%(maxValue - minValue +1)) + minValue;

3.8 显示分数

在 speechManager.h 中提供显示分数的成员函数

// 显示分数
void showScore();

在 speechManager.cpp 中实现成员函数

void SpeechManager::showScore()
{
	string s(20, '-');
	cout << "第" << this->m_Index << "轮晋级选手信息如下:" << endl;
	cout << s << 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;
	}
	system("pause");
	system("cls");
	this->showMenu();
}

3.9 第二轮比赛

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

  • 在startSpeech 比赛流程控制函数中,加入第二轮的流程
void SpeechManager::startSpeech()
{
	// 开始比赛,比赛整个流程控制函数
	// 第一轮比赛开始
	// 抽签
	this->speechDraw();  
	// 比赛
	this->speechContest();
	// 显示晋级结果
	this->showScore();
	// 第二轮比赛开始
	this->m_Index++;
	// 抽签
	this->speechDraw();
	// 比赛
	this->speechContest();
	// 显示最终结果
	this->showScore();
	// 保存分数
}

3.10 保存分数

功能描述:

  • 将每次演讲比赛的得分记录到文件中

功能实现:

  • 在 speechManager.h 中添加保存记录的成员函数
// 保存记录
void saveRecord();
  • 在 speechManager.cpp 中实现成员函数
void SpeechManager::saveRecord()
{
	// 保存记录
	ofstream ofs("./spech.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();
}

六、 查看记录

1、 读取记录分数

  • 在 speechManager.h 中添加保存记录的成员函数
  • 添加判断文件是否为空的标志
  • 添加往届记录的容器

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

// 读取记录
void loadRecord();
// 判断文件是否为空
bool fileEmpty;
// 往届记录
map<int, vector<string>> m_Record;

在 speechManager.cpp 中实现成员函数

void SpeechManager::loadRecord()
{
	ifstream ifs("./spech.csv", ios::in);  // 读文件
	// 文件不存在
	if (!ifs.is_open())
	{
		this->fileEmpty = true;
		ifs.close();
	}
	// 文件清空情况
	char ch;
	ifs >> ch;
	if (ifs.eof())
	{
		this->fileEmpty = true;
		ifs.close();
	}
	// 文件不为空
	this->fileEmpty = false;
	ifs.putback(ch);  // 将上面读取的单个字符再放回来
	string data;
	int index = 0;
	while (ifs >> data)
	{
		vector<string> v;
		int pos = -1;  // 查到逗号位置的变量
		int start = 0;
		while (true) {
			pos = data.find(",", start);
			if (pos == -1)
			{
				break;
			}
			string temp = data.substr(start, pos - start);  // 得到所有的字符串
			v.push_back(temp);
			start = pos + 1;
		}
		this->m_Record.insert(make_pair(index + 1, v));
		index++;
	}
	ifs.close();
}

2、 展示记录分数

  • 在 speechManager.h 中添加展示保存记录的成员函数
// 显示数据
void showRecord();
  • 在 speechManager.cpp 中实现函数
void SpeechManager::showRecord()
{
	if (this->fileEmpty)
	{
		cout << "文件为空或者文件不存在" << endl;
		return;
	}
	for (map<int, vector<string>>::iterator it = m_Record.begin(); it != m_Record.end(); it++)
	{
		cout << "第" << it->first << "届比赛数据:"
			<< endl << "冠军编号:" << it->second[0] << "  分数:" << it->second[1]
			<< endl << "季军编号:" << it->second[2] << "  分数:" << it->second[3]
			<< endl << "亚军编号:" << it->second[4] << "  分数:" << it->second[5]
			<< endl;
	}
	system("pause");
	system("cls");
}

七、 清空记录

1、 清空记录功能实现

  • 在 speechManager.h 中添加保存记录的成员函数
// 清空记录
void clearRecord();
  • 在 speechManager.cpp 中实现成员函数
void SpeechManager::clearRecord()
{
	// 清空文件
	cout << "是否确定清空文件?" << endl
		<< "1、 是" << endl
		<< "2、 否" << endl;
	int choice;
	cin >> choice;
	if (choice == 1)
	{
		// 确认清空
		ofstream ofsm("./speech.csv", ios::trunc);
		ofsm.close();
		cout << "清除成功!" << endl;
        // 重新初始化容器
		// 初始化容器和属性
		this->initSpeech();
		// 创建12名选手
		this->createSpeaker();
		// 加载往届记录
		this->loadRecord();
	}
	else if (choice == 0)
	{
		cout << "正在退出!" << endl;
		return;
	}
	else
	{
		cout << "输入失败!" << endl;
	}
}

2、 测试

在 main 函数中

#include "speechManager.h"
#include <iostream>
using namespace std;

int main()
{
	// 添加随机种子
	srand((unsigned int)time(NULL));
	// 实例化
	SpeechManager sm;
	while (true)
	{
		sm.showMenu();
		int choice;
		cout << "请输入你的选择:" << endl;
		cin >> choice;

		switch (choice)
		{
		case 0:  // 退出程序
			sm.exitSystem();
			break;
		case 1:  // 开始比赛
			sm.startSpeech();
			break;
		case 2:  // 查看记录
			sm.showRecord();
			break;
		case 3:  // 清空记录
			sm.clearRecord();
			system("pause");
			system("cls");
			break;
		default:
			cout << "请按照要求输入哦!" << endl;
			system("pause");
			system("cls");
			break;
		}
		
	}

	system("pause");
	return 0;
}
posted @ 2022-02-21 15:36  Kenny_LZK  阅读(161)  评论(0编辑  收藏  举报