-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnake.cpp
389 lines (346 loc) · 11.5 KB
/
snake.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
#include <cstdlib>
#include <ctime>
#include <ncurses.h>
#include <unistd.h>
// TODO:Organize code and improve efficiency
#define HEIGHT 50
#define WIDTH 100
// Declare functions to link later
void input(WINDOW *win, int &dirY, int &dirX, char tailY[], char tailX[],
int &posY, int &posX, bool &gameover);
void logic(int &foodY, int &foodX, int posY, int posX, char tailY[],
char tailX[], unsigned int &score, int &length, bool &gameover,
bool &appleEaten);
void draw(WINDOW *win, WINDOW *text, int posY, int posX, int length,
char tailY[], char tailX[], int foodY, int foodX, unsigned int score,
struct phrases phrases, bool &appleEaten);
// Snake phrases
struct phrases {
// Eaten apple
char apple1[7] = {"Yummy!"};
char apple2[25] = {"Anoother oneee~ pleease~"};
char apple3[11] = {"Soo tasty!"};
char apple4[12] = {"Keep it up!"};
char apple5[10] = {"Delicious"};
char apple6[33] = {"Best apple ever eaten in my life"};
// Gameover
char gameover1[8] = {"Ouch..."};
char gameover2[16] = {"AHII, MY TAIL!?"};
} phrases;
int main() {
// Set random time seed
srand(time(NULL));
// Inizialize screen
initscr();
if (!has_colors()) {
printw("Terminal doesn't support colors!");
getch();
return -1;
}
start_color();
/*
1. Stop when ^C is pressed
2. Don't echo getch charaters
3. Disble cursor
*/
cbreak();
noecho();
curs_set(0);
// Inizialize new windows
WINDOW *win = newwin(HEIGHT, WIDTH, 0, 70);
WINDOW *text = newwin(HEIGHT, WIDTH, HEIGHT, 70);
/*
1. Enable keys such as arrow keys, ...
2. Make so getch is a non-blocking call
*/
keypad(win, true);
nodelay(win, false);
// Refresh the main screen
refresh();
// Create color pairs
init_pair(1, COLOR_MAGENTA, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_RED, COLOR_BLACK);
// Main menu loop
while (true) {
// Set wgetch a blocking call
nodelay(win, false);
// Clear window screen
wclear(win);
wclear(text);
// Draw a box
wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
// Ascii art
// Copyright (c) Jennifer E. Swofford
mvwaddstr(win, 1, 0, R"(
__ __ __ __
/ \ / \ / \ / \
____________________________________/ __\/ __\/ __\/ __\_______________________________________
___________________________________/ /__/ /__/ /__/ /__________________________________________
| / \ / \ / \ / \ \____
|/ \_/ \_/ \_/ \ o \
\_____/--<
)");
mvwaddstr(win, 10, 0, R"(
ad88888ba 88
d8" "8b 88
Y8, 88
`Y8aaaaa, 8b,dPPYba, ,adPPYYba, 88 ,d8 ,adPPYba,
`"""""8b, 88P' `"8a "" `Y8 88 ,a8" a8P_____88
`8b 88 88 ,adPPPPP88 8888[ 8PP"""""""
Y8a a8P 88 88 88, ,88 88`"Yba, "8b, ,aa
"Y88888P" 88 88 `"8bbdP"Y8 88 `Y8a `"Ybbd8"'
)");
// Menu entries
mvwprintw(win, (HEIGHT / 2), ((WIDTH / 2) - 7), "1 -> New Game");
mvwprintw(win, ((HEIGHT / 2) + 1), ((WIDTH / 2) - 7), "q -> Quit");
// Refresh window
wrefresh(win);
wrefresh(text);
// TODO: Full menu
int pressed = wgetch(win);
switch (pressed) {
case 'q':
return 0;
case 27:
return 0;
case '2': // Leaadboards
case '1':
// Tutorial
mvwaddstr(win, (HEIGHT / 2), ((WIDTH / 2) - 7), " How To Play:");
mvwaddstr(
win, ((HEIGHT / 2) + 1), ((WIDTH / 2) - 31),
"1) Push *ONE TIME* any of the arrow keys to move the snake head.");
mvwaddstr(win, ((HEIGHT / 2) + 2), ((WIDTH / 2) - 25),
"The movment is secured so you can't go to the opposite");
mvwaddstr(win, ((HEIGHT / 2) + 3), ((WIDTH / 2) - 15),
"direction of where you're going.");
mvwaddstr(win, ((HEIGHT / 2) + 5), ((WIDTH / 2) - 22),
"2) You can always quit the game by pressing 'q'");
mvwaddstr(win, ((HEIGHT / 2) + 7), ((WIDTH / 2) - 12),
"3) Hit you tail and it's");
wattrset(win, COLOR_PAIR(3));
mvwaddstr(win, ((HEIGHT / 2) + 9), ((WIDTH / 2) - 4), "GAMEOVER");
wattroff(win, COLOR_PAIR(3));
wgetch(win);
// Declare and define variables
int posY = HEIGHT / 2;
int posX = WIDTH / 2;
int foodY = rand() % (HEIGHT - 2) + 1;
int foodX = rand() % (WIDTH - 2) + 1;
int dirY = 0;
int dirX = 1;
unsigned int sleepTime = 100000;
unsigned int score = 0;
int length = 0;
char tailY[(HEIGHT - 2) * (WIDTH - 2) + 1];
char tailX[(WIDTH - 2) * (HEIGHT - 2) + 1];
bool gameover = false;
bool appleEaten = false;
// Set wgetch a non-blockable call
nodelay(win, true);
// Main game loop
while (!gameover) {
// Clear window screen
wclear(win);
// Handle input
input(win, dirY, dirX, tailY, tailX, posY, posX, gameover);
// Handle game logic
logic(foodY, foodX, posY, posX, tailY, tailX, score, length, gameover,
appleEaten);
// Handle game UI
draw(win, text, posY, posX, length, tailY, tailX, foodY, foodX, score,
phrases, appleEaten);
// Difficulty meter
if (length < 10) {
sleepTime = 150000;
}
if (length >= 10 and length < 20) {
sleepTime = 100000;
}
if (length >= 20 and length < 30) {
sleepTime = 75000;
}
if (length >= 30) {
sleepTime = 50000;
}
// Prevent the terminal from buffering
usleep(sleepTime);
}
mvwprintw(win, (HEIGHT / 2), ((WIDTH / 2) - 5), "Game Over");
mvwprintw(win, ((HEIGHT / 2) + 2), ((WIDTH / 2) - 6), "Score:%d", score);
wrefresh(win);
wclear(text);
int n = rand() % 2 + 1;
wattron(text, COLOR_PAIR(2));
switch (n) {
case 1:
mvwprintw(text, 3, 25, "%s", phrases.gameover1);
case 2:
mvwprintw(text, 3, 25, "%s", phrases.gameover2);
};
wattroff(text, COLOR_PAIR(2));
// Noo, snaky!! ;(
wattron(text, COLOR_PAIR(1));
mvwaddstr(text, 0, 1, " /^\\/^\\ ");
mvwaddstr(text, 1, 1, " _|__| X| ");
mvwaddstr(text, 2, 1, " /~ \\_/ \\ ");
mvwaddstr(text, 3, 1, " ____|__________ \\ ");
mvwaddstr(text, 4, 1, " / \\_______ \\ \\ ");
mvwaddstr(text, 5, 1, " `\\ \\ ");
mvwaddstr(text, 5, 1, " | | ");
wattroff(text, COLOR_PAIR(1));
wrefresh(text);
getch();
break;
}
usleep(100000);
}
// Close the main window and screen aand end the program
endwin();
return 0;
}
void input(WINDOW *win, int &dirY, int &dirX, char tailY[], char tailX[],
int &posY, int &posX, bool &gameover) {
// Get window input as character
int pressed = wgetch(win);
// Movement logic
if (pressed == KEY_LEFT and dirX != 1) {
dirY = 0;
dirX = -1;
}
if (pressed == KEY_RIGHT and dirX != -1) {
dirY = 0;
dirX = 1;
}
if (pressed == KEY_UP and dirY != 1) {
dirY = -1;
dirX = 0;
}
if (pressed == KEY_DOWN and dirY != -1) {
dirY = 1;
dirX = 0;
}
if (pressed == 'q') {
gameover = true;
}
tailY[0] = posY;
tailX[0] = posX;
posY += dirY;
posX += dirX;
// Teleport snake when it suprass the window borders
if (posY >= HEIGHT - 1) {
posY = 1;
}
if (posY <= 0) {
posY = HEIGHT - 1;
}
if (posX >= WIDTH - 1) {
posX = 1;
}
if (posX <= 0) {
posX = WIDTH - 1;
}
}
void logic(int &foodY, int &foodX, int posY, int posX, char tailY[],
char tailX[], unsigned int &score, int &length, bool &gameover,
bool &appleEaten) {
// Generate new apple when last one has been ate
if (foodY == posY and foodX == posX) {
foodY = rand() % (HEIGHT - 2) + 1;
foodX = rand() % (WIDTH - 2) + 1;
score += 120;
length += 1;
appleEaten = true;
}
// Make the apple spawn on the map and not on the snake tail
for (int i = length; i != 0; i--) {
if (foodY == tailY[i] and foodX == tailX[i]) {
foodY = rand() % (HEIGHT - 2) + 1;
foodX = rand() % (WIDTH - 2) + 1;
}
}
// Check for gameover
for (int i = length; i != 0; i--) {
if (posY == tailY[i] and posX == tailX[i]) {
gameover = true;
}
}
}
void draw(WINDOW *win, WINDOW *text, int posY, int posX, int length,
char tailY[], char tailX[], int foodY, int foodX, unsigned int score,
struct phrases phrases, bool &appleEaten) {
// Set colors and print chaarachers on the window box
wattrset(win, COLOR_PAIR(1));
mvwaddstr(win, posY, posX, "*");
wattrset(win, COLOR_PAIR(2));
for (int i = length; i != 0; i--) {
tailY[i] = tailY[i - 1];
tailX[i] = tailX[i - 1];
mvwaddstr(win, tailY[i], tailX[i], "*");
}
wattrset(win, COLOR_PAIR(3));
mvwaddstr(win, foodY, foodX, "@");
wattroff(win, COLOR_PAIR(3));
// Draw the min box with the text in the appropiate windows
box(win, 0, 0);
mvwprintw(win, 0, (WIDTH / 2) - 8, "Welcome to snake!");
if (appleEaten) {
int n = rand() % 6 + 1;
wclear(text);
wattron(text, COLOR_PAIR(2));
switch (n) {
case 1:
mvwprintw(text, 3, 25, "%s", phrases.apple1);
break;
case 2:
mvwprintw(text, 3, 25, "%s", phrases.apple2);
break;
case 3:
mvwprintw(text, 3, 25, "%s", phrases.apple3);
break;
case 4:
mvwprintw(text, 3, 25, "%s", phrases.apple4);
break;
case 5:
mvwprintw(text, 3, 25, "%s", phrases.apple5);
break;
case 6:
mvwprintw(text, 3, 25, "%s", phrases.apple6);
break;
}
wattroff(text, COLOR_PAIR(2));
appleEaten = false;
};
// Hi snaky!
wattrset(text, COLOR_PAIR(1));
mvwaddstr(text, 0, 1, " /^\\/^\\ ");
mvwaddstr(text, 1, 1, " _|__| O| ");
mvwaddstr(text, 2, 1, "\\/ /~ \\_/ \\ ");
mvwaddstr(text, 3, 1, " \\____|__________/ \\ ");
mvwaddstr(text, 4, 1, " \\_______ \\ ");
mvwaddstr(text, 5, 1, " `\\ \\ ");
mvwaddstr(text, 5, 1, " | | ");
wattroff(text, COLOR_PAIR(1));
wattrset(text, COLOR_PAIR(3));
mvwaddstr(text, 1, 65, "@");
wattroff(text, COLOR_PAIR(3));
mvwprintw(text, 1, 67, "-> X: %d", foodX);
wattrset(text, COLOR_PAIR(3));
mvwaddstr(text, 2, 65, "@");
wattroff(text, COLOR_PAIR(3));
mvwprintw(text, 2, 67, "-> Y: %d", foodY);
wattrset(text, COLOR_PAIR(1));
mvwaddstr(text, 1, 85, "*");
wattroff(text, COLOR_PAIR(1));
mvwprintw(text, 1, 87, "-> X: %d", posX);
wattrset(text, COLOR_PAIR(1));
mvwaddstr(text, 2, 85, "*");
wattroff(text, COLOR_PAIR(1));
mvwprintw(text, 2, 87, "-> Y: %d", posY);
mvwprintw(text, 0, 65, "Apples: %d", score / 120);
mvwprintw(text, 0, 85, "Score: %d", score);
// Refresh windows
wrefresh(win);
wrefresh(text);
}