From 2f123db3c2f73a390aaec9a9b23fafa2c09ff391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ka=C4=8Dm=C3=A1r?= Date: Fri, 2 May 2025 08:31:49 +0000 Subject: [PATCH] Upload files to "a4" --- a4/Makefile | 14 ++++ a4/game.c | 91 ++++++++++++++++++++++++ a4/game.h | 30 ++++++++ a4/main.c | 9 +++ a4/world.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++ a4/world.h | 113 ++++++++++++++++++++++++++++++ 6 files changed, 455 insertions(+) create mode 100644 a4/Makefile create mode 100644 a4/game.c create mode 100644 a4/game.h create mode 100644 a4/main.c create mode 100644 a4/world.c create mode 100644 a4/world.h diff --git a/a4/Makefile b/a4/Makefile new file mode 100644 index 0000000..8c35442 --- /dev/null +++ b/a4/Makefile @@ -0,0 +1,14 @@ +CFLAGS=-std=c99 -Wall -g + +all: game + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +clean: + rm *.o + rm game + +game: main.o game.o world.o + gcc main.o game.o world.o -lcurses -lm -o game + diff --git a/a4/game.c b/a4/game.c new file mode 100644 index 0000000..5b4100e --- /dev/null +++ b/a4/game.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include "world.h" +#include "game.h" + +#define NUM_MICE 5 + +// Start is called once at the beginning +void* init_game() { + struct game* st = calloc(1, sizeof(struct game)); + // Initialize mice at random positions + for (int i = 0; i < NUM_MICE; i++) { + st->mousex[i] = rand() % 20 + 1; + st->mousey[i] = rand() % 10 + 1; + } + st->catx = 0; + st->caty = 0; + st->catx_position = 15; + st->caty_position = 15; + return st; +} + +// Step is called in a loop once per interval +int game_event(struct event* event, void* game) { + struct game* state = game; + int width = event->width; + int height = event->height; + + if (event->type == EVENT_ESC) { + return 1; + } + + // Handle keyboard input + if (event->type == EVENT_KEY) { + if (event->key == KEY_UP) { state->catx = 0; state->caty = -1; } + else if (event->key == KEY_DOWN) { state->catx = 0; state->caty = 1; } + else if (event->key == KEY_LEFT) { state->catx = -1; state->caty = 0; } + else if (event->key == KEY_RIGHT) { state->catx = 1; state->caty = 0; } + } + + if (event->type == EVENT_TIMEOUT) { + int cx = state->catx_position + state->catx; + int cy = state->caty_position + state->caty; + // Keep cat inside bounds + if (cx >= 1 && cx < width - 1) state->catx_position = cx; + if (cy >= 1 && cy < height - 1) state->caty_position = cy; + + // Move mice randomly + for (int i = 0; i < NUM_MICE; i++) { + int m = rand() % 4; + int mx = state->mousex[i]; + int my = state->mousey[i]; + if (m == 0 && my > 1) state->mousey[i]--; + else if (m == 1 && my < height - 2) state->mousey[i]++; + else if (m == 2 && mx > 1) state->mousex[i]--; + else if (m == 3 && mx < width - 2) state->mousex[i]++; + } + } + + // Check if cat caught any mouse + for (int i = 0; i < NUM_MICE; i++) { + if (state->catx_position == state->mousex[i] && state->caty_position == state->mousey[i]) { + state->mousex[i] = -1; // remove mouse from play + state->mousey[i] = -1; + } + } + + // Draw world + clear_screen(); + set_color_cell('c', state->catx_position, state->caty_position, COLOR_YELLOW, COLOR_RED); + set_color_cell('-', state->catx_position - 1, state->caty_position, COLOR_YELLOW, COLOR_GREEN); + + int mice_left = 0; + for (int i = 0; i < NUM_MICE; i++) { + if (state->mousex[i] >= 0) { + set_cell('m', state->mousex[i], state->mousey[i]); + mice_left++; + } + } + + sprintf(state->message, "Mysky zive: %d", mice_left); + set_message(state->message, 1, 0); + + // If all mice are gone, show win message + if (mice_left == 0) { + set_message("Vsetky mysky chytene! Gratulujem!", width / 2 - 10, height / 2); + } + + return 0; +} diff --git a/a4/game.h b/a4/game.h new file mode 100644 index 0000000..ea74230 --- /dev/null +++ b/a4/game.h @@ -0,0 +1,30 @@ +#ifndef _GAME_H_INCLUDE_ +#define _GAME_H_INCLUDE_ +#include "world.h" + +// Set of variables that expresses state of the game. +// +struct game { + // X speed of the cat + int catx; + // Y speed of the cat + int caty; + // X position of the cat + int catx_position; + // Y opsition of the cat + int caty_position;; + // X position of the mouse + int mousex[5]; + // Y position of the mouse + int mousey[5]; + // Funky message + char message[100]; +}; + +// Returns pointer to newly allocated state +void* init_game(); + +// Changes world according to the game state (pressed key, screen size or other event) +int game_event(struct event* event,void* game); + +#endif diff --git a/a4/main.c b/a4/main.c new file mode 100644 index 0000000..0446027 --- /dev/null +++ b/a4/main.c @@ -0,0 +1,9 @@ +#include "game.h" +#include "world.h" +#include + + +int main(int argc, char** argv){ + start_world(init_game,game_event,free); + return 0; +} diff --git a/a4/world.c b/a4/world.c new file mode 100644 index 0000000..a45c109 --- /dev/null +++ b/a4/world.c @@ -0,0 +1,198 @@ +#include "world.h" +#include +#include +#include +#include +#include + +int TIMEOUT; + +void abort_game(const char* message){ + endwin(); + puts(message); + exit(1); +} + +void check_bounds(const char* source,int x, int y){ + char msg[200]; + if (x < 0 || x >= COLS){ + sprintf(msg,"%s:: width %d is out of bounds (0,%d)",source,x,COLS); + abort_game(msg); + } + if (y < 0 || y >= LINES){ + sprintf(msg,"%s:: height %d is out of bounds (0,%d)",source,y,LINES); + abort_game(msg); + } +} + +void clear_screen(){ + // Clear screen + mvaddch(0,0,' '); + int screenchars = LINES*COLS; + for (int j = 1; j < screenchars;j++ ){ + addch(' '); + } +} + +void game_speed(int value){ + if (value < 0){ + abort_game("world_seed:: cannot be negative\n"); + } + TIMEOUT =value; +} + +void set_message(const char* message,int x,int y) { + int l = strlen(message); + for (int i = 0; i < l; i++){ + check_bounds("set_message",x+i,y); + set_cell(message[i],x+i,y); + } +} + +void assert_message(int event,const char* message){ + if (event == 0){ + abort_game(message); + } +} + + +void set_cell(int character,int x,int y) { + check_bounds("set_cell",x,y); + set_color_cell(character,x,y,COLOR_WHITE,COLOR_BLACK); +} + +void set_color_cell(int character,int x,int y,short front_color,short back_color){ + check_bounds("set_color_cell",x,y); + if (has_colors()){ + int pair = COLOR_COUNT * front_color + back_color; + attron(COLOR_PAIR(pair)); + mvaddch(y,x,character); + attroff(COLOR_PAIR(pair)); + } + else{ + mvaddch(y,x,character); + } +} + +int start_world(void* (*init_game)(),int (*world_event)(struct event* event,void* game),void (*destroy_game)(void*)){ + srand(time(NULL)); + int r = 1; + // Speed global variable + TIMEOUT = 100; + if (initscr() == NULL){ + // TODO Which Error? + puts("Curses Error."); + return -1; + } + noecho(); // Nevypisuj vstup na obrazovku + cbreak(); // Zabudni starý vstup + nodelay(stdscr,TRUE); // Nečakaj na stlačenie + keypad(stdscr,TRUE); // Aktivuje šípky + curs_set(FALSE); // Neviditeľný kurzor + /* Get all the mouse events */ + mousemask(ALL_MOUSE_EVENTS, NULL); + MEVENT mouse_event; + if (has_colors()){ // Zistenie či terminál podporuje farby + start_color(); + for (int i = 0; i < COLOR_COUNT;i++){ + for (int j = 0; j < COLOR_COUNT;j++){ + init_pair(i * COLOR_COUNT + j, i,j); + } + } + } + else { + puts("No colors!\n"); + } + void* game = NULL; + if (init_game != NULL){ + game = init_game(); + assert_message(game != NULL,"init_game:: should return non null pointer"); + } + timeout(TIMEOUT); + // Initial step + struct event event; + memset(&event,0,sizeof(struct event)); + event.height = LINES; + event.width = COLS; + event.type = EVENT_START; + clock_t start_time = clock(); + clock_t last_timeout = start_time; + clock_t next_timeout = last_timeout + TIMEOUT; + event.time_ms = start_time; + // Start event + r = world_event(&event,game); + refresh(); + while (!r) { + memset(&event,0,sizeof(struct event)); + event.height = LINES; + event.width = COLS; + event.key = getch(); + // No key was pressed + if (event.key == ERR){ + event.type = EVENT_TIMEOUT; + last_timeout = clock(); + next_timeout = last_timeout + TIMEOUT; + } + // Mouse event + else if (event.key == KEY_MOUSE ){ + event.type = EVENT_MOUSE; + if(getmouse(&mouse_event) == OK){ + event.mouse_x = mouse_event.x; + event.mouse_y = mouse_event.y; + if(mouse_event.bstate & BUTTON1_PRESSED){ + event.mouse_left = 1; + } + if(mouse_event.bstate & BUTTON2_PRESSED){ + event.mouse_middle = 1; + } + if(mouse_event.bstate & BUTTON3_PRESSED){ + event.mouse_right = 1; + } + } + } + else if (event.key == KEY_RESIZE) { + event.type = EVENT_RESIZE; + } + else{ + event.type = EVENT_KEY; + if (event.key == 27){ + int k = getch(); + if (k == -1){ + // Esc Was pressed + event.type = EVENT_ESC; + } + else { + // Alt was pressed + event.key = k; + event.alt_key = 1; + } + } + } + // Draw new world + event.time_ms = clock(); + r = world_event(&event,game); + refresh(); + event.time_ms = clock(); + // set new timeout + int nt = next_timeout - event.time_ms; + //printf("%d\n",nt); + if (nt > 0){ + timeout(nt); + } + else { + timeout(TIMEOUT); + next_timeout = event.time_ms + TIMEOUT; + } + } + memset(&event,0,sizeof(struct event)); + event.height = LINES; + event.width = COLS; + event.type = EVENT_END; + event.time_ms = clock(); + world_event(&event,game); + if (destroy_game != NULL){ + destroy_game(game); + } + endwin(); + return r; +}; diff --git a/a4/world.h b/a4/world.h new file mode 100644 index 0000000..73be057 --- /dev/null +++ b/a4/world.h @@ -0,0 +1,113 @@ +#ifndef _WORLD_H_ +#define _WORLD_H_ + +#include + +/** + * World represented as a rectangular matrix of colorful characters. + * + * Point [0,0] is displayed the upper left corner of the screen. + * + */ + +enum event_type { + EVENT_START, + EVENT_TIMEOUT, + EVENT_KEY, + EVENT_MOUSE, + EVENT_RESIZE, + EVENT_ESC, + EVENT_END, +}; + +struct event { + /** + * Last width of the screen. + */ + int width; + /** + * Last height of the screen. + */ + int height; + /** + * Last pressed key or Curses event. + * + * Special event values: + * ERR if timeout, + * KEY_RESIZE if screen resize + * KEY_EVENT, other event, + * KEY_MOUSE, mouse clicked + * + * Key values: + * + * ' ' Space + * KEY_DOWN Arrow down + * KEY_UP Arrow up + * KEY_LEFT Arrow left + * KEY_RIGHT Arrow right + * KEY_A1 Upper left of keypad + * KEY_A3 Upper right of keypad + * KEY_B2 Center of keypad + * KEY_C1 Lower left of keypad + * KEY_C3 Lower right of keypad + * + * KEY_ENTER + * KEY_BACKSPACE + */ + int key; + int alt_key; + enum event_type type; + int mouse_x; + int mouse_y; + int mouse_left; + int mouse_right; + int mouse_middle; + long int time_ms; +}; + +/** + * Sets cell to a state. + * @param event + * @param x coordinate of cell + * @param y coordinate of cell + * @param new state of the cell + */ +void set_cell(int character,int x,int y); + +/** + * COLOR_BLACK 0 + * COLOR_RED 1 + * COLOR_GREEN 2 + * COLOR_YELLOW 3 + * COLOR_BLUE 4 + * COLOR_MAGENTA 5 + * COLOR_CYAN 6 + * COLOR_WHITE 7 + */ + +#define COLOR_COUNT 8 + +void set_color_cell(int character,int x,int y,short front_color,short back_color); + + +/** + * + * @param event + * @param number of commandline arguments + * @param init_world + * @param destroy_world + * + * void init_world(struct event* w); + * Initializes user state. + * Free user state. + * @param event + */ + +int start_world(void* (*init_game)(),int (*world_event)(struct event* event,void* game),void (*destroy_game)(void* game)); + +void game_speed(int value); + +void set_message(const char* message,int x,int y); +void clear_screen(); + +#endif