#include #include #include #include #include #include "game.h" #include "snake.h" #define GAME_SPEED 100000 // microseconds between steps struct state* init_game() { struct state* state = (struct state*)malloc(sizeof(struct state)); if (state == NULL) { return NULL; } // Get screen dimensions int max_x, max_y; getmaxyx(stdscr, max_y, max_x); state->width = max_x - 2; state->height = max_y - 3; // Initialize snake in the center state->snake = NULL; int center_x = state->width / 2; int center_y = state->height / 2; // Add 5 initial snake parts (head is added last) state->snake = add_snake(state->snake, center_x, center_y); state->snake = add_snake(state->snake, center_x, center_y + 1); state->snake = add_snake(state->snake, center_x, center_y + 2); state->snake = add_snake(state->snake, center_x, center_y + 3); state->snake = add_snake(state->snake, center_x, center_y + 4); // Initialize velocity state->sx = 1; // Moving right state->sy = 0; // Initialize food randomly srand((unsigned int)time(NULL)); for (int i = 0; i < FOOD_COUNT; i++) { state->foodx[i] = rand() % state->width; state->foody[i] = rand() % state->height; } return state; } void render_game(struct state* state) { if (state == NULL) { return; } // Clear the screen clear(); // Draw border for (int x = 0; x < state->width + 2; x++) { mvaddch(0, x, '+'); mvaddch(state->height + 1, x, '+'); } for (int y = 0; y < state->height + 2; y++) { mvaddch(y, 0, '+'); mvaddch(y, state->width + 1, '+'); } // Draw food for (int i = 0; i < FOOD_COUNT; i++) { if (state->foodx[i] >= 0 && state->foody[i] >= 0) { mvaddch(state->foody[i] + 1, state->foodx[i] + 1, '*'); } } // Draw snake struct snake* current = state->snake; while (current != NULL) { if (current->x >= 0 && current->x < state->width && current->y >= 0 && current->y < state->height) { mvaddch(current->y + 1, current->x + 1, 'x'); } current = current->next; } // Draw info line int food_count = 0; for (int i = 0; i < FOOD_COUNT; i++) { if (state->foodx[i] >= 0 && state->foody[i] >= 0) { food_count++; } } int snake_length = 0; current = state->snake; while (current != NULL) { snake_length++; current = current->next; } mvprintw(state->height + 2, 0, "Food: %d Snake Length: %d Speed: (%d, %d)", food_count, snake_length, state->sx, state->sy); refresh(); } int handle_input(struct state* state) { int ch = getch(); if (ch == ERR) { return 0; // No input } switch (ch) { case 'q': case 'Q': return 1; // Quit case KEY_UP: if (state->sy == 0) { // Don't allow reversing state->sx = 0; state->sy = -1; } break; case KEY_DOWN: if (state->sy == 0) { // Don't allow reversing state->sx = 0; state->sy = 1; } break; case KEY_LEFT: if (state->sx == 0) { // Don't allow reversing state->sx = -1; state->sy = 0; } break; case KEY_RIGHT: if (state->sx == 0) { // Don't allow reversing state->sx = 1; state->sy = 0; } break; } return 0; } void cleanup_game(struct state* state) { if (state != NULL) { free_snake(state->snake); free(state); } } void run_game() { // Initialize ncurses initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); nodelay(stdscr, TRUE); curs_set(0); // Hide cursor struct state* game = init_game(); if (game == NULL) { endwin(); return; } int game_over = 0; int end_reason = 0; while (!game_over) { // Handle input if (handle_input(game)) { break; // User quit } // Update game state end_reason = step_state(game); if (end_reason != END_CONTINUE) { game_over = 1; } // Render render_game(game); // Delay usleep(GAME_SPEED); } // Show end game message if (game_over) { const char* message = ""; switch (end_reason) { case END_WALL: message = "GAME OVER: Hit wall! Press any key to exit..."; break; case END_SNAKE: message = "GAME OVER: Snake bit itself! Press any key to exit..."; break; case END_FOOD: message = "VICTORY: All food eaten! Press any key to exit..."; break; case END_USER: message = "Game ended. Press any key to exit..."; break; default: message = "Game ended. Press any key to exit..."; } mvprintw(game->height / 2, 5, "%s", message); refresh(); nodelay(stdscr, FALSE); getch(); } // Cleanup cleanup_game(game); endwin(); }