在学习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,转载请注明出处。