#include #include #include #include #include "world.h" #include "game.h" // Helper function to get a random position within bounds // Returns 1 if position is valid, 0 if we can't find a distinct position static int get_random_position(int* x, int* y, int width, int height, int cat_x, int cat_y, int* existing_x, int* existing_y, int existing_count) { // Leave 1 cell for border int min_x = 1; int max_x = width - 2; int min_y = 1; int max_y = height - 2; int attempts = 0; while (attempts < 100) { *x = min_x + rand() % (max_x - min_x + 1); *y = min_y + rand() % (max_y - min_y + 1); // Check if position is distinct from cat if (*x == cat_x && *y == cat_y) { attempts++; continue; } // Check if position is distinct from other entities int distinct = 1; for (int i = 0; i < existing_count; i++) { if (*x == existing_x[i] && *y == existing_y[i]) { distinct = 0; break; } } if (distinct) { return 1; } attempts++; } return 0; } // Initialize the game state void* init_game() { // Allocate memory for the game state struct game* state = calloc(1, sizeof(struct game)); if (state == NULL) { return NULL; } // Use current time for random seed (more random than time(NULL) alone) srand((unsigned int)time(NULL) + rand()); // Initial state values state->score = 0; strcpy(state->message, ""); // Place cat at a random position (leaving room for border) state->cat_x = 5 + rand() % 20; state->cat_y = 2 + rand() % 15; // Place 5 mice at distinct random positions for (int i = 0; i < MOUSE_COUNT; i++) { int px, py; get_random_position(&px, &py, 30, 20, state->cat_x, state->cat_y, state->mouse_x, state->mouse_y, i); state->mouse_x[i] = px; state->mouse_y[i] = py; state->mouse_alive[i] = 1; // All mice start alive } return state; } // Draw the game state on screen static void draw_game(struct game* state, struct event* event) { // Clear screen clear_screen(); // Draw border around the playing field (using walls: '#' in cyan) // Top and bottom borders for (int x = 0; x < event->width; x++) { set_color_cell('#', x, 0, COLOR_CYAN, COLOR_BLACK); set_color_cell('#', x, event->height - 1, COLOR_CYAN, COLOR_BLACK); } // Left and right borders for (int y = 1; y < event->height - 1; y++) { set_color_cell('#', 0, y, COLOR_CYAN, COLOR_BLACK); set_color_cell('#', event->width - 1, y, COLOR_CYAN, COLOR_BLACK); } // Draw cat in yellow set_color_cell('c', state->cat_x, state->cat_y, COLOR_YELLOW, COLOR_BLACK); // Draw alive mice in green for (int i = 0; i < MOUSE_COUNT; i++) { if (state->mouse_alive[i]) { set_color_cell('m', state->mouse_x[i], state->mouse_y[i], COLOR_GREEN, COLOR_BLACK); } } // Display score char score_msg[50]; snprintf(score_msg, sizeof(score_msg), "Score: %d/5", state->score); set_message(score_msg, 2, event->height - 2); // Display end-game message if game is won if (state->game_won) { set_message(state->message, (event->width - 40) / 2, event->height / 2); } } // Handle game events int game_event(struct event* event, void* game) { struct game* state = (struct game*)game; // Handle ESC key to quit if (event->type == EVENT_ESC) { return 1; // Non-zero means end the game } // Handle keyboard input (arrow keys to move cat) if (event->type == EVENT_KEY) { if (event->key == KEY_UP) { int new_y = state->cat_y - 1; // Clamp to walls (1 inside border, event->height-2 is last valid position) if (new_y > 0) { state->cat_y = new_y; } } else if (event->key == KEY_DOWN) { int new_y = state->cat_y + 1; if (new_y < event->height - 1) { state->cat_y = new_y; } } else if (event->key == KEY_LEFT) { int new_x = state->cat_x - 1; if (new_x > 0) { state->cat_x = new_x; } } else if (event->key == KEY_RIGHT) { int new_x = state->cat_x + 1; if (new_x < event->width - 1) { state->cat_x = new_x; } } } // Handle timer tick (move mice) if (event->type == EVENT_TIMEOUT) { for (int i = 0; i < MOUSE_COUNT; i++) { if (state->mouse_alive[i]) { // Random direction: 0=up, 1=down, 2=left, 3=right, 4=stay int direction = rand() % 5; int new_x = state->mouse_x[i]; int new_y = state->mouse_y[i]; if (direction == 0) { // Up new_y = state->mouse_y[i] - 1; } else if (direction == 1) { // Down new_y = state->mouse_y[i] + 1; } else if (direction == 2) { // Left new_x = state->mouse_x[i] - 1; } else if (direction == 3) { // Right new_x = state->mouse_x[i] + 1; } // direction 4 means stay (no change to new_x, new_y) // Clamp mouse to walls if (new_x > 0 && new_x < event->width - 1) { state->mouse_x[i] = new_x; } if (new_y > 0 && new_y < event->height - 1) { state->mouse_y[i] = new_y; } } } } // Check collision: cat catches mouse for (int i = 0; i < MOUSE_COUNT; i++) { if (state->mouse_alive[i] && state->cat_x == state->mouse_x[i] && state->cat_y == state->mouse_y[i]) { state->mouse_alive[i] = 0; // Mark mouse as eaten state->score++; } } // Check if all mice are caught (game won) if (state->score == MOUSE_COUNT && !state->game_won) { strcpy(state->message, "Zlapil si vsetky mysky! Lusty macko! :-D"); state->game_won = 1; state->win_tick = 0; } // If game is won, display message and eventually exit if (state->game_won) { state->win_tick++; draw_game(state, event); // After 30 frames (~3 seconds at 10fps), exit if (state->win_tick > 30) { return 1; } return 0; } // Draw the current game state draw_game(state, event); return 0; // Continue the game }