贪吃蛇是一款儿时爱不释手的游戏。近日修行,想玩玩游戏开发。便简单写了个控制台版的贪吃蛇。

 

    程序的简单框架:

    建立一张固定大小的MAP,保存输出信息。

    当信息有变动时,用system("cls")进行清屏操作,再重新输出实现伪动态。

    重点算法在蛇身的移动,转向与增长。三者均基于链表实现。

    移动与转向:通过判定移动方向,确定下一步移动的位置后,新建表头结点。将新表头结点置为表头。删除末尾结点。

    增长:通过判断尾部移动方向,确定位置后在尾部添加节点。

    熟练运用链表的同学,相信也是小菜一碟了。

    演示代码如下。

  1 /*
  2 *   windy 2016 7.9
  3 *   Snake FirstStep
  4 *   A program of the GreadySnake
  5 */
  6 #include <iostream>
  7 #include <conio.h>   //包含_kbhit()函数的头文件,_kbhit()运用可GOOGLE
  8 #include <string.h>
  9 #include <time.h>
 10 #include <windows.h>
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #define ROW 25  // height of MAP
 14 #define COL 75   // weight of MAP
 15 
 16 using namespace std;
 17 
 18 //蛇身结点结构体
 19 typedef struct Node {
 20     int row;
 21     int col;
 22     Node* next;
 23 
 24     Node() {};
 25     Node(int _r, int _c) {
 26         row = _r;
 27         col = _c;
 28     }
 29 }SnakeNode;
 30 
 31 //果实结构体
 32 typedef struct {
 33     int row;
 34     int col;
 35     bool isEaten = true;  //果实生成后,isEaten置为false,被吃后,重新置为true
 36 }Fruit;
 37 
 38 //draw the map outline
 39 void drawMap();
 40 
 41 //create the fruit randomly
 42 void createFruit();
 43 
 44 //create the snake body
 45 void createSnake();
 46 
 47 //add snake body node
 48 void addNode(SnakeNode* head);
 49 
 50 //let the snake move
 51 void snakeMove();
 52 
 53 //print the snake
 54 void snakePrint();
 55 
 56 //check if snake eat the fruit, if snake pump the boundary
 57 void check();
 58 
 59 //snake turn
 60 void snakeTurn();
 61 
 62 //erase the tail
 63 void tailErase(SnakeNode* newHead);
 64 
 65 //snake body extend
 66 void snakeExtend();
 67 
 68 //set global value
 69 Fruit fruit;
 70 //建立一张全是空格的地图
 71 char MAP[ROW][COL];
 72 //创建蛇头
 73 SnakeNode* head = new SnakeNode(10, 20);
 74 //记录分数
 75 int cnt = 0;
 76 //移动速度
 77 int TIME = 60;   
 78 
 79 int main()
 80 {
 81     system("color 0C");   //设置背景色
 82     system("title 贪吃蛇小游戏~");  //设置窗口名字
 83     system("mode con cols=80 lines=30");  //设置窗口大小
 84     memset(MAP, ' ', sizeof(MAP));
 85     createSnake();      //生成蛇
 86     drawMap();     //主要函数,详见下面代码
 87     return 0;
 88 }
 89 
 90 void drawMap()
 91 {
 92     while (true) {
 93         //绘制地图外框
 94         for (int row = 0; row != ROW; row++) {
 95             for (int col = 0; col != COL; col++) {
 96                 if (row == 0 || row == ROW - 1)
 97                     MAP[row][col] = '-';
 98                 else if (col == 0 || col == COL - 1)
 99                     MAP[row][col] = '*';
100             }
101         }
102 
103         if (!_kbhit())
104             snakeMove(); //无键盘输入信号,继续向前移动
105         else snakeTurn();    //有键盘输入信号,进行转向判定
106         check();          //检查移动后是否吃到果实,是否越界,是否自撞
107         if (fruit.isEaten) {
108             createFruit();
109             fruit.isEaten = false;
110         }
111         //打印地图
112         for (int row = 0; row != ROW; row++) {
113             for (int col = 0; col != COL; col++) {
114                 printf("%c", MAP[row][col]);
115             }
116             printf("\n"); //换行
117         }
118 
119         Sleep(TIME);
120         system("cls");
121     }
122 }
123 
124 void createFruit()
125 {
126     srand((unsigned)time(NULL));
127     int row = rand() % (ROW - 1) + 1;
128     int col = rand() % (COL - 1) + 1;
129 
130     //检查果实是否在蛇身生成
131     SnakeNode* cur = head;
132     while (cur) {
133         if (cur->row == row && cur->col == col) {
134             row = rand() % (ROW - 1) + 1;   //若是,重新生成果实
135             col = rand() % (COL - 1) + 1;
136             cur = head;
137             continue;
138         }
139         cur = cur->next;
140     }
141 
142     fruit.row = row;
143     fruit.col = col;
144     MAP[row][col] = '$';
145 }
146 
147 void createSnake()
148 {
149     head->next = NULL;
150 
151     //生成蛇身
152     const int N = 5;
153     for (int i = 0; i != N; i++) {
154         addNode(head);
155     }
156 
157     //在MAP绘制蛇身
158     snakePrint();
159 }
160 
161 void addNode(SnakeNode* head)
162 {
163     SnakeNode* curBody = head;
164     
165     while (curBody->next) {
166         curBody = curBody->next;
167     }
168 
169     SnakeNode* malc = new SnakeNode(curBody->row, curBody->col - 1);
170     malc->next = NULL;
171 
172     curBody->next = malc;
173 }
174 
175 void snakeMove()
176 {
177     SnakeNode* newHead = new SnakeNode();
178     //前进状态
179     if (head->row == head->next->row) {
180         if (head->col > head->next->col)  newHead->col = head->col + 1; //若向右行
181         else newHead->col = head->col - 1;   //若向左行
182         newHead->row = head->row;
183         newHead->next = head;
184     }
185     else if (head->col == head->next->col) {
186         if (head->row > head->next->row)  newHead->row = head->row + 1; //若向下行
187         else newHead->row = head->row - 1; //若向上行
188         newHead->col = head->col;
189         newHead->next = head;
190     }
191     //蛇移动后,将蛇尾结点删除
192     tailErase(newHead);
193     head = newHead;
194     snakePrint();
195 }
196 
197 void snakePrint()
198 {
199     MAP[head->row][head->col] = '@';
200     SnakeNode* cur = head->next;
201     while (cur) {
202         MAP[cur->row][cur->col] = '#';
203         cur = cur->next;
204     }
205 }
206 
207 void check()
208 {
209     if (fruit.row == head->row && fruit.col == head->col) {
210         fruit.isEaten = true;
211         cnt += 10;
212         TIME -= 5;
213         //snake extend while eating the fruit
214         snakeExtend();
215     }
216     if (head->row == ROW-1 || head->row == 0 || head->col == COL-1 || head->col == 0) {
217         printf("                   撞到墙啦!游戏结束 -_- \n\n\n\n 本次得分%d!\n\n\n\n",cnt);
218         if ( cnt <= 40 ) printf("                              为何如此彩笔!\n");
219         if (cnt > 40 && cnt < 80) printf("                       你离极限玩家不远了!\n");
220         if (cnt >= 80) printf("                          你已经超神了!\n");
221         system("pause");
222         exit(1);
223     }
224 
225     SnakeNode* cur = head->next;
226     while (cur->next) {
227         if (head->row == cur->row && head->col == cur->col) {
228             printf(" 撞到自己啦!游戏结束 -_- \n\n\n\n 本次得分%d!\n\n\n\n", cnt);
229             if (cnt <= 40) printf("                              为何如此彩笔!\n");
230             if (cnt > 40 && cnt < 80) printf("                       你离极限玩家不远了!\n");
231             if (cnt >= 80) printf("                          你已经超神了!\n");
232             system("pause");
233             exit(1);
234         }
235         cur = cur->next;
236     }
237 }
238 
239 void snakeTurn()
240 {
241     char key;
242     if (_kbhit()) { //kbhit函数在有键盘输入是,返回0.. 检测是否有键盘输入
243         while (_kbhit())  //存在多次输入时,以最后一次输入为主
244             key = _getch();
245         SnakeNode* newHead = new SnakeNode();
246         switch (key) {  //判断转向
247         case 'w': { //上转
248             if (head->row <= head->next->row) {
249                 newHead->row = head->row - 1;
250                 newHead->col = head->col;
251                 newHead->next = head;
252                 tailErase(newHead);
253                 head = newHead;
254             }
255         }break;
256         case 's': {//下转
257             if (head->row >= head->next->row) {
258                 newHead->row = head->row + 1;
259                 newHead->col = head->col;
260                 newHead->next = head;
261                 tailErase(newHead);
262                 head = newHead;
263             }
264         }break;
265         case 'a': {//左转
266             if (head->col <= head->next->col) {
267                 newHead->row = head->row;
268                 newHead->col = head->col - 1;
269                 newHead->next = head;
270                 tailErase(newHead);
271                 head = newHead;
272             }
273         }break;
274         case 'd': {//右转
275             if (head->col >= head->next->col) {
276                 newHead->row = head->row;
277                 newHead->col = head->col + 1;
278                 newHead->next = head;
279                 tailErase(newHead);
280                 head = newHead;
281             }
282         }break;
283         default: {
284             snakeMove();
285         }break;
286         }
287         snakePrint();
288     }
289 }
290 
291 void tailErase(SnakeNode* newHead)
292 {
293     //删除尾部节点
294     SnakeNode* cur = newHead;
295     while (cur->next->next) {
296         cur = cur->next;
297     }
298     //将尾部结点置空
299     MAP[cur->next->row][cur->next->col] = ' ';
300     free(cur->next);
301     cur->next = NULL;
302 }
303 
304 void snakeExtend()
305 {
306     SnakeNode* cur = head;
307 
308     while (cur->next->next) {
309         cur = cur->next;
310     }
311 
312     SnakeNode* newTail = new SnakeNode();
313     if (cur->row == cur->next->row) //尾部横向
314         if (cur->col > cur->next->col) { //尾巴在左
315             newTail->row = cur->next->row;
316             newTail->col = cur->next->col - 1;
317         }
318         else {
319             newTail->row = cur->next->row;
320             newTail->col = cur->next->col + 1; //尾巴在右
321         }
322     else  /*if( cur->col == cur->next->col )*/ //尾部竖向
323         if (cur->row > cur->next->row) {//尾巴在上
324             newTail->row = cur->next->row - 1;
325             newTail->col = cur->next->col;
326         }
327         else {
328             newTail->row = cur->next->row + 1;//尾巴在下
329             newTail->col = cur->next->col;
330         }
331 
332         newTail->next = NULL;
333         cur->next->next = newTail;
334         snakePrint();
335 }

 

      简单简单的控制台贪吃蛇就完成啦~

 

posted on 2016-07-09 23:22  Elapsed_Time  阅读(354)  评论(0编辑  收藏  举报