C language implements snake game design
- 2020-10-23 20:12:01
- OfStack
C language to realize the snake, for your reference, the specific content is as follows
Experimental platform: DEV C++
/********************************************************************************
*File name:SnakeGame3.0.c
*Description: Snake game source code ( C Language), adopted
* The width-first algorithm calculates the shortest path from snake to food (time complexity) n^3 Space complexity n^2 ), this algorithm encounters *
* The shortest path will not be calculated until the self siege is over *
*********************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<time.h>
#include<math.h>
#include<conio.h>
#define SIZE 25 // Define map size
#define MAX_LENGTH 19 * 19 // Defines the maximum length of a snake
typedef struct point // The node of a point on a map
{
int r;
int c;
} point;
typedef struct queue // Iterate to search the queues used by the shortest path
{
point * body[5 * SIZE]; // Holds an array of snake bodies (maximum stack depth) 5 * SIZE )
int num; // Record the number of nodes in the queue
int first_in_pos; // The first 1 The index value of the elements that were queued
} queue;
HANDLE stdOutput; // The statement windows Standard output handle
void init(int * length, point * foodAt, int * dir, point body[], char map[][SIZE]); // Initialize the
int getDir(int dir); // Gets the snake's direction of travel
int getAIDir(int dir, int length, point body[], point foodAt); // To obtain AI Judged the direction of travel
int moveable(point moveTo, int length, point body[]);
int move(point foodAt, int dir, int length, point body[]); // The snake's movement
void draw(int length, point foodAt, point body[], char map[][SIZE]); // drawing
void food(point * foodAt, point body[], int length, char map[][SIZE]); // Produce food
// Stack related operations
point * pop(queue *queue); // Retrieves the first entry point from the queue. Returns the pointer to the fetch point. Fails to retrieve NULL
void push(point *point, queue *queue); // Push into the queue
int main()
{
char map[SIZE][SIZE]; // Define the map
point body[MAX_LENGTH], foodAt; // The entire body and food of the snake ( body The first of an array of 1 Is the head of the snake)
int length; // The actual length of the snake
int dir; // Direction of travel
int rate = 1; // Travel rate
int result; // Preserve the results of the snake movement: [death], [score], [none]
init(&length, &foodAt, &dir, body, map); // Initialize the
while (1)
{
Sleep(100 / rate);
//dir = getDir(dir); // Gets the snake's direction of travel
dir = getAIDir(dir, length, body, foodAt); // To obtain AI Judged the direction of travel
result = move(foodAt, dir, length, body); // The snake's movement
if (result == 1) // If you eat food
{
length++;
rate = length / 3;
if (length == MAX_LENGTH)
{
printf(" You have cleared the customs! ");
break;
}
food(&foodAt, body, length, map); // Produce food
}
draw(length, foodAt, body, map); // drawing
if (result == -1) // If death
{
break;
}
}
Sleep(500);
printf(" Failure. This time the score is %d ", (length - 3) * 100);
system("pause");
}
void init(int * length, point * foodAt, int * dir, point body[], char map[][SIZE]) // Initialize the
{
memset(map, '*', SIZE * SIZE); // Initialization map
body[0].r = 3, body[0].c = 2; // Initialize the snake's body
body[1].r = 2, body[1].c = 2;
body[2].r = 1, body[2].c = 2;
*length = 3; // The initial length is 3
*dir = 2; // Initial downward direction
food(foodAt, body, *length, map); // Produce food
draw(*length, *foodAt, body, map); // drawing
printf(" Press any key to start. Use ASDW Control the direction, ESC suspended \n");
_getch();
srand((unsigned)time(NULL)); // Generate random number seeds, spare
stdOutput = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the standard output handle
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(stdOutput, &cci);
COORD coord = { 0, SIZE * 2 + 3 };
}
int getDir(int dir) // Gets the snake's direction of travel, specifying the return value 0 It stands for up, 1 That's to the right, 2 Is for down, 3 On behalf of the left
{
char key;
int newDir = dir;
if (_kbhit())
{
key = _getch();
switch (key)
{
case 'A': case 'a': newDir = 3; break;
case 'S': case 's': newDir = 2; break;
case 'D': case 'd': newDir = 1; break;
case 'W': case 'w': newDir = 0; break;
case 27: _getch(); break;
}
}
if (newDir - dir == 2 || newDir - dir == -2) // Snakes can't reverse
{
newDir = dir;
}
return newDir;
}
int getAIDir(int dir, int length, point body[], point foodAt) // To obtain AI Judged the direction of travel
{
static int *shortestPathDir, count = 0; // Save the direction of the shortest path (in reverse order, that is, go first in the direction behind)
if (count == 0) // If the shortest path has not been generated, then regenerate
{
int map_of_steps[SIZE][SIZE]; // Save to arrive at some on the map 1 The minimum number of steps in a point
queue queue = { 0,0 };
point *last_body = (point *)malloc(length * sizeof(point)); // Save the body position of the snake during the calculation
point *next_body; // Save the 1 The body of the secondary snake
point next_point;
int i, step = 0;
point moveTo;
memcpy(last_body, body, length * sizeof(point));
memset(map_of_steps, 0, SIZE * SIZE * sizeof(int));
// Put an initial into the queue body
push(last_body, &queue);
push(NULL, &queue); // insert NULL To identify a width-first search 1 The end of the floor
step++; // with step To represent the number of steps, and also the number of layers
while (queue.num != 0)
{
last_body = pop(&queue);
if (last_body == NULL) // If a 1 End of the floor
{
if (queue.num != 0) // If there are any more 1 Layer of the element
{
step++;
push(NULL, &queue); // Insert the 1 The end of the layer
continue;
}
else
{
break;
}
}
for (i = 0; i < 4; i++) // Detection respectively 4 Can I move in one direction or another
{
switch (i)
{
case 0: moveTo.r = last_body[0].r - 1, moveTo.c = last_body[0].c; break;
case 1: moveTo.r = last_body[0].r, moveTo.c = last_body[0].c + 1; break;
case 2: moveTo.r = last_body[0].r + 1, moveTo.c = last_body[0].c; break;
case 3: moveTo.r = last_body[0].r, moveTo.c = last_body[0].c - 1; break;
}
if (moveable(moveTo, length, last_body) && map_of_steps[moveTo.r][moveTo.c] == 0) // If you're moving to a point that you haven't moved to before
// (that is, the current path is the shortest path to the point), and the point is moveable the
{
map_of_steps[moveTo.r][moveTo.c] = step;
if (moveTo.r == foodAt.r && moveTo.c == foodAt.c) // If the 1 You can reach the point where the food is
{
// First, free1 Some useless dynamic memory
free(last_body);
while (queue.num != 0)
{
free(pop(&queue));
}
goto outer; // Jump out of the loop
}
// generate next_body And push it into the queue
next_body = (point *)malloc(length * sizeof(point));
for (i = length - 1; i > 0; i--) // Move the snake's position
{
next_body[i] = body[i - 1];
}
next_body[0] = moveTo; // in 1 size
push(next_body, &queue);// Push the queue
}
}
//free1 Some useless dynamic memory
free(last_body);
}
outer:;
if (map_of_steps[foodAt.r][foodAt.c] == 0) // If you cannot reach the point where the food is, follow the same path until you die
{
return dir;
}
// generate shortestPath
shortestPathDir = (int *)malloc(step * sizeof(int));
count = step;
next_point = foodAt;
for (i = 0; i < step - 1; i++) // using map_of_steps And the lower 1 The point is extrapolated to the top 1 Point to the next 1 The direction of the dot dir
{
if (next_point.r + 1 < SIZE && map_of_steps[next_point.r][next_point.c] ==
map_of_steps[next_point.r + 1][next_point.c] + 1)
{
shortestPathDir[i] = 0;
next_point.r += 1;
}
else if (next_point.c - 1 >= 0 && map_of_steps[next_point.r][next_point.c] ==
map_of_steps[next_point.r][next_point.c - 1] + 1)
{
shortestPathDir[i] = 1;
next_point.c -= 1;
}
else if (next_point.r - 1 >= 0 && map_of_steps[next_point.r][next_point.c] ==
map_of_steps[next_point.r - 1][next_point.c] + 1)
{
shortestPathDir[i] = 2;
next_point.r -= 1;
}
else
{
shortestPathDir[i] = 3;
next_point.c += 1;
}
}
// The first 1 Step must be judged separately (because map_of_steps The value of 0 It could be the head of a snake or the body of a snake, which would treat the snake 1 Step direction judgment produces interference)
if (body[0].r > next_point.r)
{
shortestPathDir[step - 1] = 0;
}
else if (body[0].r < next_point.r)
{
shortestPathDir[step - 1] = 2;
}
else if (body[0].c > next_point.c)
{
shortestPathDir[step - 1] = 3;
}
else
{
shortestPathDir[step - 1] = 1;
}
/*printf("\n\n\n");
int j;
for (i = 0; i < SIZE; i++)
{
for (j = 0; j < SIZE; j++)
{
printf("%3d", map_of_steps[i][j]);
}
printf("\n");
}
printf("\n");*/
}
// Go along the shortest path
return shortestPathDir[--count];
}
int moveable(point moveTo, int length, point body[]) // Determine if you can move to moveTo Can point, 1 , can't 0
{
int i;
for (i = 0; i < length - 1; i++)
{
if (moveTo.r == body[i].r && moveTo.c == body[i].c)
{
return 0;
}
}
if (moveTo.r < 0 || moveTo.r >= SIZE || moveTo.c < 0 || moveTo.c >= SIZE) // If you go beyond the boundary
{
return 0;
}
return 1;
}
int move(point foodAt, int dir, int length, point body[]) // Snake movement, specifying the return value -1 Is for death, 0 That means no food, 1 It's for eating food
{
int i, flag = 0;
point head = body[0];
switch (dir)
{
case 0: head.r -= 1; break;
case 1: head.c += 1; break;
case 2: head.r += 1; break;
case 3: head.c -= 1; break;
}
if (head.r < 0 || head.r >= SIZE || head.c < 0 || head.c >= SIZE) // Death is out of bounds
{
return -1;
}
for (i = 0; i < length - 1; i++)
{
if (head.r == body[i].r && head.c == body[i].c) // He bit himself to death
{
return -1;
}
}
if (head.r == foodAt.r && head.c == foodAt.c) // Eat the food
{
length++;
flag = 1; // tag 1 , and the return value is 1
}
for (i = length - 1; i > 0; i--) // Move the snake's position
{
body[i] = body[i - 1];
}
body[0] = head; // in 1 size
if (flag == 1)
{
return 1;
}
return 0;
}
void draw(int length, point foodAt, point body[], char map[][SIZE]) // drawing
{
static char bitmap[SIZE + 2][SIZE + 2]; // define 1 An array to draw the map's background, borders, snakes, and food
int i, j;
for (i = 0; i < SIZE; i++) // background
{
for (j = 0; j < SIZE; j++)
{
bitmap[i + 1][j + 1] = map[i][j];
}
}
// A border
bitmap[0][0] = '0', bitmap[0][SIZE + 1] = '1';
bitmap[SIZE + 1][0] = '2', bitmap[SIZE + 1][SIZE + 1] = '3';
for (i = 0; i < SIZE; i++)
{
bitmap[0][i + 1] = '4', bitmap[SIZE + 1][i + 1] = '4';
bitmap[i + 1][0] = '5', bitmap[i + 1][SIZE + 1] = '5';
}
bitmap[foodAt.r + 1][foodAt.c + 1] = 'f'; // food
bitmap[body[0].r + 1][body[0].c + 1] = 'h'; // The snake
for (i = 1; i < length; i++) // Snake-body.
{
bitmap[body[i].r + 1][body[i].c + 1] = 'b';
}
COORD coord = { 0, 0 }; // coordinates 0 . 0
SetConsoleCursorPosition(stdOutput, coord); // Set the cursor to 0 . 0 location
for (i = 0; i < SIZE + 2; i++)
{
for (j = 0; j < SIZE + 2; j++)
{
switch (bitmap[i][j])
{
case 'f': printf(" u "); break;
case 'b': printf(" low "); break;
case 'h': printf(" a. "); break;
case '0': printf(" ┏ "); break;
case '1': printf(" ━ ┓ "); break;
case '2': printf(" ┗ "); break;
case '3': printf(" ━ ┛ "); break;
case '4': printf(" ━ "); break;
case '5': printf(" ┃ "); break;
default: printf(" ");
}
}
printf("\n");
}
}
void food(point * foodAt, point body[], int length, char map[][SIZE]) // Produce food
{
int i;
while (1)
{
foodAt->r = rand() % SIZE, foodAt->c = rand() % SIZE; // Randomly generate food locations
for (i = 0; i < length; i++)
{
if (foodAt->r == body[i].r && foodAt->c == body[i].c) // If the position is on the snake's body
{
goto retry;
}
}
break;
retry:;
}
}
// Queue-dependent functions
point * pop(queue *queue) // Gets out of the queue and returns a pointer to the fetch point
{
queue->num--;
if (queue->first_in_pos == 5 * SIZE - 1) // Returns the first 1 Enter the point of the queue and put the variable fist_in_pos change
{
queue->first_in_pos = 0;
return queue->body[5 * SIZE - 1];
}
else
{
return queue->body[queue->first_in_pos++];
}
}
void push(point * body, queue *queue)
{
if (queue->num == 0) // If the queue is empty
{
queue->num++;
queue->first_in_pos = 0; // Will be the first 1 The queue entry location is set to 0
queue->body[queue->first_in_pos] = body;
}
else // Otherwise, insert the queue
{
if (queue->first_in_pos + queue->num > 5 * SIZE - 1)
{
queue->body[queue->first_in_pos + queue->num++ - 5 * SIZE] = body;
}
else
{
queue->body[queue->first_in_pos + queue->num++] = body;
}
}
}
More interesting classic games to realize the special topic, to share with you:
C++ classic game summary
python classic game summary
python Tetris game collection
JavaScript classic games don't stop playing
java classic game summary
javascript classic game summary