字符游戏——智能蛇
来源:互联网 发布:英雄联盟官方代练 知乎 编辑:程序博客网 时间:2024/06/06 09:20
经过了漫长的一学期地学习,一直以来的C语言作业都给我们留下了C似乎只能做数学题这样的一种重要却无趣的功能,这不禁让人有些厌烦。然而,这两周的软件工程导论作业却令我们耳目一新,作业的要求是让我们用C语言完成一个简单的贪吃蛇游戏,并且在此基础上让其“智能”化,即能够自己寻找食物。在我的程序编写过程中,出现了很多令人啼笑皆非的bug,在令人捧腹大笑地同时,也增加了对C语言地兴趣。好了,话不多说,接下来我要介绍一下我的“智能”蛇成长过程。
首先,先贴代码为敬:
#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<math.h>#define WALL_CELL *#define SNAKE_HEAD H#define SNAKE_BODY X#define SNAKE_FOOD $#define SNAKE_MAX_LENGTH 20int snake_index = 4;//当前蛇尾数组下标int fail = 0;//判断是否失败int snake_x[SNAKE_MAX_LENGTH] = {5,4,3,2,1};int snake_y[SNAKE_MAX_LENGTH] = {1,1,1,1,1};int have_food = 0;//判断是否输出食物int distance[4] = {0};char movable[4] = {'W','S','A','D'};int Fx = 0,Fy = 0;char map[12][12] ={ "************", "*XXXXH *", "* *", "* *", "* *", "* *", "* *", "* *", "* *", "* *", "* *", "************"};int getmin(int distance[],char n){ int i = 0,temp = distance[0],j=0; for(i = 0;i<4;i++) { if(temp > distance[i] && movable[i] != n) { temp = distance[i]; j = i; } } return j;}char getnot_move(){ if( (map[snake_y[0]][snake_x[0] + 1] == 'x' && map[snake_y[0]][snake_x[0] + 1] == '*')) return 'D'; else if( (map[snake_y[0]][snake_x[0] - 1] == 'x' && map[snake_y[0]][snake_x[0] - 1] == '*')) return 'A'; else if( (map[snake_y[0]][snake_x[0] + 1] == 'x' && map[snake_y[0]][snake_x[0] + 1] == '*') ) return 'S'; else if( (map[snake_y[0]][snake_x[0] - 1] == 'x' && map[snake_y[0]][snake_x[0] - 1] == '*') ) return 'W';}char wherego(){ int i; distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx); distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx); distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx); distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx); char n = getnot_move(); i = getmin(distance,n); return movable[i];}void movesnake(int sx , int sy)//利用贪吃蛇总是沿着之前的轨迹爬行{ int i,tempx,tempy; map[snake_y[snake_index]][snake_x[snake_index]] = ' '; tempx = snake_x[snake_index]; tempy = snake_y[snake_index];//记录新生成的尾巴的位置 for(i = snake_index;i>0;i-- ) { snake_x[i] = snake_x[i-1]; snake_y[i] = snake_y[i-1]; map[snake_y[i]][snake_x[i]] = 'X'; } if(sx == 0){ snake_y[0] = snake_y[0] + sy; } else snake_x[0] = snake_x[0] + sx; if(map[snake_y[0]][snake_x[0]] == '$') { have_food = 0; snake_index++; snake_x[snake_index] = tempx; snake_y[snake_index] = tempy; //map[snake_y[tempy]][tempx] = 'X';过多导致输出混乱 } if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1;; map[snake_y[0]][snake_x[0]] = 'H';}void output(){ int i ,j ; for( i = 0;i < 12;i++) { for(j = 0;j < 12;j++) printf("%c",map[i][j]); printf("\n"); }}void put_money(){ int i,j,k; if(!have_food) { srand((int)time(NULL)); for(k = 0;k < 100 ;k++){ i = rand() % 11 + 1;//使输出在框架之内 j = rand() % 11 + 1; if(map[i][j] == ' ') { map[i][j] = '$'; have_food = 1; Fx = j; Fy = i; break; } } }}void gameover(){ puts("gameover");}int main(){ char ch; while(1) { output(); while(1) { put_money(); ch = wherego(); if(ch == 'W') movesnake(0,-1); else if(ch == 'S') movesnake(0,1); else if(ch == 'A') movesnake(-1,0); else if(ch == 'D') movesnake(1,0); else break; if(fail){ gameover(); break; } output(); if(snake_index == SNAKE_MAX_LENGTH - 1) { puts("winning!"); break; } } break; }}
这是我看完老师所给的算法后第一感打出的代码(然而错漏百出),由于移动函数方面的判断失误,这条蛇经常把自己咬死了,因而,我对这个代码的移动部分进行了改进。
这里是修改后的移动代码:
int getnot_move(int i){ int dx = 0,dy = 0; if(i == 0) dy = -1; else if(i == 1) dy = 1; else if(i == 2) dx = -1; else dx = 1; if(dy){ if(map[snake_y[0] + dy][snake_x[0]] == 'X') return 0; else if(map[snake_y[0] + dy][snake_x[0]] == '*') return 0; else return 1; } else{ if(map[snake_y[0]][snake_x[0] + dx] == '*') return 0; else if(map[snake_y[0]][snake_x[0] + dx] == 'X') return 0; else return 1; }}char wherego(){ int i; int count= 4; distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx); distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx); distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx); distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx); while(count--){ i = getmin(distance); if(!getnot_move(i)){ distance[i] = 9999; i = getmin(distance); } } return movable[i];}
经过修改后的代码,果然不会无缘无故地自己咬死自己啦。
可是:这条蛇却会自己走到死胡同里。。。。。。我再看了一下老师的算法,老师利用贪心的原理,每次都寻找最短的距离,而忽略了这条蛇究竟能不能存活的问题,可以说,这是算法的问题,那么,就只有改变方法了。
方法一:
if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1;
将我的代码里面这条判定死亡的代码删去,蛇就不会死啦!我创作了无敌版贪吃蛇。
当然,下面的方法是更合理的。
方法二:
char map[12][12] ={ "************", "*XXXXH *", "* ******** *", "* ******** *", "* ******** *", "* ******** *", "* ******** *", "* ******** *", "* ******** *", "* ******** *", "* *", "************"};
只要把地图设置成单行道,那么蛇在限定20的长度以内,就永远不会死啦!
当然,我们应该还有更好地方法:
我们可以设置一条蛇,让它去移动,记录下路径,找出一条不会死的路.
代码呢?
然而博主太懒了,技术又渣,打不出来那么厉害的蛇,所以就没有代码了。。
当然,博主还是对蛇代码进行了一些体验上的改造的,下面贴出代码:
system("cls");
有了这个代码,终于可以好好玩蛇了。
system("title 贪吃蛇——HaiRG"); system("mode con cols=35 lines=25"); system("color F0");
设定颜色啦、标题啦、大小啦,看起来我觉得更舒适了。
clock_t start,end;start = time(NULL);end = time(NULL);while(end - start < 4 / snake_index) end = time(NULL);
利用计数器进行延时,并且你会发现蛇越吃越快,这样就增加了少许的难度了。
最后是我完整的代码:
#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<math.h>#define WALL_CELL *#define SNAKE_HEAD H#define SNAKE_BODY X#define SNAKE_FOOD $#define SNAKE_MAX_LENGTH 20int snake_index = 4;//当前蛇尾数组下标int fail = 0;//判断是否失败int snake_x[SNAKE_MAX_LENGTH] = {5,4,3,2,1};int snake_y[SNAKE_MAX_LENGTH] = {1,1,1,1,1};int have_food = 0;//判断是否输出食物int distance[4] = {0};char movable[4] = {'W','S','A','D'};int Fx = 0,Fy = 0;char map[12][12] ={ "************", "*XXXXH *", "* *** * *", "* *** * *", "* *", "* **** *", "* *", "* * ** *", "* * *", "* * ** *", "* *", "************"};int getmin(int distance[]){ int i = 0,temp = distance[0],j=0; for(i = 0;i<4;i++) { if(temp > distance[i] ) { temp = distance[i]; j = i; } } return j;}int getnot_move(int i){ int dx = 0,dy = 0; if(i == 0) dy = -1; else if(i == 1) dy = 1; else if(i == 2) dx = -1; else dx = 1; if(dy){ if(map[snake_y[0] + dy][snake_x[0]] == 'X') return 0; else if(map[snake_y[0] + dy][snake_x[0]] == '*') return 0; else return 1; } else{ if(map[snake_y[0]][snake_x[0] + dx] == '*') return 0; else if(map[snake_y[0]][snake_x[0] + dx] == 'X') return 0; else return 1; }}char wherego(){ int i; int count= 4; distance[0] = abs(snake_y[0] -1 - Fy) + abs(snake_x[0] - Fx); distance[1] = abs(snake_y[0] +1 - Fy) + abs(snake_x[0] - Fx); distance[2] = abs(snake_y[0] - Fy) + abs(snake_x[0] -1 - Fx); distance[3] = abs(snake_y[0] - Fy) + abs(snake_x[0] +1 - Fx); while(count--){ i = getmin(distance); if(!getnot_move(i)){ distance[i] = 9999; i = getmin(distance); } } return movable[i];}void movesnake(int sx , int sy)//利用贪吃蛇总是沿着之前的轨迹爬行{ int i,tempx,tempy; map[snake_y[snake_index]][snake_x[snake_index]] = ' '; tempx = snake_x[snake_index]; tempy = snake_y[snake_index];//记录新生成的尾巴的位置 for(i = snake_index;i>0;i-- ) { snake_x[i] = snake_x[i-1]; snake_y[i] = snake_y[i-1]; map[snake_y[i]][snake_x[i]] = 'X'; } if(sx == 0){ snake_y[0] = snake_y[0] + sy; } else snake_x[0] = snake_x[0] + sx; if(map[snake_y[0]][snake_x[0]] == '$') { have_food = 0; snake_index++; snake_x[snake_index] = tempx; snake_y[snake_index] = tempy; //map[snake_y[tempy]][tempx] = 'X';过多导致输出混乱 } if(map[snake_y[0]][snake_x[0]] == '*' || map[snake_y[0]][snake_x[0]] == 'X') fail = 1; map[snake_y[0]][snake_x[0]] = 'H';}void output(){ int i ,j ; system("cls"); for( i = 0;i < 12;i++) { for(j = 0;j < 12;j++) printf("%c",map[i][j]); printf("\n"); }}void put_money(){ int i,j,k; if(!have_food) { srand((int)time(NULL)); for(k = 0;k < 1000 ;k++){ i = rand() % 11 + 1;//使输出在框架之内 j = rand() % 11 + 1; if(map[i][j] == ' ') { map[i][j] = '$'; have_food = 1; Fx = j; Fy = i; break; } } }}void gameover(){ puts("gameover");}int main(){ char ch; system("title 贪吃蛇——HaiRG"); system("mode con cols=35 lines=25"); system("color F0"); //clock_t start,end; while(1) { output(); while(1) { put_money(); ch = wherego(); start = time(NULL); end = time(NULL); while(end - start < 4 / snake_index) end = time(NULL); if(ch == 'W') movesnake(0,-1); else if(ch == 'S') movesnake(0,1); else if(ch == 'A') movesnake(-1,0); else if(ch == 'D') movesnake(1,0); else break; if(fail){ gameover(); break; } output(); if(snake_index == SNAKE_MAX_LENGTH - 1) { puts("winning!"); break; } } break; }}
附上一些游戏图:
这是没设置障碍时的图。
很多失败的图我就不发了。。
其实打一条智能蛇的代码还是挺有趣的,你也可以尝试一番。
- 字符游戏——智能蛇
- 字符游戏——智能蛇
- 字符游戏-智能蛇
- 字符游戏-智能蛇
- 字符游戏-智能蛇
- 字符游戏-智能蛇
- 字符游戏-智能蛇(上)
- 字符游戏-智能蛇(下)
- 字符游戏-智能蛇(学习体会)
- 字符游戏-智能蛇(代码版)
- 字符游戏—贪吃蛇
- 字符游戏——贪吃蛇
- 简单字符游戏——贪吃蛇
- 字符游戏——贪吃蛇
- 字符游戏——贪吃蛇
- 【C语言编程设计】字符游戏——贪吃蛇
- 字符游戏——简单贪吃蛇的制作
- Python100例——第十一章----智能游戏
- Spring boot 全部默认配置
- 图像的小波变换(一)
- 快捷方式
- matlab串口通信
- Python(二)python简介、变量、数值类型、操作符、I/O、判断|循环语句
- 字符游戏——智能蛇
- YTU.1743: 多处最优服务次序问题
- 代码规范 : 关于注释和日志
- Android之Intent(数据传递)
- ros学习
- VM 虚拟机配置NAT模式,连接互联网
- caffe 训练模型时出错 caffe-parallel has a bug: Check failed: proto.SerializeToOstream(&output)
- SDUT 2122-数据结构实验之链表七:单链表中重复元素的删除
- 可扩展ListView