字符版本贪吃蛇游戏

这篇博客介绍了我是怎样通过自顶而下的方法一步步开发出一个字符版本的贪吃蛇游戏,并利用此前实现的智能蛇开发出全新的人机大战贪吃蛇。


会动的蛇

首先我们先实现一条能根据输入移动的蛇。
这条蛇的伪代码如下:

输出字符矩阵
    WHILE not 游戏结束 DO
        ch=等待输入
        CASE ch DO
        ‘A’:左前进一步,break 
        ‘D’:右前进一步,break    
        ‘W’:上前进一步,break    
        ‘S’:下前进一步,break    
        END CASE
        输出字符矩阵
    END WHILE
    输出 Game Over!!! 

在实现时,首先管理好程序的头部:

#define SNAKE_MAX_LENGTH 20
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define SNAKE_FOOD '$'
#define WALL_CELL '*'
#define MAP_SIZE 12

//snake stepping: dy = -1(up), 1(down); dx = -1(left), 1(right), 0(no move)
void snakeMove(int, int);

// put a food randimized on a blank cell
void put_money(void);

//output cells of the grid
void output(void);

//output gameover
void gameover(void);

char map[MAP_SIZE][MAP_SIZE] =
{
    "************",
    "*XXXXH     *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "************",
};

// variables for snake and the initial values
int snakeX[SNAKE_MAX_LENGTH] = {1, 2, 3, 4, 5};
int snakeY[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};
int snakeLength = 5;

int isGameOver = 0;

然后按伪代码编写 main 函数:

int main(int argc, const char * argv[]) {
    char c;
    output();
    while (isGameOver == 0) { // if game is not over
        scanf("%c", &c); //
        while (c == '\n') {
            scanf("%c", &c);
        }
        switch(c){
            case 'a':
                snakeMove(-1, 0);
                break;
            case 'd':
                snakeMove(1, 0);
                break;
            case 'w':
                snakeMove(0, 1);
                break;
            case 's':
                snakeMove(0, -1);
                break;
            default:
                break;
        }
        output();
    }
    gameover();
    return 0;
}

然后一个个实现 main 中的函数:

void snakeMove(int dx, int dy){
    int i = snakeLength - 1;
    // check if snake is going backward
    if (snakeX[i] + dx == snakeX[i - 1] && snakeY[i] - dy == snakeY[i - 1]) {
        return;
    }
    i = 0;
    // turn TAIL into ' '
    map[snakeY[i]][snakeX[i]] = ' ';
    // make every BODY move forward
    for (i = 0; i < snakeLength-1; i ++) {
        snakeX[i] = snakeX[i+1];
        snakeY[i] = snakeY[i+1];
    }
    // display every BODY
    for (i = 1; i < snakeLength - 1; i ++) {
        map[snakeY[i]][snakeX[i]] = SNAKE_BODY;
    }
    // make HEAD move
    snakeX[i] += dx;
    snakeY[i] -= dy;
    // check if HEAD is moving to somewhere blank
    if (map[snakeY[i]][snakeX[i]] != ' ') {
        isGameOver = 1; // if not, game over
        return;
    }
    // if so, display HEAD
    map[snakeY[i]][snakeX[i]] = SNAKE_HEAD;
}


void output(void){
    //system("clear && printf '\e[3J'");
    //system("clear && '\e[3J'");
    //system("\033[2J");
    //system("\e[3J");
    // if in windows environment, change the statement into:
    // system("cls");
    int i = 0, j = 0;
    for (i = 0 ; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            printf("%c",map[i][j]);
        }
        printf("\n");
    }
}

void gameover(void){
    printf("Game Over!");
}

能吃的蛇

接下来就要让这条蛇有吃东西的功能了。
首先需要实现一个在空白位置放食物的函数:

void put_money(void){
    if (isFoodEaten) {
        foodX = rand() % 10 + 1;
        foodY = rand() % 10 + 1;
        while (map[foodY][foodX] != ' ') {
            foodX = rand() % 10 + 1;
            foodY = rand() % 10 + 1;
        }
        map[foodY][foodX] = SNAKE_FOOD;
        isFoodEaten = 0;
    }
}

并修改 snakeMove 函数:

void snakeMove(int dx, int dy){
    int i = snakeLength - 1;
    // check if snake is going backward
    if (snakeX[i] + dx == snakeX[i - 1] && snakeY[i] - dy == snakeY[i - 1]) {
        return;
    }
    // check if snake is eating the food
    if (map[snakeY[i] - dy][snakeX[i] + dx] == '$'){
        map[snakeY[i] - dy][snakeX[i] + dx] = 'H';
        map[snakeY[i]][snakeX[i]] = 'X';
        snakeLength += 1;
        // add HEAD position
        snakeX[snakeLength-1] = snakeX[i] + dx;
        snakeY[snakeLength-1] = snakeY[i] - dy;
        isFoodEaten = 1;
        return;
    }
    i = 0;
    // turn TAIL into ' '
    map[snakeY[i]][snakeX[i]] = ' ';
    // make every BODY move forward
    for (i = 0; i < snakeLength-1; i ++) {
        snakeX[i] = snakeX[i+1];
        snakeY[i] = snakeY[i+1];
    }
    // display every BODY
    for (i = 1; i < snakeLength - 1; i ++) {
        map[snakeY[i]][snakeX[i]] = SNAKE_BODY;
    }
    // make HEAD move
    snakeX[i] += dx;
    snakeY[i] -= dy;
    // check if HEAD is moving to somewhere blank
    if (map[snakeY[i]][snakeX[i]] != ' ') {
        isGameOver = 1; // if not, game over
        return;
    }
    // if so, display HEAD
    map[snakeY[i]][snakeX[i]] = SNAKE_HEAD;
}

可玩的贪吃蛇

能吃的蛇距离可玩的贪吃蛇游戏还有一些距离。主要问题在于蛇不能每个一端时间自动前进;并且输入时还需要摁回车确认。
我参考了这篇文章:Linux下非阻塞地检测键盘输入的方法 (整理),在原来的基础上加入了 kbhit() 功能,解决上面的问题。
具体代码如下:

//
//  main.c
//  snake_play1
//
//  Created by 尤大智 on 2017/12/24.
//  Copyright © 2017年 尤大智. All rights reserved.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>

#define SNAKE_MAX_LENGTH 100
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define SNAKE_FOOD '$'
#define WALL_CELL '*'
#define MAP_SIZE 20

static struct termios ori_attr, cur_attr;

static __inline
int tty_reset(void)
{
    if (tcsetattr(STDIN_FILENO, TCSANOW, &ori_attr) != 0)
        return -1;

    return 0;
}


static __inline
int tty_set(void)
{

    if ( tcgetattr(STDIN_FILENO, &ori_attr) )
        return -1;

    memcpy(&cur_attr, &ori_attr, sizeof(cur_attr) );
    cur_attr.c_lflag &= ~ICANON;
    //        cur_attr.c_lflag |= ECHO;
    cur_attr.c_lflag &= ~ECHO;
    cur_attr.c_cc[VMIN] = 1;
    cur_attr.c_cc[VTIME] = 0;

    if (tcsetattr(STDIN_FILENO, TCSANOW, &cur_attr) != 0)
        return -1;

    return 0;
}

static __inline
int kbhit(void)
{

    fd_set rfds;
    struct timeval tv;
    int retval;

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    /* Wait up to five seconds. */
    tv.tv_sec  = 0;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);
    /* Don't rely on the value of tv now! */

    if (retval == -1) {
        perror("select()");
        return 0;
    } else if (retval)
        return 1;
    /* FD_ISSET(0, &rfds) will be true. */
    else
        return 0;
    return 0;
}


//snake stepping: dy = -1(up), 1(down); dx = -1(left), 1(right), 0(no move)
void snakeMove(int, int);

// put a food randimized on a blank cell
void put_money(void);

//output cells of the grid
void output(void);

//output gameover
void gameover(void);

char map[MAP_SIZE][MAP_SIZE];
void start(void);

// variables for snake and the initial values
int snakeX[SNAKE_MAX_LENGTH] = {1, 2, 3, 4, 5};
int snakeY[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};
int snakeLength = 5;
// variables for food
int foodX;
int foodY;

int isGameOver = 0;
int isFoodEaten = 1;
int score = 0;


int main(int argc, const char * argv[]) {

    while (1) {
        start();
        //设置终端进入非缓冲状态
        int tty_set_flag;
        tty_set_flag = tty_set();

        char c = 'd';
        srand((unsigned int)time(NULL));
        put_money();
        output();
        while (isGameOver == 0) { // if game is not over
            if(kbhit()){
                c = getchar();
                usleep(500000);
            }
            else{
                usleep(500000);
            }
            switch(c){
                case 'a':
                    snakeMove(-1, 0);
                    break;
                case 'd':
                    snakeMove(1, 0);
                    break;
                case 'w':
                    snakeMove(0, 1);
                    break;
                case 's':
                    snakeMove(0, -1);
                    break;
                default:
                    break;
            }
            put_money();
            output();
        }
        gameover();
        printf("press ANY button to restart or press Q to quit.\n");

        c = getchar();
        if (c == 'q') {
            break;
        }

        //恢复终端设置
        if(tty_set_flag == 0)
            tty_reset();
    }

    return 0;
}
void snakeMove(int dx, int dy){
    int i = snakeLength - 1;
    // check if snake is going backward
    if (snakeX[i] + dx == snakeX[i - 1] && snakeY[i] - dy == snakeY[i - 1]) {
        return;
    }
    // check if snake is eating the food
    if (map[snakeY[i] - dy][snakeX[i] + dx] == '$'){
        map[snakeY[i] - dy][snakeX[i] + dx] = 'H';
        map[snakeY[i]][snakeX[i]] = 'X';
        snakeLength += 1;
        // add HEAD position
        snakeX[snakeLength-1] = snakeX[i] + dx;
        snakeY[snakeLength-1] = snakeY[i] - dy;
        isFoodEaten = 1;
        score ++;
        return;
    }
    i = 0;
    // turn TAIL into ' '
    map[snakeY[i]][snakeX[i]] = ' ';
    // make every BODY move forward
    for (i = 0; i < snakeLength-1; i ++) {
        snakeX[i] = snakeX[i+1];
        snakeY[i] = snakeY[i+1];
    }
    // display every BODY
    for (i = 1; i < snakeLength - 1; i ++) {
        map[snakeY[i]][snakeX[i]] = SNAKE_BODY;
    }
    // make HEAD move
    snakeX[i] += dx;
    snakeY[i] -= dy;
    // check if HEAD is moving to somewhere blank
    if (map[snakeY[i]][snakeX[i]] != ' ') {
        isGameOver = 1; // if not, game over
        return;
    }
    // if so, display HEAD
    map[snakeY[i]][snakeX[i]] = SNAKE_HEAD;
}

void output(void){
    //system("clear && \033[2J");
    system("clear && printf '\e[3J'");
    // if in windows environment, change the statement into:
    // system("cls");
    int i = 0, j = 0;
    printf("score : %d\n", score);
    for (i = 0 ; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            printf("%c",map[i][j]);
        }
        printf("\n");
    }
}

void gameover(void){
    printf("Game Over!\nYour score is %d.\n", score);
}
void start(void){
    snakeLength = 5;
    score = 0;
    int i = 0, j = 0;
    for (i = 0; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            map[i][j] = ' ';
        }
    }
    for (i = 0; i < MAP_SIZE; i ++) {
        map[0][i] = '*';
        map[MAP_SIZE-1][i] = '*';
        map[i][0] = '*';
        map[i][MAP_SIZE-1] = '*';
    }
    for (i = 0; i <= 4; i ++) {
        snakeX[i] = i+1;
        snakeY[i] = 1;
        map[snakeY[i]][snakeX[i]] = 'X';
    }
    map[snakeY[snakeLength-1]][snakeX[snakeLength-1]] = 'H';
    isGameOver = 0;
    isFoodEaten = 1;
}
void put_money(void){
    if (isFoodEaten) {
        foodX = rand() % 10 + 1;
        foodY = rand() % 10 + 1;
        while (map[foodY][foodX] != ' ') {
            foodX = rand() % 10 + 1;
            foodY = rand() % 10 + 1;
        }
        map[foodY][foodX] = SNAKE_FOOD;
        isFoodEaten = 0;
    }
}

于是一个如下图所示的字符版本贪吃蛇游戏就实现了:

这里写图片描述


创新玩法:人机大战贪吃蛇

利用此前实现的智能蛇程序,我想到可以把它加进游戏,使玩家和这只蛇对战一下,看看谁能活得更久,吃得更多。

这里写图片描述

具体代码如下:

//
//  main.c
//  snake_battle
//
//  Created by 尤大智 on 2017/12/26.
//  Copyright © 2017年 尤大智. All rights reserved.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>

#define SNAKE_MAX_LENGTH 100
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define SNAKE_FOOD '$'
#define WALL_CELL '*'
#define MAP_SIZE 20

// variables for snake and the initial values
int snakePlayerX[SNAKE_MAX_LENGTH] = {1, 2, 3, 4, 5};
int snakePlayerY[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};
int snakeAIX[SNAKE_MAX_LENGTH] = {1, 2, 3, 4, 5};
int snakeAIY[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};
int snakePlayerLength = 5;
int snakeAILength = 5;
// variables for food
int foodX;
int foodY;

int isGameOverPlayer = 0;
int isGameOverAI = 0;
int isFoodEaten = 1;
int scorePlayer = 0;
int scoreAI = 0;

char mapPlayer[MAP_SIZE][MAP_SIZE];
char mapAI[MAP_SIZE][MAP_SIZE];
void start(void);

static struct termios ori_attr, cur_attr;

static __inline
int tty_reset(void)
{
    if (tcsetattr(STDIN_FILENO, TCSANOW, &ori_attr) != 0)
        return -1;

    return 0;
}


static __inline
int tty_set(void)
{

    if ( tcgetattr(STDIN_FILENO, &ori_attr) )
        return -1;

    memcpy(&cur_attr, &ori_attr, sizeof(cur_attr) );
    cur_attr.c_lflag &= ~ICANON;
    //        cur_attr.c_lflag |= ECHO;
    cur_attr.c_lflag &= ~ECHO;
    cur_attr.c_cc[VMIN] = 1;
    cur_attr.c_cc[VTIME] = 0;

    if (tcsetattr(STDIN_FILENO, TCSANOW, &cur_attr) != 0)
        return -1;

    return 0;
}

static __inline
int kbhit(void)
{

    fd_set rfds;
    struct timeval tv;
    int retval;

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    /* Wait up to five seconds. */
    tv.tv_sec  = 0;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);
    /* Don't rely on the value of tv now! */

    if (retval == -1) {
        perror("select()");
        return 0;
    } else if (retval)
        return 1;
    /* FD_ISSET(0, &rfds) will be true. */
    else
        return 0;
    return 0;
}
//snake stepping: dy = -1(up), 1(down); dx = -1(left), 1(right), 0(no move)
void snakePlayerMove(int, int);
void snakeAIMove(int, int);
// put a food randimized on a blank cell
void put_money(void);
//output cells of the grid
void output(void);
//determine AI where to go next
char whereGoNext(void);
//output gameover
void gameover(void);

int main(int argc, const char * argv[]) {
    while (1) {
        start();
        //设置终端进入非缓冲状态
        int tty_set_flag;
        tty_set_flag = tty_set();

        char cPlayer = 'd', cAI = 'd';
        srand((unsigned int)time(NULL));
        put_money();
        output();
        while (isGameOverPlayer == 0 && isGameOverAI == 0) { // if game is not over
            if(kbhit()){
                cPlayer = getchar();
                usleep(500000);
            }
            else{
                usleep(500000);
            }
            cAI = whereGoNext();
            switch(cPlayer){
                case 'a':
                    snakePlayerMove(-1, 0);
                    break;
                case 'd':
                    snakePlayerMove(1, 0);
                    break;
                case 'w':
                    snakePlayerMove(0, 1);
                    break;
                case 's':
                    snakePlayerMove(0, -1);
                    break;
                default:
                    break;
            }
            switch(cAI){
                case 'a':
                    snakeAIMove(-1, 0);
                    break;
                case 'd':
                    snakeAIMove(1, 0);
                    break;
                case 'w':
                    snakeAIMove(0, 1);
                    break;
                case 's':
                    snakeAIMove(0, -1);
                    break;
                default:
                    break;
            }
            put_money();
            output();
        }
        gameover();
        usleep(1000000);
        printf("press R to restart or press Q to quit.\n");
        cPlayer = getchar();
        while (cPlayer != 'r') {
            if (cPlayer == 'q') {
                return 0;
            }
            cPlayer = getchar();
        }

        //恢复终端设置
        if(tty_set_flag == 0)
            tty_reset();
    }
    return 0;
}

void snakePlayerMove(int dx, int dy){
    int i = snakePlayerLength - 1;
    // check if snake is going backward
    if (snakePlayerX[i] + dx == snakePlayerX[i - 1] && snakePlayerY[i] - dy == snakePlayerY[i - 1]) {
        return;
    }
    // check if snake is eating the food
    if (mapPlayer[snakePlayerY[i] - dy][snakePlayerX[i] + dx] == '$'){
        mapPlayer[snakePlayerY[i] - dy][snakePlayerX[i] + dx] = 'H';
        mapPlayer[snakePlayerY[i]][snakePlayerX[i]] = 'X';
        snakePlayerLength += 1;
        // add HEAD position
        snakePlayerX[snakePlayerLength-1] = snakePlayerX[i] + dx;
        snakePlayerY[snakePlayerLength-1] = snakePlayerY[i] - dy;
        isFoodEaten = 1;
        scorePlayer ++;
        return;
    }
    i = 0;
    // turn TAIL into ' '
    mapPlayer[snakePlayerY[i]][snakePlayerX[i]] = ' ';
    // make every BODY move forward
    for (i = 0; i < snakePlayerLength-1; i ++) {
        snakePlayerX[i] = snakePlayerX[i+1];
        snakePlayerY[i] = snakePlayerY[i+1];
    }
    // display every BODY
    for (i = 1; i < snakePlayerLength - 1; i ++) {
        mapPlayer[snakePlayerY[i]][snakePlayerX[i]] = SNAKE_BODY;
    }
    // make HEAD move
    snakePlayerX[i] += dx;
    snakePlayerY[i] -= dy;
    // check if HEAD is moving to somewhere blank
    if (mapPlayer[snakePlayerY[i]][snakePlayerX[i]] != ' ') {
        isGameOverPlayer = 1; // if not, game over
        return;
    }
    // if so, display HEAD
    mapPlayer[snakePlayerY[i]][snakePlayerX[i]] = SNAKE_HEAD;
}
void snakeAIMove(int dx, int dy){
    int i = snakeAILength - 1;
    // check if snake is going backward
    if (snakeAIX[i] + dx == snakeAIX[i - 1] && snakeAIY[i] - dy == snakeAIY[i - 1]) {
        return;
    }
    // check if snake is eating the food
    if (mapAI[snakeAIY[i] - dy][snakeAIX[i] + dx] == '$'){
        mapAI[snakeAIY[i] - dy][snakeAIX[i] + dx] = 'H';
        mapAI[snakeAIY[i]][snakeAIX[i]] = 'X';
        snakeAILength += 1;
        // add HEAD position
        snakeAIX[snakeAILength-1] = snakeAIX[i] + dx;
        snakeAIY[snakeAILength-1] = snakeAIY[i] - dy;
        isFoodEaten = 1;
        scoreAI ++;
        return;
    }
    i = 0;
    // turn TAIL into ' '
    mapAI[snakeAIY[i]][snakeAIX[i]] = ' ';
    // make every BODY move forward
    for (i = 0; i < snakeAILength-1; i ++) {
        snakeAIX[i] = snakeAIX[i+1];
        snakeAIY[i] = snakeAIY[i+1];
    }
    // display every BODY
    for (i = 1; i < snakeAILength - 1; i ++) {
        mapAI[snakeAIY[i]][snakeAIX[i]] = SNAKE_BODY;
    }
    // make HEAD move
    snakeAIX[i] += dx;
    snakeAIY[i] -= dy;
    // check if HEAD is moving to somewhere blank
    if (mapAI[snakeAIY[i]][snakeAIX[i]] != ' ') {
        isGameOverAI = 1; // if not, game over
        return;
    }
    // if so, display HEAD
    mapAI[snakeAIY[i]][snakeAIX[i]] = SNAKE_HEAD;
}
void start(void){
    snakePlayerLength = 5;
    snakeAILength = 5;
    scorePlayer = 0;
    scoreAI = 0;
    int i = 0, j = 0;
    for (i = 0; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            mapPlayer[i][j] = BLANK_CELL;
            mapAI[i][j] = BLANK_CELL;
        }
    }
    for (i = 0; i < MAP_SIZE; i ++) {
        mapPlayer[0][i] = WALL_CELL;
        mapPlayer[MAP_SIZE-1][i] = WALL_CELL;
        mapPlayer[i][0] = WALL_CELL;
        mapPlayer[i][MAP_SIZE-1] = WALL_CELL;
        mapAI[0][i] = WALL_CELL;
        mapAI[MAP_SIZE-1][i] = WALL_CELL;
        mapAI[i][0] = WALL_CELL;
        mapAI[i][MAP_SIZE-1] = WALL_CELL;
    }
    for (i = 0; i <= 4; i ++) {
        snakePlayerX[i] = i+1;
        snakeAIX[i] = i+1;
        snakePlayerY[i] = 1;
        snakeAIY[i] = 1;
        mapPlayer[snakePlayerY[i]][snakePlayerX[i]] = SNAKE_BODY;
        mapAI[snakeAIY[i]][snakeAIX[i]] = SNAKE_BODY;
    }
    mapPlayer[snakePlayerY[snakePlayerLength-1]][snakePlayerX[snakePlayerLength-1]] = SNAKE_HEAD;
    mapAI[snakeAIY[snakePlayerLength-1]][snakeAIX[snakePlayerLength-1]] = SNAKE_HEAD;
    isGameOverPlayer = 0;
    isGameOverAI = 0;
    isFoodEaten = 1;
}
void put_money(void){
    if (isFoodEaten) {
        foodX = rand() % 10 + 1;
        foodY = rand() % 10 + 1;
        while (mapPlayer[foodY][foodX] != BLANK_CELL || mapAI[foodY][foodX] != BLANK_CELL) {
            foodX = rand() % 10 + 1;
            foodY = rand() % 10 + 1;
        }
        mapPlayer[foodY][foodX] = SNAKE_FOOD;
        mapAI[foodY][foodX] = SNAKE_FOOD;
        isFoodEaten = 0;
    }
}
void output(void){
    system("clear && printf '\e[3J'");
    // if in windows environment, change the statement into:
    // system("cls");
    int i = 0, j = 0;
    printf("score : %d\n", scorePlayer);
    for (i = 0 ; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            printf("%c",mapPlayer[i][j]);
        }
        printf("\n");
    }
    printf("\nscore : %d\n", scoreAI);
    for (i = 0 ; i < MAP_SIZE; i ++) {
        for (j = 0; j < MAP_SIZE; j ++) {
            printf("%c",mapAI[i][j]);
        }
        printf("\n");
    }
}
char whereGoNext(void){
    char move[4] = {'a', 'd', 'w', 's'};
    int minDistIndex = 0;
    int distance[4] = {0, 0, 0, 0};
    int i = snakeAILength - 1;
    int dx = 0, dy = 0;
    int moveIndex = 0;
    for (moveIndex = 0; moveIndex < 4; moveIndex ++) {
        switch (move[moveIndex]) {
            case 'a':
                dx = -1;
                dy = 0;
                break;
            case 'd':
                dx = 1;
                dy = 0;
                break;
            case 'w':
                dx = 0;
                dy = 1;
                break;
            case 's':
                dx = 0;
                dy = -1;
                break;
            default:
                break;
        }
        // if next step is eating the food, do it.
        if (mapAI[snakeAIY[i] - dy][snakeAIX[i] + dx] == '$') {
            return move[moveIndex];
        }
        // cannot move backward
        else if (snakeAIX[i] + dx == snakeAIX[i - 1] && snakeAIY[i] - dy == snakeAIY[i - 1]) {
            distance[moveIndex] = 9999;
        }
        // cannot move to somewhere not a blank
        else if (mapAI[snakeAIY[i] - dy][snakeAIX[i] + dx] != ' '){ /*have already determined if it is '$'*/
            distance[moveIndex] = 9999;
        }
        else{
            distance[moveIndex] = abs(foodX - (snakeAIX[i] + dx)) + abs(foodY - (snakeAIY[i] - dy));
        }
        if (distance[minDistIndex] > distance[moveIndex]) {
            minDistIndex = moveIndex;
        }
    }
    if (distance[minDistIndex] == 9999) {
        isGameOverAI = 1;
    }
    return move[minDistIndex];
}
void gameover(void){
    if (isGameOverAI) {
        printf("You Win!\n");
    }else{
        printf("You Lose!\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值