C语言: 贪吃蛇异常退出

C语言: 贪吃蛇

标签: C语言 贪吃蛇

by 小威威


这个贪吃蛇是作业来着,所以按照作业的要求做的,只在12*12的区域移动。在放代码之前,我要说一下我在做贪吃蛇的时候遇到的非常隐蔽的BUG:就是已经实现了贪吃蛇,在吃食物的时候,有的时候程序会出现异常,即贪吃蛇.exe遇到问题需要退出。其实,这主要是栈溢出导致的。那哪里栈溢出了呢?

你可以检查一下生成随机食物那一部分代码,你是否用了递归?
如果有,那问题就出在这了。解决方法就是将递归改成while循环,注意将srand((unsigned)time(NULL))放在循环外。

为什么要这样做呢?因为随机数字时以秒为单位产生,即一秒产生一组随机数字,然而,倘若你用递归,产生的随机数字不符合要求而再次调用此函数时,用的时间远远小于1s,随机数字并没有改变,即是此时的随机数依旧是不符合的所以它会继续递归,最终导致栈溢出(因为CPU执行的速度很快,不到1s就已经把栈填满了)

我的代码没有改成while循环,确实有点瑕疵,不过为了赶交作业嘛~

还有一个问题要说明一下:就是一定要自己思考,争取自己把贪吃蛇做出来。遇到不懂的就去查,而不是一味看别人的代码。比如:我想实现清屏,我就去查清屏函数怎么用,而不是看别人的贪吃蛇代码照搬照用。再如,别人的代码中有kbhit()和getch(),而我们想要的是读取键盘输入的值,只需要getch(),根本不需要kbhit()。你就不能照抄别人的,把kbhit()也给写上去,因为你不知道kbhit究竟有什么用。当你用getch()函数编写出贪吃蛇代码,发现只能通过按键来实现贪吃蛇移动,不能实现贪吃蛇自动移动,我们就会想到,怎样让我的贪吃蛇在我没有按键盘时保持原来的方向继续移动,通过查询我们就知道了kbhit()函数就是发挥这个作用,我们也就理所当然的将这个函数用到我们的代码中去。还有其他小细节阿如怎么产生随机食物阿,rand()后的%有什么作用阿…这些都要通过思考,转变成自己的知识,再应用到贪吃蛇代码,如此,当你完成了贪吃蛇代码后,你就会觉得收获颇丰,而不是吐槽这份作业是多么多么地坑!!!

下面放代码:

# include <stdio.h>
# include <stdlib.h>
# include <conio.h>
# include <windows.h>
# include <time.h>

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

void snakemove(int, int);  // Achieve the snake's movement
void put_money(void);  // Achieve the random money occurring
void output(void); // Print the array of map
void gameover(void); // Stop the game and print "game over"

char map[12][13] = {
    "************",
    "*XXXXH     *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "*          *",
    "************"
};   // This is the map
int snakeX[SNAKE_MAX_LENGTH] = {1, 2, 3, 4, 5};  // Define this array to instruct the colunmn coordinate of snake
int snakeY[SNAKE_MAX_LENGTH] = {1, 1, 1, 1, 1};  // Define this array to instruct the row coordinate of snake
int snakeLength = 5;  // The original length of snake
int money_exist = 0;  // Used to judged the money's existion
int eatfood = 0; // Used to judged whether the snake has eaten the food

int main(void) {
    output();  // Print the mao
    while(snakeLength <= SNAKE_MAX_LENGTH-1) {  // Set the loop to achieve entering messages more times
        int ch;  // The valuable we set to store the input value
        if (kbhit()) // Judge whether the user has hit the keyboard
            ch = getch();  // Enter the message without hit the "ENTER"
        switch(ch) {  // According to the message they enter, choose the respectly way to perform
            case 'w':
            case 'W':
                snakemove(0, -1); // Call the function to move the snake
                break;
            case 's':
            case 'S':
                snakemove(0, 1);  // Call the function to move the snake
                break;
            case 'a':
            case 'A':
                snakemove(-1, 0);  // Call the function to move the snake
                break;
            case 'd':
            case 'D':
                snakemove(1, 0);  // Call the function to move the snake
                break;
            default:
                break;
        }
        Sleep(500);  // To pause the for 0.5 seconds.
        system("CLS"); // To empty all the thing in the screen
        output();  // Print the map
    }
    system("CLS"); // To empty all the thing in the screen
    printf("You are so great~\n"); // When you pass it will be print
    return 0;
}

void snakemove(int dx, int dy) {
    if (map[snakeY[snakeLength-1]+dy][snakeX[snakeLength-1]+dx] == WALL_CELL
        || map[snakeY[snakeLength-1]+dy][snakeX[snakeLength-1]+dx] == SNAKE_BODY)
        gameover();  // If the next step is the wall or itself,it means game over
    for (int i = 0; i < snakeLength; i++) {
        map[snakeY[i]][snakeX[i]] = BLANK_CELL;  // Empty the snake in the map first
    }
    for (int i = 0; i < snakeLength-1; i++) {
        if (map[snakeY[snakeLength-1]+dy][snakeX[snakeLength-1]+dx] == SNAKE_FOOD) {
            snakeLength++; // Jugde if the next step is the money and perform respect ways
            money_exist = 0; // Set the value to 0
            snakeX[snakeLength-1] = snakeX[snakeLength-2]+dx;
            snakeY[snakeLength-1] = snakeY[snakeLength-2]+dy;
            map[snakeY[snakeLength-1]][snakeX[snakeLength-1]] = SNAKE_HEAD;
            // Let the location of food becomes the head of snake
            eatfood = 1; // Set the value to 1 means it has eaten the food
            map[snakeY[snakeLength-2]][snakeX[snakeLength-2]] = SNAKE_BODY;
            // Change the ordinary head to the part of body
        }
        if (eatfood == 0) {  // If the next step is not food, move every part of the body to the former one
            snakeX[i] = snakeX[i+1];
            snakeY[i] = snakeY[i+1];
            map[snakeY[i]][snakeX[i]] = SNAKE_BODY; // Move to the former one
            if (i == snakeLength-2) {   // Set the first one as the head of snake
                snakeX[i+1] = snakeX[i+1] + dx;
                snakeY[i+1] = snakeY[i+1] + dy;
                map[snakeY[i+1]][snakeX[i+1]] = SNAKE_HEAD;
            }
        } else {
            eatfood = 0;  // Successfully add the length of snake and perform this statement
        }
    }
    if (money_exist == 0) {  // Judge whether the money have been put
        put_money();
        money_exist = 1;
    }
    if (money_exist == 0) {  // In case of the fail of putting the money
        put_money();
        money_exist = 1;
    }
}
void put_money(void) {  // Define the function of put_money
    srand((unsigned)time(NULL));  // Set the random seed
    int dx, dy, ran; // ran means the random number
    while (1) {
        if ((ran = rand()%10) > 2) { // Creat the correct coordinate
            dx = ran;
            break;
        }
    }
    while (1) {
        if ((ran = rand()%10) > 2) { // Creat the correct coordinate
            dy = ran;
            break;
        }
    }
    if (map[dx][dy] != SNAKE_BODY && map[dx][dy] != SNAKE_HEAD)  // In case of the incorret location
        map[dx][dy] = SNAKE_FOOD;
    else  // If creat the incorrect location that perform this statement
        map[2][2] = SNAKE_FOOD;
}
void output(void) {  // Define the funtion to output the map
    for (int i = 0; i < 12; i++) {
        printf("\n");
        for (int j = 0; j < 12; j++) {
            printf("%c", map[i][j]);
        }
    }
}
void gameover(void) {  // Define the function of gave over
    system("CLS");
    printf("game over!");
    exit(1);  // exit the program
}

以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值