win下的贪吃蛇模拟小程序

本文介绍了两种贪吃蛇游戏的实现方法:一种是单头蛇不允许后退;另一种是双头蛇允许后退。详细展示了游戏逻辑、边界处理、食物生成及键盘输入处理等关键环节,并探讨了程序优化的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

贪吃蛇模拟小程序注意点:

1. 蛇不能出界。

2. 食物不能出界,也不能出现在蛇身上。


1. 单头蛇的模拟: //蛇不能直接后退

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




#define SIZE 21
#define AREA SIZE-1
#define MAXLEN 100
#define SNAKE_MAX_LEN 100
#define ESC 0x1b
#define LEFT_ARROW_KEY 75
#define UP_ARROW_KEY  72
#define RIGHT_ARROW_KEY 77
#define DOWN_ARROW_KEY  80


volatile int food_count = 0;
typedef enum direction{up, down, left, right, logout, none} direction_t;
typedef enum ctlcmd{restart, end} ctlcmd_t;
typedef struct point {
	int x;
	int y;
} point_t;

static point_t food = {-1,-1};



typedef struct snake {
	point_t  points[MAXLEN];
	int max_len;
	int cur_len;
	direction_t dir;
} snake_t;



void clearScreen() {
	system("cls");
}

void initSnake(snake_t *snake) {
	int i;
	int x = SIZE >> 1;
	int y = SIZE >> 1;

	snake->cur_len = 3;
	snake->max_len = MAXLEN;

	snake->points[0].x = x;
	snake->points[0].y = y;

	snake->points[1].x = x;
	snake->points[1].y = y+1;

	snake->points[2].x = x;
	snake->points[2].y = y+2;

	for(i=3; i<snake->max_len; i++){
		snake->points[i].x = -1;
		snake->points[i].y = -1;
	}

	snake->dir = up;
}

void initMatrix(char matrix[SIZE][SIZE]) {
	int i=0;
	int j=0;

	for(i=0; i<SIZE; i++) {
		for(j=0; j<SIZE; j++) {
			matrix[i][j] = ' ';

            if(i==0) matrix[i][j] = '-';    //上边界
			if(j==AREA) matrix[i][j]='|';   //右边界
			if(i==AREA)	matrix[i][j]='-';   //下边界
			if(j==0) matrix[i][j] = '|';    //左边界
		}
		printf("\n");
	}

}

void getRandomFood(char matrix[SIZE][SIZE], snake_t *snake) {
    int i;
    int x;
    int y;
    int max = AREA - 1;

    srand((unsigned)time(NULL));

    if(food_count == 0)
    {
        do {

            x = rand() % max + 1;
            y = rand() % max + 1;
            for(i=0; i<snake->cur_len; i++) {
                if(x==snake->points[i].x && y==snake->points[i].y) break;
            }
            if(i!=snake->cur_len) continue;
        } while(0);

        food.x = x;
        food.y = y;

        matrix[x][y] = 'X';

        food_count++;
    }

}


void drawSnakeToMatrix(char matrix[SIZE][SIZE], snake_t *snake) {
	int i;
	for(i=0; i<snake->cur_len; i++) {
		matrix[snake->points[i].x][snake->points[i].y]= 'o';
	}

}

void drawMatrix(char matrix[SIZE][SIZE]) {
	int i;
	int j;

	clearScreen();
	for(i=0; i<SIZE; i++) {
		for(j=0; j<SIZE; j++) {
			printf("%c ", matrix[i][j]);
		}
		printf("\n");
	}

	printf("******Game Rules****** \n");
	printf(" 方向: left: a; up: w; right: d; down: s;  或者使用方向键;\n");
	printf("O表示蛇,X表示食物,当没有食物时,说明你胜利了,请按ESC键退出 \n");

}







direction_t changeDirection() {
    char c;
    direction_t dir;

    while(!kbhit());
    c = getch();
    switch (c) {
        case 'a':
        case LEFT_ARROW_KEY:
            dir = left;
            break;

        case 'w':
        case UP_ARROW_KEY:
            dir = up;
            break;

        case 'd':
        case RIGHT_ARROW_KEY:
            dir = right;
            break;

        case 's':
        case DOWN_ARROW_KEY:
            dir = down;
            break;

        case ESC:
            dir = logout;
            break;

        default:
            dir = none;
    }

    return dir;
}

void moveSnake(char matrix[SIZE][SIZE], snake_t *snake,   direction_t dir) {

    point_t next_point;
	int tag = 1;
	int last;
	int i;

    if(dir == none) return;

    switch(dir)	{
		case left:
            if(snake->dir == right) {
                tag = 0;
            } else {
                snake->dir = left;
                next_point.y = snake->points[0].y-1;
                next_point.x = snake->points[0].x;

                if(next_point.y == 0)  next_point.y = AREA-1;
            }

            break;

		case right:
            if(snake->dir == left) {
                tag = 0;
            }else {
                snake->dir = right;
                next_point.y = snake->points[0].y+1;
                next_point.x = snake->points[0].x;

                if(next_point.y == AREA)  next_point.y = 1;
            }

			break;

		case up:
            if(snake->dir == down) {
                tag = 0;
            }else {
                snake->dir = up;
                next_point.y = snake->points[0].y;
                next_point.x = snake->points[0].x-1;

                if(next_point.x == 0)  next_point.x = AREA-1;
            }

			break;

		case down:
            if(snake->dir == up) {
                tag = 0;
            }else {
                snake->dir = down;
                next_point.y = snake->points[0].y;
                next_point.x = snake->points[0].x+1;

                if(next_point.x==AREA)  next_point.x = 1;
            }

			break;
	}

	if(tag){
	    last = snake->cur_len - 1;
        if(next_point.x==food.x && next_point.y==food.y) {
            snake->cur_len++;
            last++;
            food_count--;
            matrix[food.x][food.y] = ' ';
            getRandomFood(matrix, snake);
        }else {
            matrix[snake->points[last].x][snake->points[last].y] = ' ';
        }

        for(i=last; i>0; i--) {
            snake->points[i].x = snake->points[i-1].x;
            snake->points[i].y = snake->points[i-1].y;
        }
        snake->points[0].x = next_point.x;
        snake->points[0].y = next_point.y;
	}

}

void sankeGame() {
    char matrix[SIZE][SIZE];
	snake_t snake;
	direction_t dir;

	initSnake(&snake);
	initMatrix(matrix);

	while(1) {
		getRandomFood(matrix, &snake);
		drawSnakeToMatrix(matrix, &snake);
		drawMatrix(matrix);
		dir = changeDirection();
		if(dir == logout) break;
		moveSnake(matrix, &snake, dir);
	}
}




int main(int argc, char *argv[], char *env[])
{
    sankeGame();
    clearScreen();
    printf("\n\n\t\t********SNAKE GAME OVER ******* \n\n\n");

    printf("\n\n\n press any key to exit this window!\n\n\n");
    getch();

    return 0;

}

2.双头蛇的模拟: 蛇可以后退。

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




#define SIZE 21
#define AREA SIZE-1
#define MAXLEN 100
#define SNAKE_MAX_LEN 100
#define ESC 0x1b
#define LEFT_ARROW_KEY 75
#define UP_ARROW_KEY  72
#define RIGHT_ARROW_KEY 77
#define DOWN_ARROW_KEY  80


volatile int food_count = 0;
typedef enum direction{up, down, left, right, logout, none} direction_t;
typedef struct point {
	int x;
	int y;
} point_t;

static point_t food = {-1,-1};

typedef struct snake {
	point_t  points[MAXLEN];
	int max_len;
	int cur_len;
	direction_t dir;
} snake_t;

void swap(point_t *p, point_t *q) {
    point_t tmp = *p;
    *p = *q;
    *q = tmp;
}
void reverseArray(point_t *array, int start, int end) {

    for( ; start<end; start++, end--){
        swap(array+start, array+end);
    }

}



void clearScreen() {
	system("cls");
}

void initSnake(snake_t *snake) {
	int i;
	int x = SIZE >> 1;
	int y = SIZE >> 1;

	snake->cur_len = 3;
	snake->max_len = MAXLEN;

	snake->points[0].x = x;
	snake->points[0].y = y;

	snake->points[1].x = x;
	snake->points[1].y = y+1;

	snake->points[2].x = x;
	snake->points[2].y = y+2;

	for(i=3; i<snake->max_len; i++){
		snake->points[i].x = -1;
		snake->points[i].y = -1;
	}

	snake->dir = up;
}

void initMatrix(char matrix[SIZE][SIZE]) {
	int i=0;
	int j=0;

	for(i=0; i<SIZE; i++) {
		for(j=0; j<SIZE; j++) {
			matrix[i][j] = ' ';

            if(i==0) matrix[i][j] = '-';    //上边界
			if(j==AREA) matrix[i][j]='|';   //右边界
			if(i==AREA)	matrix[i][j]='-';   //下边界
			if(j==0) matrix[i][j] = '|';    //左边界
		}
		printf("\n");
	}

}

void getRandomFood(char matrix[SIZE][SIZE], snake_t *snake) {
    int i;
    int x;
    int y;
    int max = AREA - 1;

    srand((unsigned)time(NULL));

    if(food_count == 0)
    {
        do {

            x = rand() % max + 1;
            y = rand() % max + 1;
            for(i=0; i<snake->cur_len; i++) {
                if(x==snake->points[i].x && y==snake->points[i].y) break;
            }
            if(i!=snake->cur_len) continue;
        } while(0);

        food.x = x;
        food.y = y;

        matrix[x][y] = 'X';

        food_count++;
    }

}


void drawSnakeToMatrix(char matrix[SIZE][SIZE], snake_t *snake) {
	int i;
	for(i=0; i<snake->cur_len; i++) {
		matrix[snake->points[i].x][snake->points[i].y]= 'o';
	}

}

void drawMatrix(char matrix[SIZE][SIZE]) {
	int i;
	int j;

	clearScreen();
	for(i=0; i<SIZE; i++) {
		for(j=0; j<SIZE; j++) {
			printf("%c ", matrix[i][j]);
		}
		printf("\n");
	}

	printf("******Game Rules****** \n");
	printf(" 方向: left: a; up: w; right: d; down: s;  或者使用方向键;\n");
	printf("O表示蛇,X表示食物,当没有食物时,说明你胜利了,请按ESC键退出 \n");

}

direction_t changeDirection() {
    char c;
    direction_t dir;

    while(!kbhit());
    c = getch();
    switch (c) {
        case 'a':
        case LEFT_ARROW_KEY:
            dir = left;
            break;

        case 'w':
        case UP_ARROW_KEY:
            dir = up;
            break;

        case 'd':
        case RIGHT_ARROW_KEY:
            dir = right;
            break;

        case 's':
        case DOWN_ARROW_KEY:
            dir = down;
            break;

        case ESC:
            dir = logout;
            break;

        default:
            dir = none;
    }

    return dir;
}
void reverseSnake(snake_t *snake) {
    reverseArray(snake->points, 0, snake->cur_len - 1 );
}

void moveSnake(char matrix[SIZE][SIZE], snake_t *snake,   direction_t dir) {

    point_t next_point;
	int tag = 1;
	int last;
	int i;

    if(dir == none) return;

    switch(dir)	{
		case left:
            if(snake->dir == right) {
                reverseSnake(snake);
            }

            snake->dir = left;
            next_point.y = snake->points[0].y-1;
            next_point.x = snake->points[0].x;
            if(next_point.y == 0)  next_point.y = AREA-1;

            break;

		case right:
            if(snake->dir == left) {
              reverseSnake(snake);
            }

            snake->dir = right;
            next_point.y = snake->points[0].y+1;
            next_point.x = snake->points[0].x;
            if(next_point.y == AREA)  next_point.y = 1;

			break;

		case up:
            if(snake->dir == down) {
                reverseSnake(snake);
            }

            snake->dir = up;
            next_point.y = snake->points[0].y;
            next_point.x = snake->points[0].x-1;
            if(next_point.x == 0)  next_point.x = AREA-1;

			break;

		case down:
            if(snake->dir == up) {
               reverseSnake(snake);
            }

            snake->dir = down;
            next_point.y = snake->points[0].y;
            next_point.x = snake->points[0].x+1;
            if(next_point.x==AREA)  next_point.x = 1;


			break;
	}

	if(tag){
	    last = snake->cur_len - 1;
        if(next_point.x==food.x && next_point.y==food.y) {
            snake->cur_len++;
            last++;
            food_count--;
            matrix[food.x][food.y] = ' ';
            getRandomFood(matrix, snake);
        }else {
            matrix[snake->points[last].x][snake->points[last].y] = ' ';
        }

        for(i=last; i>0; i--) {
            snake->points[i].x = snake->points[i-1].x;
            snake->points[i].y = snake->points[i-1].y;
        }
        snake->points[0].x = next_point.x;
        snake->points[0].y = next_point.y;
	}

}

void sankeGame() {
    char matrix[SIZE][SIZE];
	snake_t snake;
	direction_t dir;

	initSnake(&snake);
	initMatrix(matrix);

	while(1) {
		getRandomFood(matrix, &snake);
		drawSnakeToMatrix(matrix, &snake);
		drawMatrix(matrix);
		dir = changeDirection();
		if(dir == logout) break;
		moveSnake(matrix, &snake, dir);
	}
}






int main(int argc, char *argv[], char *env[])
{
    sankeGame();
    clearScreen();
    printf("\n\n\t\t********SNAKE GAME OVER ******* \n\n\n");

    printf("\n\n\n press any key to exit this window!\n\n\n");
    getch();

    return 0;

}


总结: 每次的重绘,没有做好,好像有抖动,其次是否能用多线程使程序的并发性更好!

其他获取按键的ASCII码的方法:

void printCharKeyASCII() {
    int ch;
    ch = getch();
    printf("%c : %d\n", ch, ch);

}

 void testKeyASCII() {
    int ch;

    while((ch=getch()) != 0X1B) { //按ESC退出
        printf("%c : %d\n", ch, ch);
    }

 }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值