在学习c++提高-STL总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
05-c++STLday13_贪吃蛇案例
目录:一、上节作业——综合案例(学校演讲比赛)二、贪食蛇案例
一、上节作业——综合案例(学校演讲比赛)
》比赛规则:某市举行一场演讲比赛( speech_contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。
》比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;
>第一轮分为4个小组,每组6个人。比如编号为: 100-123. 整体进行抽签(draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
>第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
>第三轮只剩下1组6个人,本轮为决赛,选出前三名。
》比赛评分:10个评委打分,去除最低、最高分,求平均分每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。用STL编程,求解这个问题1)请打印出所有选手的名字与参赛号,并以参赛号的升序排列。2)打印每一轮比赛后,小组比赛成绩和小组晋级名单
需求分析:
1) 产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWX ) 姓名、得分;选手编号
2) 第1轮 选手抽签 选手比赛 查看比赛结果
3) 第2轮 选手抽签 选手比赛 查看比赛结果
4) 第3轮 选手抽签 选手比赛 查看比赛结果实现思路:
需要把选手信息、选手得分信息、选手比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。
选手可以设计一个类Speaker(姓名和得分)
所有选手的编号可以单独放在一个vector容器中,做抽签用
所有选手编号和选手信息,可以放在容器内:map<int, Speaker>
所有选手的编号名单,可以放在容器:vecter<int> v1中
第1轮晋级编号名单,可以放在容器vecter<int> v2中
第2轮晋级编号名单,可以放在容器vecter<int> v3中
第3轮前三名名单,可以放在容器vecter<int> v4中
每个小组的比赛得分信息,按照从大到小的顺序放在multimap<成绩, 编号, greater<int>>中
每个选手的得分,可以放在容器deque<int> dscore; 方便去除最低最高分.
代码如下:
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include<vector>
5 #include<map>
6 #include<string>
7 #include<algorithm>
8 #include<deque>
9 #include<numric>
10 #include<functional>
11 #inlcude<ctime>
12
13 /*
14 需求分析:
15 1) 产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWX ) 姓名、得分;选手编号
16
17 2) 第1轮 选手抽签 选手比赛 查看比赛结果
18 3) 第2轮 选手抽签 选手比赛 查看比赛结果
19 4) 第3轮 选手抽签 选手比赛 查看比赛结果
20
21 */
22 class Speaker
23 {
24 public:
25
26 string m_Name;//姓名
27 int m_Score[3];//得分数组
28 };
29
30 void createSpeaker(vector<int>& v, map<int, Speaker>& m)
31 {
32 string nameSeed = "ABCDEFGHIJKLMNOPQRSTUVWX";
33 for(int i = 0; i < nameSeed.size(); i++)
34 {
35 string name = "选手";
36 name += nameSeed[i];
37
38 Speaker sp;
39 sp.m_Name = name;
40 for(int j = 0; j < 3; j++)
41 {
42 sp.m_Score[j] = 0;
43 }
44
45 v.push_back(i + 100);//编号100~123
46 m.insert(make_pair(i + 100, sp));
47 }
48
49 }
50
51 //抽签
52 void speechDraw(vector<int>v)
53 {
54 //洗牌
55 random_shuffle(v.begin(), v.end());
56 }
57
58 //index存放第几轮,v1存放比赛选手编号,m是选手编号和具体选手,v2存放晋级选手编号容器
59 void speechContest(int index,vector<int>& v1, map<int, Speaker>& m, vector<int>& v2)
60 {
61 //临时容器:key 分数,value 编号
62 multimap<int, int, greater<int>>groupMap;
63 int num = 0;
64 for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
65 {
66 num++;
67 deque<int>d;
68 for(int i = 0; i < 10; i++)
69 {
70 int score = rand() % 41 + 60;//60~100
71 d.push_back(score);
72 }
73 //排序
74 sort(d.begin(), d.end());
75 //去除最高最低分
76 d.pop_back();
77 d.pop_front();
78 //累积分数
79 int sum = accumulate(d.begin(), d.end(), 0);
80 int avg = sum / d.size();
81
82 //将平均分放入到m容器中
83 m[*it].m_Score[index - 1] = avg;
84
85 //每6个人,取前三名晋级
86 //临时容器,保存6个人
87 //临时容器,存入数据
88 groupMap.insert(make_pair(avg, *it));
89
90 if(num % 6 == 0)
91 {
92 /*
93 cout << "各个小组比赛成绩如下:" << endl;
94 for(multimap<int, int, greater>:: iterator mit = groupMap.begin(); mit != groupMap.end(); mit++)
95 {
96 cout << "选手编号:" << mit->second << " 姓名:" << m[mit->second].m_Name << " 得分:" << m[mit->second].m_Score[index-1] << endl;
97 }
98 */
99
100 //取前三名
101 int count = 0;
102 for(multimap<int, int, greater>:: iterator mit = groupMap.begin(); mit != groupMap.end(), count < 3; mit++, count++)
103 {
104 //晋级容器,获取数据
105 v2.push_back(mit->second);
106 }
107
108 groupMap.clear();//清空临时容器
109 }
110 }
111
112
113
114 }
115
116
117 void showScore(int index, vector<int>& v, map<int, Speaker>& m)
118 {
119 cout << "第" << index << "轮,比赛成绩如下:" << endl;
120
121 for(map<int, Speaker>::iterator it = m.begin(); it != m.end(); it++)
122 {
123 cout << "选手编号:" << it->first << "姓名:" << it->second.m_Name << "分数:" << it->second.m_Score[index-1] << endl;
124 }
125
126 cout << "晋级选手编号" << endl;
127 for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
128 {
129 cout << *it << endl;
130 }
131
132 }
133
134
135
136 void test01()
137 {
138 //最后添加随机数种子
139 srand((unsigned int)time(NULL));
140
141 vector<int>v1;//选手编号
142
143 map<int, Speaker>m;//存放选手编号和对应的具体的选手
144
145 //创建选手
146 createSpeaker(v1, m);
147
148 /*
149 //测试
150 for(map<int, Speaker>::iterator it = m.begin(); it!= m.end(); it++)
151 {
152 cout << "选手编号:" << it->first << "姓名:" << it->second.m_Name << endl;
153 }
154 */
155
156 //抽签
157 speechDraw(v1);
158
159 vector<int>v2;//进入下一轮比赛的人员编号
160
161 //第一轮比赛
162 speechContest(1, v1, m, v2);
163
164 //显示比赛结果
165 showScore(1, v2, m);//轮数 晋级编号 具体人员信息
166
167 //第二轮比赛
168 speechDraw(v2);
169 vector<int>v3;//进入下一轮比赛的人员编号
170 speechContest(2, v2, m, v3);
171 showScore(2, v3, m);
172
173 //第三轮比赛
174 speechDraw(v3);
175 vector<int>v4;//进入下一轮比赛的人员编号
176 speechContest(3, v3, m, v4);
177 showScore(3, v4, m);
178
179 }
180
181 int main()
182 {
183 test01();
184
185 system("pause");
186 return EXIT_SUCCESS;
187 }
二、贪食蛇案例
总结:
1、玩法介绍
2、具体实现
3、墙模块
3.1 二维数组维护,游戏内容
3.2 初始化二维数组:initwall
3.3 画出墙壁 drawwall
3.4 提供对外接口setwall、getwall
3.5测试
4、蛇模块
4.1 初始化蛇
4.2 销毁所有结点
4.3 添加新结点
5、食物模块
5.1 foodX、foodY位置
5.2 setFood对外接口,可以设置食物
5.3 随机出两个可以放置的位置,设置#
6、删除结点和移动蛇的封装
6.1 删除结点,通过两个临时结点,删除尾结点
6.2 移动,判断用户输入内容,然后进行移动操作
7、接收用户输入
7.1 接收一个字符,让蛇移动第一步
7.2 用户输入按键后,进行自动移动
8、解决bug
8.1 按键冲突
8.2 180度不可以转
8.3 死亡撞墙,多走一步
8.4 循环追尾,不要进入死亡判断
9、辅助玩法
9.1 难度设定,根据蛇身段,产生不同难度
9.2 分数设定
10、优化游戏
代码如下:
game.cpp
1 #define _CRT_SECURE_NO_WARNINGS
2 #include<iostream>
3 using namespace std;
4 #include"wall.h"
5 #include"snake.h"
6 #include"food.h"
7 #include<ctime>
8 #include<conio.h>
9 #include<window.h>
10
11 void gotoxy(HANDLE hOut, int x, int y)
12 {
13 COORD pos;
14 pos.X = x; //横坐标
15 pos.Y = y; //纵坐标
16 SetConsoleCursorPosition(hOut, pos);
17 }
18 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量
19
20
21
22 void test01()
23 {
24 //添加随机种子
25 srand((unsigned int)time(NULL));
26
27 //是否死亡的标识
28 bool isDead = false;
29
30 //上一步的标识
31 char preKey = NULL;
32
33 Wall wall;
34 wall.initWall();
35 wall.drawWall();
36
37 /*
38 //测试
39 wall.setWall(5, 4, '=');
40 wall.setWall(5, 5, '=');
41 wall.setWall(5, 6, '@');
42
43 wall.drawWall();
44
45 cout << wall.getWall(0, 0) << endl;
46 cout << wall.getWall(5, 4) << endl;
47 cout << wall.getWall(5, 6) << endl;
48 cout << wall.getWall(1, 1) << endl;
49 */
50 Food food(wall);
51 food.setFood();
52
53 Snake snake(wall, food);
54 snake.initSnake();
55
56 /*
57 //测试
58 snake.move('w');
59 snake.move('w');
60 snake.move('a');
61 */
62 //snake.delPoint();//测试删结点
63
64 //wall.drawWall();
65 gotoxy(hOut, 0, Wall::ROW);
66
67 cout << "得分:" << snake.getScore() << "分" << endl;
68
69 //gotoxy(hOut, 10, 5);//坐标系相反;y*2,x
70
71 //接收用户的输入
72 while(!isDead)
73 {
74 char key = _getch();
75
76 //判断,如果是第一次按了左键,才不能激活游戏
77 //判断上一次移动方向
78 if(preKey == NULL && key == snake.LEFT)
79 {
80 continue;
81 }
82
83 do
84 {
85 if(key == snake.UP || key == snake.DOWN || key == snake.LEFT || key == snake.RIGHT)
86 {
87 //判断本次按键是否与上次冲突
88 if((key == snake.LEFT && preKey == snake.RIGHT)||(key == snake.RIGHT && preKey == snake.LEFT)||(key == snake.UP && preKey == snake.DOWN)||(key == snake.DOWN && preKey == snake.UP))
89 {
90 key = preKey;
91 }
92 else
93 {
94 preKey = key; //不是冲突按键,可以更新按键
95 }
96
97 if(snake.move(key) == true)
98 {
99 //移动成功 代码
100 //system("cls");
101 //wall.drawWall();
102 gotoxy(hOut, 0, Wall::ROW);
103
104 cout << "得分:" << snake.getScore() << "分" << endl;
105 Sleep(snake.getSleepTime());
106 }
107 else
108 {
109 isDead = true;
110 break;
111 }
112 }
113 else
114 {
115 key = preKey;//强制将错误按键变为上一次移动的方向
116 }
117
118 }while(!_kbhit());//当没有键盘输入的时候,返回0
119
120
121 }
122
123
124 }
125
126 int main()
127 {
128 test01();
129
130 system("pause");
131 return EXIT_SUCCESS;
132 }
wall.cpp
1 #include"wall.h"
2
3
4 void Wall::initWall()
5 {
6 for(int i = 0; i < ROW; i++)
7 {
8 for(int j = 0; j < COL; j++)
9 {
10 //放墙壁
11 if(i == 0 || j == 0 || i == ROW - 1 || j == COL -1)
12 {
13 gameArray[i][j] = '*';
14 }
15 else
16 {
17 gameArray[i][j] = ' ';
18 }
19 }
20
21 }
22 }
23
24
25 void Wall::drawWall()
26 {
27 for(int i = 0; i < ROW; i++)
28 {
29 for(int j = 0; j < COL; j++)
30 {
31 cout << gameArray[i][j] << " ";
32 }
33 if(i == 5)
34 {
35 cout << "create by wp";
36 }
37 if(i == 6)
38 {
39 cout << "a:left";
40 }
41 if(i == 7)
42 {
43 cout << "d:right";
44 }
45 if(i == 8)
46 {
47 cout << "w:up";
48 }
49 if(i == 9)
50 {
51 cout << "s:down";
52 }
53
54
55 cout << endl;
56 }
57 }
58
59
60 void Wall::setWall(int x, int y, char c)
61 {
62 gameArray[x][y] = c;
63 }
64
65 char Wall::getWall(int x, int y)
66 {
67 return gameArray[x][y];
68 }
wall.h
1 #ifndef _WALL_HEAD
2 #define _WALL_HEAD
3 #include<iostream>
4 using namespace std;
5
6 class Wall
7 {
8 public:
9 enum{ROW = 26, COL = 26};
10
11 //初始化墙壁
12 void initWall();
13
14 //画出墙壁
15 void drawWall();
16
17 //根据索引设置二维数组里的内容
18 void setWall(int x, int y, char c);
19
20 //根据索引获取当前位置的符号
21 char getWall(int x, int y);
22
23 private:
24 char gameArray[ROW][COL];
25
26 };
27
28
29
30
31
32
33 #endif
snake.cpp
1 #include"snake.h"
2 #include<window.h>
3
4 void gotoxy1(HANDLE hOut1, int x, int y)
5 {
6 COORD pos;
7 pos.X = x; //横坐标
8 pos.Y = y; //纵坐标
9 SetConsoleCursorPosition(hOut1, pos);
10 }
11 HANDLE hOut1 = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量
12
13 Snake::Snake(Wall& tempWall, Food& tmpFood):wall(tempWall),food(tmpFood)
14 {
15 pHead = NULL;
16 isRool = false;
17 }
18
19 void Snake::initSnake()
20 {
21 destroyPoint();
22 addPoint(5, 3);
23 addPoint(5, 4);
24 addPoint(5, 5);
25 }
26
27 void Snake::destroyPoint()
28 {
29 Point* pCur = pHead;
30
31 while(pHead != NULL)
32 {
33 pCur = pHead->next;
34 delete pHead;
35
36 pHead = pCur;
37 }
38
39 }
40
41 void Snake::addPoint(int x, int y)
42 {
43 //创建新结点
44 Point* newPoint = new Point;
45 newPoint->x = x;
46 newPoint->y = y;
47 newPoint->next = NULL;
48
49 //如果原来头不为空,改为身子
50 if(pHead != NULL)
51 {
52 wall.setWall(pHead->x, pHead->y, '=');
53
54 gotoxy1(hOut1, pHead->y * 2, pHead->x);
55 cout << "=";
56 }
57
58 newPoint->next = pHead;
59
60 pHead = newPoint;//更新头部
61
62 wall.setWall(pHead->x, pHead->y, '@');
63
64 gotoxy1(hOut1, pHead->y * 2, pHead->x);
65 cout << "@";
66 }
67
68 void Snake::delPoint()
69 {
70 //两个结点以上,才去做删除操作
71 if(pHead == NULL || pHead->next == NULL)
72 {
73 return;
74 }
75
76 Point* pCur = pHead->next;
77 Point* pPre = pHead;
78
79 while(pCur->next != NULL)
80 {
81 pPre = pPre->next;
82 pCur = pCur->next;
83 }
84 //删除尾结点
85
86 wall.setWall(pCur->x, pCur->y, ' ');
87 gotoxy1(hOut1, pCur->y * 2, pCur->x);
88 cout << " ";
89
90 delete pCur;
91 pCur = NULL;
92 pPre->next = NULL;
93 }
94
95 bool Snake::move(char key)
96 {
97 int x = pHead->x;
98 int y = pHead->y;
99
100 switch(key)
101 {
102 case UP:
103 x--;
104 break;
105 case DOWN:
106 x++;
107 break;
108 case LEFT:
109 y--;
110 break;
111 case RIGHT:
112 y++;
113 break;
114 default:
115 break;
116 }
117
118 //判断:如果是下一步碰到的尾巴,不应该死亡
119 Point* pCur = pHead->next;
120 Point* pPre = pHead;
121
122 while(pCur->next != NULL)
123 {
124 pPre = pPre->next;
125 pCur = pCur->next;
126 }
127 if(pCur->x == x && pCur->y == y)
128 {
129 //碰到尾巴,成为循环
130 isRool = true;
131 }
132 else
133 {
134 //判断用户到达位置是否成功
135 if(wall.getWall(x, y) == '*' || wall.getWall(x, y) = '=')
136 {
137 addPoint(x,y);//如果是*的话,再多走一步,但是吃掉自己也会出问题,可以更改上面的if分开进行判断
138 delPoint();
139 system("cls");
140 wall.drawWall();
141
142 cout << "得分:" << getScore() << "分" << endl;
143 cout << "GAME OVER!!!" << endl;
144 return false;
145 }
146 }
147
148
149 //移动成功分两种
150 //吃到食物 未吃到食物
151 if(wall.getWall(x, y) == '#')
152 {
153 addPoint(x, y);
154
155 //重新设置食物
156 food.setFood();
157 }
158 else
159 {
160 addPoint(x, y);
161 delPoint();
162 if(isRool == true)
163 {
164 wall.setWall(x, y, '@');
165 gotoxy1(hOut1, y * 2, x);
166 cout << "@";
167 }
168 }
169 return true;
170 }
171
172 int Snake::getSleepTime()
173 {
174 int sleepTime = 0;
175 int size = countList();
176 if(size < 5)
177 {
178 sleepTime = 300;
179 }
180 else if(size >= 5 && size <= 8)
181 {
182 sleepTime = 200;
183 }
184 else
185 {
186 sleepTime = 100;
187 }
188 return sleepTime;
189 }
190 int Snake::countList()
191 {
192 int size = 0;
193 Point* curPoint = pHead;
194 while(curPoint != NULL)
195 {
196 size++;
197 curPoint = curPoint->next;
198 }
199 return size;
200 }
201
202 int Snake::getScore()
203 {
204 int size = countList();
205
206 int score = (size - 3) * 100;
207
208 return score;
209 }
snake.h
1 #pragma once
2 #include<iostream>
3 using namespace std;
4 #include"wall.h"
5 #include"food.h"
6
7 class Snake
8 {
9 public:
10
11 Snake(Wall& tempWall, Food& food);
12
13 enum{ UP = 'w', DOWN = 's', LEFT = 'a', RIGHT = 'd'};
14
15
16 //结点
17 struct Point
18 {
19 //数据域
20 int x;
21 int y;
22
23 //指针域
24 Point* next;
25 };
26
27 //初始化
28 void initSnake();
29
30 //销毁所有结点
31 void destroyPoint();
32
33 //添加结点
34 void addPoint(int x, int y);
35
36 //删除结点
37 void delPoint();
38
39 //移动蛇操作
40 //返回值代表移动是否成功
41 bool move(char key);
42
43 //设定难度
44 //设定刷屏时间
45 int getSleepTime();
46 //获取蛇身段
47 int countList();
48
49 //获取分数
50 int getScore();
51
52 Point* pHead;
53
54 Wall& wall;
55
56 Food& food;
57
58 bool isRool;//判断碰到尾巴的标识
59 };
food.cpp
1 #pragma once
2 #include<iostream>
3 using namespace std;
4 #include"wall.h"
5
6 class Food
7 {
8 public:
9 Food(Wall& tempWall);
10
11 //设置食物
12 void setFood();
13
14 int foodX;
15 int foodY;
16
17 Wall& wall;
18 };
food.h
1 #include"food.h"
2 #include<window.h>
3
4 void gotoxy2(HANDLE hOut2, int x, int y)
5 {
6 COORD pos;
7 pos.X = x; //横坐标
8 pos.Y = y; //纵坐标
9 SetConsoleCursorPosition(hOut2, pos);
10 }
11 HANDLE hOut2 = GetStdHandle(STD_OUTPUT_HANDLE);//定义显示器句柄变量
12
13 Food::Food(Wall& tempWall):wall(tempWall)
14 {
15
16 }
17
18 void Food::setFood()
19 {
20
21 while(true)
22 {
23 foodX = rand() % (Wall::ROW - 2) + 1;
24 foodY = rand() % (Wall::COL - 2) + 1;
25
26 //如果随机的位置是蛇头或蛇身,就重新生成随机数
27 if(wall.getWall(foodX, foodY) == ' ')
28 {
29 wall.setWall(foodX, foodY, '#');
30 gotoxy2(hOut2, foodY * 2, foodX);
31 cout << "#";
32 break;
33 }
34 }
35 }
在学习c++提高-STL总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。