Skip to content

Commit ef9d5a3

Browse files
committed
Add Snake game implementation in C
1 parent 74871c8 commit ef9d5a3

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

games/csnake.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <conio.h> // for _kbhit() and _getch() -> keyboard input
4+
#include <time.h> // for random food generation (using time as seed)
5+
#include <windows.h> // for system("cls") on Windows
6+
7+
// ==== Game Constants ====
8+
#define ROWS 25 // Number of rows in the game board
9+
#define COLS 25 // Number of columns in the game board
10+
#define MAX_LEN 256 // Maximum snake length
11+
12+
// ==== Global Variables ====
13+
14+
// Board matrix (ROWS x COLS)
15+
char board[ROWS][COLS];
16+
17+
// Game states
18+
int isgameover = 0; // Flag to end the game
19+
int eaten = 1; // Indicates if food has been eaten
20+
int snake_len = 1; // Initial snake length
21+
int dx = 1, dy = 0; // Initial direction (moving right)
22+
23+
// Snake head position (start from middle of board)
24+
int posx = ROWS / 2;
25+
int posy = COLS / 2;
26+
27+
// Snake body coordinates (a[i][0] -> row, a[i][1] -> col)
28+
int a[MAX_LEN][2];
29+
30+
// Food position
31+
int foodx, foody;
32+
33+
// Timing variables
34+
clock_t last = 0; // To track last move time
35+
int delay = 150; // Snake speed (milliseconds)
36+
37+
// ==== FUNCTIONS ====
38+
39+
// Draw empty board (borders = '*', inside = ' ')
40+
void draw_board() {
41+
for (int i = 0; i < ROWS; i++) {
42+
for (int j = 0; j < COLS; j++) {
43+
if (i == 0 || j == 0 || i == ROWS - 1 || j == COLS - 1) {
44+
board[i][j] = '*'; // Border
45+
} else {
46+
board[i][j] = ' '; // Empty space
47+
}
48+
}
49+
}
50+
}
51+
52+
// Place snake on board
53+
void snake() {
54+
// Shift body (move each segment to the previous segment’s position)
55+
for (int i = snake_len; i > 0; i--) {
56+
a[i][0] = a[i - 1][0];
57+
a[i][1] = a[i - 1][1];
58+
}
59+
60+
// Update head position
61+
a[0][0] = posx;
62+
a[0][1] = posy;
63+
64+
// Draw snake on board
65+
for (int k = 0; k < snake_len; k++) {
66+
if (k == 0)
67+
board[a[k][0]][a[k][1]] = '@'; // Snake head
68+
else
69+
board[a[k][0]][a[k][1]] = 'O'; // Snake body
70+
}
71+
}
72+
73+
// Print board to screen (with ANSI colors)
74+
void print_board() {
75+
fflush(stdout);
76+
printf("\033[H"); // Move cursor to top-left (instead of clearing screen)
77+
78+
for (int i = 0; i < ROWS; i++) {
79+
for (int j = 0; j < COLS; j++) {
80+
if (i == 0 || j == 0 || i == ROWS - 1 || j == COLS - 1)
81+
printf("\033[35m%c\033[0m", board[i][j]); // Purple border
82+
else if (i == foodx && j == foody)
83+
printf("\033[31m%c\033[0m", board[i][j]); // Red food
84+
else
85+
printf("\033[32m%c\033[0m", board[i][j]); // Green snake / empty
86+
}
87+
printf("\n");
88+
}
89+
}
90+
91+
// Update snake’s head position
92+
void transform(int x, int y) {
93+
posx += x;
94+
posy += y;
95+
}
96+
97+
// Handle keyboard input
98+
void input() {
99+
if (_kbhit()) { // Check if a key was pressed
100+
int m = _getch();
101+
102+
// Handle arrow keys (they come as two-byte sequence)
103+
if (m == 0 || m == 224) {
104+
int arrow = _getch(); // Get actual arrow code
105+
switch (arrow) {
106+
case 72: // Up
107+
if (dx != 1 || snake_len == 1) { dx = -1; dy = 0; }
108+
break;
109+
case 80: // Down
110+
if (dx != -1 || snake_len == 1) { dx = 1; dy = 0; }
111+
break;
112+
case 75: // Left
113+
if (dy != 1 || snake_len == 1) { dx = 0; dy = -1; }
114+
break;
115+
case 77: // Right
116+
if (dy != -1 || snake_len == 1) { dx = 0; dy = 1; }
117+
break;
118+
}
119+
} else {
120+
// WASD keys as alternative controls
121+
switch (m) {
122+
case 'w': if (dx != 1 || snake_len == 1) { dx = -1; dy = 0; } break;
123+
case 's': if (dx != -1 || snake_len == 1) { dx = 1; dy = 0; } break;
124+
case 'a': if (dy != 1 || snake_len == 1) { dx = 0; dy = -1; } break;
125+
case 'd': if (dy != -1 || snake_len == 1) { dx = 0; dy = 1; } break;
126+
case 'q': isgameover = 1; break; // Quit game
127+
}
128+
}
129+
}
130+
}
131+
132+
// Check collisions (walls or self)
133+
void collision() {
134+
// Check wall collision
135+
if (posx == ROWS - 1 || posx == 0 || posy == 0 || posy == COLS - 1) {
136+
isgameover = 1;
137+
}
138+
139+
// Check self collision
140+
for (int i = 1; i < snake_len; i++) {
141+
if (posx == a[i][0] && posy == a[i][1]) {
142+
isgameover = 1;
143+
}
144+
}
145+
}
146+
147+
// Generate food if needed
148+
void food() {
149+
if (eaten) {
150+
int max = ROWS - 2, min = 1;
151+
foodx = (rand() % (max - min + 1)) + min;
152+
foody = (rand() % (max - min + 1)) + min;
153+
eaten = 0; // Reset eaten flag
154+
}
155+
board[foodx][foody] = '#'; // Place food on board
156+
}
157+
158+
// Check if food is eaten
159+
void Eaten() {
160+
if (posx == foodx && posy == foody) {
161+
eaten = 1;
162+
snake_len++; // Increase length
163+
if (snake_len >= MAX_LEN) {
164+
printf("You won!\n");
165+
exit(0);
166+
}
167+
}
168+
}
169+
170+
// ==== MAIN FUNCTION ====
171+
int main() {
172+
int difficulty = 0;
173+
srand(time(NULL)); // Seed random number generator
174+
175+
// Show game instructions
176+
printf("========== Snake Game ==========\n");
177+
printf("Controls:\n");
178+
printf(" Arrow Keys or WASD to move\n");
179+
printf(" Press 'q' to quit\n\n");
180+
181+
// Difficulty selection
182+
printf("Choose Difficulty (1 = Easy, 2 = Medium, 3 = Hard): ");
183+
if (scanf("%d", &difficulty) != 1) {
184+
printf("Invalid input! Defaulting to Medium.\n");
185+
difficulty = 2;
186+
}
187+
188+
switch (difficulty) {
189+
case 1: delay = 125; break; // Easy
190+
case 2: delay = 100; break; // Medium
191+
case 3: delay = 50; break; // Hard
192+
default:
193+
printf("Invalid choice! Defaulting to Medium.\n");
194+
delay = 100;
195+
break;
196+
}
197+
system("cls"); // Clear screen
198+
199+
// Hide cursor for smooth rendering
200+
printf("\033[?25l");
201+
202+
last = clock(); // Start timer
203+
204+
// Move cursor to top-left
205+
printf("\033[H");
206+
207+
// ==== Game Loop ====
208+
while (!isgameover) {
209+
input(); // Handle input
210+
211+
clock_t now = clock();
212+
// Move snake after a delay (speed control)
213+
if ((now - last) * 1000 / CLOCKS_PER_SEC >= delay) {
214+
transform(dx, dy); // Move snake
215+
Eaten(); // Check if food eaten
216+
collision(); // Check collisions
217+
last = now; // Reset timer
218+
219+
draw_board(); // Redraw board
220+
snake(); // Draw snake
221+
food(); // Place food
222+
print_board(); // Display board
223+
}
224+
}
225+
226+
// Restore cursor
227+
printf("\033[?25h");
228+
printf("Game Over!\n");
229+
return 0;
230+
}

0 commit comments

Comments
 (0)