目录
一、比赛规则描述
二、比赛程序的功能
三、比赛的运行结果
四、程序的实现
1、程序实现的大致思路
2、程序的模块化
<1>选手信息的类
<2>管理比赛所有进度的接口头文件
<3>比赛进行的实现
<4>用户的交互界面<演讲比赛管理系统.cpp>
3、待解决的问题
跟着黑马视频初学c++基础,用这个实例练习,许多更深一点的问题不清楚,欢迎评论区评论,共同学习进步!。
一、比赛规则描述
二、比赛程序的功能
三、比赛的运行结果
有之前的比赛记录,会显示四条往届的比赛记录
四、程序的实现
1、程序实现的大致思路
采用分文件编写的方式:
1、每一个选手的信息建立一个头文件<speaker.h>中,定义一个类存放。
2、对于比赛的流程与进行,建立一个头文件<speachManger.h>,用于声明所有的成员属性以及比赛流程的控制
3、建立一个<speachManger.cpp>文件用于所有成员函数的定义
4、建立一个<比赛管理系统.cpp>文件用于用户的接口,控制比赛的运行进度。
如何编写比赛的程序:
1、通过一个比赛流程的成员函数控制比赛的进度(第一轮抽签,比赛、显示晋级名单、第二轮抽签、比赛、显示获奖名单),两轮比赛的流程一致、都进行了抽签,比赛、显示晋级名单。
2、定义抽签、比赛、显示晋级名单的成员函数,两轮比赛选手数量有所不同,通过声明的三个vector容器控制两轮比赛各自的进行。一个是v1容器,用于存放第一轮比赛选手名单,一个是v2容器,用于存放第一轮晋级的名单,也就是第二轮的比赛名单,另一个是vectory容器,用于存放最终获奖名单。
3、显示往届的记录,需要文件的交互。
对于本次获奖的名单需要通过写文件进行保存,在用户使用显示往届的记录时,需要进行读文件加载往届的数据。
4、在文件的交互中,读文件时(调用显示往届记录的接口时)需要判断是否存在该文件,如果存在文件,文件是否为空,通过一个成员属性用于显示文件是否为空。
如果文件中有往届的记录,以字符串类型的方式截取每一届的记录存放在为字符串类型的vector容器中,而每一届的记录的获奖记录通过map容器进行存放,通过map容器的对组,控制每一届信息的存放。
(
文件操作之写操作:
程序中的数据都是在内存中,程序结束后,数据就无法保存。所以需要文件交互的操作进行数据的保存。
文件操作之读操作:
注意:虽然文件的写操作可以进行文件的保存,但是当关闭程序,程序再次运行时,并没有将上次程序运行后的数据读取到这次程序中。程序中也有清空文件的需求。
)
2、程序的模块化
<1>选手信息的类
<2>管理比赛所有进度的接口<speachManger.h>头文件
#pragma once
#include<iostream>
#include<vector>
#include<map>
#include"speaker.h"
using namespace std;
//设计演讲比赛管理类
class SpeachManger
{
public:
//构造函数声明
SpeachManger();
//展示菜单
void showmenu();
//退出程序
void exitSystem();
//初始化成员属性
void initspeach();
//第一轮比赛成员
vector<int>v1;
//第一轮晋级比赛成员
vector<int>v2;
//胜出的前三名成员
vector<int>vectory;
//参赛成员信息
map<int, Speaker>m_speaker;
//记录比赛的轮
int index;
//标记文件是否为空
bool FileIsEmpty;
//存放往届记录的数据
map<int, vector<string>>m_record;
//创建speaker成员
void createspeaker();
//开始比赛的流程控制函数
void startspeech();
//抽签
void speechDraw();
//开始比赛
void speechcontest();
//显示晋级信息
void showScore();
//保存记录
void saveScore();
//读取记录
void loadrecord();
//显示往届记录信息
void showrecord();
//清空记录
void clearrecord();
//析构函数声明
~SpeachManger();
};
<3>比赛进行的实现<speachManger.cpp>
#include<iostream>
#include"speachManger.h"
#include<string>
#include<vector>
#include<map>
#include<deque>
#include<functional>
#include<numeric>
#include<algorithm>
#include<fstream>
using namespace std;
//构造函数
SpeachManger::SpeachManger()
{
//调用初始化成员属性接口
this->initspeach();
//调用创建选手信息的接口
this->createspeaker();
//加载往届的记录
this->loadrecord();
}
//展示菜单
void SpeachManger::showmenu()
{
cout << "********************************" << endl;
cout << "****** 欢迎参加演讲比赛 ******" << endl;
cout << "******* 1、开始演讲比赛 ******" << endl;
cout << "******* 2、查看往届记录 ******" << endl;
cout << "******* 3、清空比赛记录 ******" << endl;
cout << "******* 0、退出比赛程序 ******" << endl;
cout << "********************************" << endl;
cout << endl;
}
//初始化容器和属性
void SpeachManger::initspeach()
{
//容器置为空
this->v1.clear();
this->v2.clear();
this->vectory.clear();
this->m_speaker.clear();
//初始化比赛的轮数
this->index = 1;
//清空往届记录的容器,但是文件记录保存数据
this->m_record.clear();
}
//创建比赛成员
void SpeachManger:: createspeaker()
{
string nameseed = "ABCDEFGHIJKL";
for (int i = 0; i < nameseed.size(); i++)
{
string name = "选手";
name += nameseed[i];
Speaker sp;
sp.name = name;
for (int i = 0; i < 2; i++)
sp.gore[i] = 0;
//选手的编号
this->v1.push_back(1000 + i);
//将选手的编号和信息存入到map容器中
this->m_speaker.insert(make_pair(1000+i,sp));
}
}
void SpeachManger::startspeech()
{
//第一轮比赛
//1、抽签
this->speechDraw();
//2、比赛
this->speechcontest();
//3、显示 晋级结果
this->showScore();
//第二轮比赛
this->index++;
//1、抽签
this->speechDraw();
//2、比赛
this->speechcontest();
//3、显示最终结果
this->showScore();
//4、保存分数到文件中
this->saveScore();
//用于查找此次程序运行中进行的比赛记录
//此次比赛结束,重置比赛,便于下次比赛
this->initspeach();
/*调用创建选手信息的接口*/
this->createspeaker();
//加载往届的记录(包括此次程序运行中的记录)
this->loadrecord();
cout << "本届比赛结束" << endl;
system("pause");
system("cls");
}
抽签
void SpeachManger::speechDraw()//抽签功能的实现
{
cout << "第--" << this->index << "--轮选手抽签开始!" << endl;
cout << "--------------------------------------" << endl;
cout << "经过抽签,演讲顺序如下: " << endl;
if (this->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;
system("pause");
}
//开始比赛
void SpeachManger::speechcontest()
{
cout << "----第" << this->index << "轮比赛正式开始-----" << endl;
vector<int>s; //存放选手的编号
multimap<double, int, greater<double>>groupscore; //用临时的map容器存放每组的选手
int num = 0; //统计每一组的目前的人数,当满一组时便于选择前三名
if (this->index == 1)
s = v1;
else
s = v2; //第二轮存放第一轮晋级的选手编号
//为每个选手打分
for (vector<int>::iterator it = s.begin(); it != s.end(); it++)
{
num++;
deque<double>g;
for (int i = 0; i < 10; i++)
{
double s_gore = (rand() % 401 + 600) / 10.f; //产生600-1000之间的百分数
g.push_back(s_gore);
}
//进行排序从大到小
sort(g.begin(), g.end(), greater<double>());
//去掉最高分,去掉最低分
g.pop_front();
g.pop_back();
//求总分然后求平均分
double sum = accumulate(g.begin(), g.end(), 0.0f);
double avg = sum / (double)g.size();
//平均分放到map容器中
this->m_speaker[*it].gore[this->index - 1] = avg;
//将平均分与其对应的编号存入临时map容器
groupscore.insert(make_pair(avg, *it));
//每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 << "name: " << this->m_speaker[it->second].name
<< " 分数为: " << this->m_speaker[it->second].gore[this->index - 1]<<endl;
}
//取走前三名
int count = 0; //限制迭代器的次数
for (multimap<double, int, greater<double>>::iterator it2 = groupscore.begin(); it2 != groupscore.end()&&count<3; it2++,count++)
{
if (this->index == 1)
v2.push_back(it2->second); //第一轮晋级选手编号
else
vectory.push_back(it2->second); //第二轮晋级选手编号
}
groupscore.clear(); //将已经评选好的小组的临时数据清空
cout << endl;
}
}
cout << "----第 " << this->index << "轮比赛结束" << endl;
system("pause");
}
//显示晋级信息
void SpeachManger::showScore()
{
cout << "第" << this->index << "轮晋级选手的信息" << endl;
vector<int>v;
//判断第几轮的输出
if (this->index == 1)
v = v2;
else
v = vectory;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
cout <<"选手编号: "<<*it<<" "<<" 姓名:"<<m_speaker[*it].name<<" "
<<"分数: "<<m_speaker[*it].gore[this->index-1]<<endl;
system("pause");
system("cls");
this->showmenu();
}
//保存记录
void SpeachManger::saveScore()
{
ofstream ofs;
ofs.open("speech.csv", ios::out |ios::app);
for (vector<int>::iterator it = vectory.begin(); it != vectory.end(); it++)
ofs << *it << "," << m_speaker[*it].gore[1]<<",";
ofs << endl;
ofs.close();
cout << "记录已经保存" << endl;
//文件保存后更改文件的状态
this->FileIsEmpty = false;
}
//读取记录
void SpeachManger::loadrecord()
{
ifstream ifs("speech.csv", ios::in);
//判断文件是否存在,通过is_open判断文件是否可以打开
if (!ifs.is_open())
{
cout << "文件不存在" << endl;
this->FileIsEmpty = true;
ifs.close();
return;
}
//判断文件是否为空
char c;
ifs >> c;
if (ifs.eof())
{
cout << "文件为空" << endl;
this->FileIsEmpty = true;
ifs.close();
return;
}
//文件存在且不为空
this->FileIsEmpty = false;
ifs.putback(c); //将上面读取的单个字符,放回来
string data;
int tindex = 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);
start = pos + 1;
v.push_back(temp);
}
this->m_record.insert(make_pair(tindex, v)); //将每一届的获奖选手信息存入map容器中
tindex++;
}
ifs.close();
}
//显示往届记录的信息
void SpeachManger::showrecord()
{
if (this->FileIsEmpty)
{
cout << "文件为空或不存在" << endl;
}
else
{
for (int i = 0; i <this-> m_record.size(); i++)
{
cout << "第" << i + 1 << "届获奖记录" << endl;
cout << "冠军编号:" << 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;
}
}
system("pause");
system("cls");
}
//清空记录
void SpeachManger::clearrecord()
{
cout << "确认清空?" << endl;
cout << "1、确认" << endl;
cout << "2、返回" << endl;
int choice = 0;
cout << "请输入你的选择:" << endl;
cin >> choice;
if (choice == 1)
{
ofstream ofs("speech.csv", ios::trunc); //删除该文件,然后再次创建该文件
this->initspeach();
this->createspeaker();
this->loadrecord(); //加载往届为空的数据
cout << "所有记录已经清空" << endl;
}
system("pause");
system("cls");
}
//退出程序
void SpeachManger::exitSystem()
{
cout << "欢迎下次使用" << endl;
system("pause");
exit(0);
}
SpeachManger::~SpeachManger()
{
}
<4>用户的交互界面<演讲比赛管理系统.cpp>
#include<iostream>
#include<map>
#include"speachManger.h"
#include<ctime>
using namespace std;
int main()
{
srand((unsigned int)time(NULL)); //产生随机数种子,用于控制每次抽签的随机性
SpeachManger sm;
int choice = 0; //用于用户的选择
while (true)
{
sm.showmenu();
cout << "请输入选项:" << endl;
cin >> choice;
switch (choice)
{
case 1: //开始比赛
sm.startspeech();
break;
case 2: //展示往届的记录
sm.showrecord();
break;
case 3: //清空比赛记录
sm.clearrecord();
break;
case 0: //退出比赛程序
sm.exitSystem();
break;
default:
system("cls");
break;
}
}
system("pause");
return 0;
}