贪吃蛇小游戏 (一)

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

程序的简单框架:

建立一张固定大小的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 }

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

时间: 2024-10-02 13:50:06

贪吃蛇小游戏 (一)的相关文章

一个简单的“贪吃蛇”小游戏

一个简单的“贪吃蛇”小游戏 页面结构 简单的21x21的方块,页面结构 id为container的div包含所21个class名为row的div,每个row代表贪吃蛇的一整行,每个row中又包含21个div,代表这一行的每一个div方格,如果这个方格是空的话,div的类名为blank,如果这一个方格表示“贪吃蛇”的“食物”,div的类名为food,如果这一个方格表示“蛇”,div的类名为snake. CSS JS 然后我们思考下一个贪吃蛇游戏需要那些参数, 首先,界面中可见的元素无非就是空方格,

贪吃蛇小游戏的初步尝试制作

这里利用二维数组做为地图,利用集合来存放蛇头和蛇尾的位置坐标,初步实现一个需要键盘控制的贪吃蛇小游戏. 首先,Main函数下面需要一个大循环来让游戏失败的时候能够重新开始,这里我们用了定义了一个bool型的sc,判断sc的true和flase来确定游戏是否开始: static void Main(string[] args)        { bool sc = true; while (sc) //大循环,用于游戏失败重新开始            { 下面是定义一个集合snake_x来存放蛇

使用Html5+JS做的贪吃蛇小游戏

学习了Html5的Canvas的使用,和JS创建对象,做了一个贪吃蛇小游戏,来巩固JS面向对象编程和Canvas的用法. Node.js 1 /** 2 * 格子类,组成贪吃蛇和舞台 3 */ 4 function Node(x,y){ 5 this.x=x; 6 this.y=y; 7 /** 8 * 比较两个格子是否重合 9 */ 10 this.equals=function(x,y){ 11 return this.x==x&&this.y==y; 12 } 13 } Snake.

Java版贪吃蛇小游戏的实现

使用的IDE eclipse JDK版本 1.6 辅助类 Coordinate.java package com.nn.util; /** *坐标点 */ public class Coordinate { public int x; public int y; public Coordinate(int newX, int newY) { x = newX; y = newY; } public boolean equals(Coordinate other) { if (x == other

贪吃蛇小游戏java实现代码分析

贪吃蛇小游戏java实现代码分析 贪吃蛇的小游戏,网上的代码比较多,今天周五,在教研室没啥事做,在电脑中发现了一个贪吃蛇的小游戏,于是就看了下实现的源码,发现别人写的代码确实挺好的,自己也是边加注释边进行理解的去看别人实现的游戏源码,发现还是挺有意思的.自己花了一个下午的时间看了源码,也加了一点小小的功能,于是,不写篇博客觉得对不起自己也,哈哈哈. 此游戏代码的思路非常的清晰,也相当好理解,没有太多难的地方,不过有很多值得学习的地方,因为,这份源码中,对java.awt包中的很多类的很多方法都进

用C写一个功能较为完善的贪吃蛇小游戏

主要功能: 方向控制-食物与增长-变速 1 #include<stdio.h> 2 #include<time.h>//种子-随机数 3 #include<windows.h>//system函数,控制台句柄 4 #include<conio.h>//按键 5 //界面(欢迎界面-游戏界面-结束得分界面)-驱动-方向控制-食物 6 //位置锁定-打印-删除 7 int snake_x[520]={0}; 8 int snake_y[520]={0}; 9 i

js+jQuery实现贪吃蛇小游戏

这是我第一次这么认真的去写一个程序.今天老师布置的编程任务是实现一个贪吃蛇的小游戏,一开始感觉很茫然的,因为以前都没有这么系统的去做过一个编程任务.后来理清思路去做,感觉问题也并不是那么的难. 首先,第一步肯定是要编写出我们的的静态页面. 第二步,让我们的贪吃蛇先从一个开始动起来. 第三步,让我们通过键盘去控制他的运动方向. 第四步,让我们去判断我们的贪吃蛇有没有撞墙,有没有吃到自己,因为这已经犯规了. 第五步,给我们的贪吃蛇随机生成一个‘食物’. 第六步,实现每当我们的贪吃蛇吃了一个食物,他都

html5面向对象做一个贪吃蛇小游戏

canvas加面向对象方式的贪吃蛇 2016-08-25 这个小游戏可以增加对面向对象的理解,可以加强js逻辑能力,总之认真自己敲一两遍收获还是不少啊!!适合刚学canvas的同学练习!! 废话不多说,直接来讲思路和代码. ----------------------------------------------------------------------------------------------------------------- 开发思路:首先要有蛇吃的食物,就是一个个canv

使用前端原生 js,贪吃蛇小游戏

好久好久,真的是好久好久没来写过了,因为最近有点小忙.不过即使是忙,也也还是写了两个小游戏,其中一个就是这个,贪吃蛇啦. 算是一个小练手了,这个是在有点太简单了,只是第一次写这种小游戏,还是零零星星花了三五天时间,下面就是这个小游戏的gif小动画,比较简单,对比过网上其他用来写出来练手的贪吃蛇作品,这个在颜值还是功能上,都还是不错的,霍霍. 这里讲解一下功能: 空格控制开始和暂停. 方向键控制移动方向. Q 键加速,再按一次恢复常规速度(在加速状态时,按下或者方向键,或者吃到了白色小食物,速度自