#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
#define R 15
#define C 29
#define DIM (R - 2) * (C - 2)
#define START_LENGTH 3
#define DIM_OBSTACLE 31
#define BITE 3
#define SOUND 7
#define BLOCK 79
#define UL 201
#define UR 187
#define DL 200
#define DR 188
#define HOR 205
#define VER 186
#define CROSS 206
#define UL_THROUGH 218
#define UR_THROUGH 191
#define DL_THROUGH 192
#define DR_THROUGH 217
#define HOR_THROUGH 196
#define VER_THROUGH 179
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
COORD coord_obstacle[DIM_OBSTACLE] = {{ 3, R / 2}, { 4, R / 2}, { 5, R / 2}, { 6, R / 2}, { 7, R / 2}, { 8, R / 2}, { 9, R / 2},
{10, R / 2}, {11, R / 2}, {12, R / 2}, {13, R / 2}, {15, R / 2}, {16, R / 2}, {17, R / 2},
{18, R / 2}, {19, R / 2}, {20, R / 2}, {21, R / 2}, {22, R / 2}, {23, R / 2}, {24, R / 2},
{25, R / 2}, {C / 2, 3}, {C / 2, 4}, {C / 2, 5}, {C / 2, 6}, {C / 2, 8}, {C / 2, 9},
{C / 2, 10}, {C / 2, 11}, {C / 2, R / 2}};
int char_obstacle[DIM_OBSTACLE] = {HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR, HOR,
HOR, HOR, HOR, HOR, VER, VER, VER, VER, VER, VER, VER, VER, CROSS};
void set_position(const COORD xy)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), xy);
}
void delay(const int ms)
{
clock_t goal = ms * CLOCKS_PER_SEC / 1000 + clock();
while(goal > clock());
}
int get_input(const int direction)
{
return getch() == 224 ? getch() : direction;
}
void choose_settings(int *through, int *obstacle)
{
char c;
do
{
printf("THROUGH MODE (y/n) --> ");
scanf(" %c", &c);
}
while(c != 'y' && c != 'n');
*through = c == 'y';
do
{
printf("OBSTACLES (y/n) --> ");
scanf(" %c", &c);
}
while(c != 'y' && c != 'n');
*obstacle = c == 'y';
system("CLS");
}
void initialize_grid(int grid[R][C])
{
for(unsigned int i = 1; i < R - 1; ++i)
{
for(unsigned int j = 1; j < C - 1; grid[i][j++] = 1);
}
}
void print_and_apply_border(int grid [R][C], const int through)
{
printf("%c", through ? UL_THROUGH : UL);
for(unsigned int i = 0; i < C - 2; ++i)
{
printf("%c", through ? HOR_THROUGH : HOR);
}
printf("%c\n", through ? UR_THROUGH : UR);
for(unsigned int i = 0; i < R - 2; ++i)
{
printf("%c", through ? VER_THROUGH : VER);
set_position((COORD){C - 1, i + 1});
printf("%c\n", through ? VER_THROUGH : VER);
}
printf("%c", through ? DL_THROUGH : DL);
for(unsigned int i = 0; i < C - 2; ++i)
{
printf("%c", through ? HOR_THROUGH : HOR);
}
printf("%c\n", through ? DR_THROUGH : DR);
if(!through)
{
for(unsigned int j = 0; j < C; ++j)
{
grid[0][j] = grid[R - 1][j] = 0;
}
for(unsigned int i = 1; i < R - 1; ++i)
{
grid[i][0] = grid[i][C - 1] = 0;
}
}
}
void print_and_apply_snake(int grid[R][C], const COORD *snake)
{
for(unsigned int i = 0; i < START_LENGTH; ++i)
{
set_position(snake[i]);
printf("%c", BLOCK);
grid[snake[i].Y][snake[i].X] = 0;
}
}
void print_and_apply_obstacle(int grid[R][C])
{
for(unsigned int i = 0; i < DIM_OBSTACLE; ++i)
{
set_position(coord_obstacle[i]);
printf("%c", char_obstacle[i]);
grid[coord_obstacle[i].Y][coord_obstacle[i].X] = 0;
}
}
void print_score(const unsigned int score)
{
set_position((COORD){C + 3, 1});
printf("SCORE: %u", score);
}
void generate_bite(int grid[R][C], const unsigned int score, const int obstacle)
{
unsigned int r = rand() % (DIM - score / 10 - START_LENGTH - obstacle * DIM_OBSTACLE) + 1;
for(unsigned int i = 1; i < R - 1; ++i)
{
for(unsigned int j = 1; j < C - 1; ++j)
{
if(!(r -= grid[i][j] == 1))
{
grid[i][j] = 2;
set_position((COORD){j, i});
printf("%c", BITE);
return;
}
}
}
}
void define_direction(int *direction, const int input)
{
if((*direction == UP || *direction == DOWN) && (input == LEFT || input == RIGHT) || (*direction == LEFT || *direction == RIGHT) && (input == UP || input == DOWN))
{
*direction = input;
}
}
int snake_update(int grid[R][C], COORD *snake, COORD **tail, COORD **head, unsigned int *score, const int obstacle, const int direction, const int through)
{
COORD temp = **head;
*head = *head == snake + DIM - 1 ? snake : *head + 1;
**head = temp;
switch(direction)
{
case UP: (*head)->Y = through && (*head)->Y == 1 ? R - 2 : (*head)->Y - 1; break;
case DOWN: (*head)->Y = through && (*head)->Y == R - 2 ? 1 : (*head)->Y + 1; break;
case LEFT: (*head)->X = through && (*head)->X == 1 ? C - 2 : (*head)->X - 1; break;
case RIGHT: (*head)->X = through && (*head)->X == C - 2 ? 1 : (*head)->X + 1;
}
if(grid[(*head)->Y][(*head)->X])
{
if(grid[(*head)->Y][(*head)->X] == 1)
{
grid[(*tail)->Y][(*tail)->X] = 1;
set_position(**tail);
printf(" ");
*tail = *tail == snake + DIM - 1 ? snake : *tail + 1;
}
else
{
*score += 10;
printf("%c", SOUND);
print_score(*score);
generate_bite(grid, *score, obstacle);
}
grid[(*head)->Y][(*head)->X] = 0;
set_position(**head);
printf("%c", BLOCK);
return 1;
}
return 0;
}
int main()
{
srand(time(0));
int grid[R][C];
int through;
int obstacle;
int direction = RIGHT;
unsigned int score = 0;
COORD snake[DIM] = {{2, R / 4}, {3, R / 4}, {4, R / 4}};
COORD *tail = snake;
COORD *head = snake + START_LENGTH - 1;
choose_settings(&through, &obstacle);
initialize_grid(grid);
print_and_apply_border(grid, through);
print_and_apply_snake(grid, snake);
print_score(score);
if(obstacle)
{
print_and_apply_obstacle(grid);
}
generate_bite(grid, score, obstacle);
set_position((COORD){0, R + 1});
printf("Press any key to start.\n");
define_direction(&direction, get_input(direction));
set_position((COORD){0, R + 1});
printf(" ");
do
{
delay(220);
if(kbhit())
{
define_direction(&direction, get_input(direction));
}
}
while(snake_update(grid, snake, &tail, &head, &score, obstacle, direction, through));
set_position((COORD){0, R + 1});
printf("GAME OVER!\n");
return 0;
}