前言
在完成贪吃蛇的设计后,我们不禁想,能不能写个小程序来代替我们控制蛇呢。感觉好像不难,这就让我们一起来探索下。
最简单的智能蛇
最初的想法也一定是最简单的,那就是一步一步地把蛇走到食物那里去,每一步的逻辑是让蛇头和食物的距离变短。那么如果是一步一步实现的,我们只要判断一下蛇前进的3个方向中哪个是不会撞墙或者撞上自己且距离最短的那个就好了。我们通过一个叫函数来实现这个想法。
int myMin(int array[4]) {
int i;
int Min = array[0];
for (i = 1; i < 4; i++) {
if (array[i] < Min) Min = array[i];
}
for (i = 0; i < 4; i++) {
if (array[i] == Min) break;
}
return i;
}
char whereToGo(int Hx, int Hy, int Fx, int Fy) {
char direction[4] = { 'W', 'A', 'S', 'D' };
int distance[4] = { 0, 0, 0, 0 };
int result[4][2] = { { Hx, Hy - 1 },{ Hx - 1, Hy },{ Hx, Hy + 1 },{ Hx + 1, Hy } };
int i;
for (i = 0; i < 4; i++) {
if (map[result[i][1]][result[i][0]] != '*' && map[result[i][1]][result[i][0]] != 'X') {
distance[i] = abs(result[i][0] - Fx) + abs(result[i][1] - Fy);
}
else distance[i] = 9999;
}
int index_Min = myMin(distance);
return direction[index_Min];
}
其中如果这一步会死我们就将距离存为9999来保证足够大。那个myMin函数就是用来返回最小距离的索引值的。
通过这样一个函数,我们的蛇确实能自己动起来了。可是多跑几遍我们就会发现,蛇会把自己走到死胡同里去。也就是说,这样的算法不能够判断这样走吃完食物后会不会死。所以接下来我们就要想办法解决这个问题。
认识人脑的过程
所谓AI,其实就是将人脑思考问题的方式提炼出来然后教会电脑。所以我们的第一步其实是要认识清楚我们自己在玩贪吃蛇的时候是怎样的一个思考过程。不难想明白,我们其实就是对之后的过程先来一个预演,然后判断一下会不会死:如果不会死,好那我们就这么走;反之如果死了,那么我们就先绕一下路,等把路线腾出来,再走。
代码实现
那么认识清楚了人脑的过程,接下里该如何交给电脑呢。首先我们需要把预演的过程实现,其实就是将路线先设计并存储下来,然后提前跑一下。这个过程我们可以通过一个函数实现。
void set_path(char path[]){
int count = 0;
int originalX = snakeX[0];
int originalY = snakeY[0];
while(snakeX[0] != foodX || snakeY[0] != foodY){
path[count] = whereToGo(snakeX[0], snakeY[0], foodX, foodY);
map[snakeY[0]][snakeX[0]] == 'X';
int x = path[count];
switch (x) {
case 'A':
snakeX[0] = snakeX[0] - 1;
break;
case 'W':
snakeY[0] = snakeY[0] - 1;
break;
case 'D':
snakeX[0] = snakeX[0] + 1;
break;
case 'S':
snakeY[0] = snakeY[0] + 1;
break;
}
if(map[snakeY[0]][snakeX[0]] == '*' || map[snakeY[0]][snakeX[0]] == 'X'){
p = 0;
return;
}
printf("%c\n",path[count]);
prediction_X[count] = snakeX[0];
prediction_Y[count] = snakeY[0];
count++;
if(count < snake_length) map[snakeY[snake_length-count]][snakeX[snake_length-count]] = ' ';
}
snakeX[0] = originalX;
snakeY[0] = originalY;
map[snakeY[0]][snakeX[0]] = 'H';
reset(map, count);
on_my_way = 1;
//printf("in\n");
}
void reset(char map[12][12], int n){
int i,j;
for(j = 1; j < n-1; j++){
map[prediction_Y[j]][prediction_X[j]] = ' ';
}
for(i = 1; i < snake_length; i++){
map[snakeY[i]][snakeX[i]] = 'X';
}
}
这里的reset是将模拟后的地图变成模拟前的样子。如果能到达金币则继续走,到达不了则返回gameover,到此为止,智能蛇的初步样子有了。接下来我们需要教会蛇判断生死的能力。经过思考,其实我们判断生死只需要判断蛇头能否到达蛇尾就可以了,而这个函数可以基本按照set_path函数照猫画虎,就不再贴上来了,欢迎读者自己实现。接下来要做的就是让蛇在不能到达蛇尾或者干脆就吃不到的时候,能够自己转悠转悠,这也很简单,将wheretogo函数大概改改,让蛇朝着远离食物的方向走一步就可以了。
一点思考
整个实现智能蛇的过程我们可以看做是做人工智能的过程,我们将人类的思考方式量化,然后教会电脑,这是一个很重要的思路。不仅是智能算法,在我们实现任何一个解决实际问题的算法时,首先将我们人类直觉似的判断量化都是个很重要的过程。