在學習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 }