diff --git a/final/.gitignore b/final/.gitignore deleted file mode 100644 index ecf4432..0000000 --- a/final/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -game - -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf diff --git a/final/LICENSE b/final/LICENSE deleted file mode 100644 index 39d1664..0000000 --- a/final/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2019, Daniel Hládek -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/final/Makefile b/final/Makefile deleted file mode 100644 index 8c35442..0000000 --- a/final/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -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/final/README.md b/final/README.md deleted file mode 100644 index b57958c..0000000 --- a/final/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# World Game Library - -Learn asycnronous C programming by a game. - -The library implements a game loop for a character-based ncurses game; - -The library finds out the event types: - -- start and end -- mouse events -- keyboard events -- screen resize events - -It can print colors and arbitrary characters on the screen. -Running is interrupted when character is drawn out of the screen. - -## Installation and Running - -Make sure, that `ncurses` is installed. - -Clone this repository. - -Compile: - -```c -make -``` - -Run: - -```c -./game -``` - -## Make your own game - -The game happens in a rectangular world of colorful characters. -Your goal as a programmer is to modify the world according to the pressed keys and the internal game state. -The library implements the game loop and draws the world to screen. - -Your game in file `game.c` consists of two functions: - -- `void* init_game()` is called in the beginning. Here you can initialize the internal state of the game. -The function should return a pointer to an instance of the initial game state `game`. -- `int game_event(struct event* event,void* game)` -is called by the game loop in periodic interval or when a key was pressed. Non-zero return value or `Ctrl+C` key interrupts the game loop. - -The world variable represents state of two-dimensional grid of characters on the screen. The screen matrix looks like this: - -``` - origin - [0,0] width - +--------------------+ -h | | -e | | -i | | -g | | -h | | -t | | - +--------------------+ -``` - -The world has the following parameters: - -- `int height`: y-dimension of the grid. -- `int width`: x-dimension of the grid. -- `int interval`: maximum time between steps in milliseconds. - -### The Event Function - -The `int game_event(struct event* event,void* game)` - function should: - -1. Read the game state (from the `void* game`) pointer. -1. Examine the pressed key from event pointer. If the `key` variable is non-zero, a key was pressed. According to the pressed key, modify the game state `game`. -1. Draw the game state. In the beginning of the step function the screen is empty. -1. Returning non-zero value ends the game loop. - diff --git a/final/game.c b/final/game.c deleted file mode 100644 index e795070..0000000 --- a/final/game.c +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include "world.h" -#include "game.h" - -// Start is called one in the beginning -void* init_game(){ - // Allocate memory for the state - struct game* st = calloc(1,(sizeof(struct game))); - // Initialize state - st->mousex = 5; - st->mousey = 5; - st->catx = 0; - st->caty = 0; - st->catx_position = 15; - st->caty_position = 15; - // Store pointer to the state to the world variable - return st; -} - -// Step is called in a loop once in interval. -// It should modify the state and draw it. -int game_event(struct event* event,void* game){ - // Get state pointer - struct game* state = game; - char msg[200]; - sprintf(msg,"%d",event->type); - set_message(msg,10,0); - if ( event->type == EVENT_ESC){ - // Non zero means finish the loop and stop the game. - return 1; - } - // Read game variable and update the eventstate - - // Is mouse caught ? - if ((state->caty_position == state->mousey) && (state->catx_position == state->mousex)){ - clear_screen(); - set_message("HAM",12,13); - return 0; - } - else if(event->type == EVENT_TIMEOUT) { - // Move cat - //state->catx_position += state->catx; - //state->caty_position += state->caty; - int cx = state->catx_position + state->catx; - int cy = state->caty_position + state->caty; - if (cx < 0 || cy < 0 || cx > event->width || cy > event->height){ - - } - else { - state->catx_position = cx; - state->caty_position = cy; - } - - //state->catx_position += state->catx; - //state->caty_position += state->caty; - //state->caty_position += state->caty; - // random mouse movement - int m = rand() % 6; - if (m == 0){ - state->mousey -= 1; - } - else if (m == 1){ - state->mousey += 1; - } - else if (m == 2){ - state->mousex -= 1; - } - else if (m == 3){ - state->mousex += 1; - } - // Je myska mimo plochy - } - else if (event->type == EVENT_KEY){ - // Move cat according to keyboard - 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; - } - } - // Draw world state - // - // Draw cat - 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); - //set_cell('c',state->catx_position,state->caty_position); - // Draw mouse - set_cell('m',state->mousex,state->mousey); - set_message( state->message,1,0); - return 0; -} - diff --git a/final/game.h b/final/game.h deleted file mode 100644 index 29b14fb..0000000 --- a/final/game.h +++ /dev/null @@ -1,30 +0,0 @@ -#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; - // Y position of the mouse - int mousey; - // 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/final/main.c b/final/main.c deleted file mode 100644 index 0446027..0000000 --- a/final/main.c +++ /dev/null @@ -1,9 +0,0 @@ -#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/final/world.c b/final/world.c deleted file mode 100644 index a45c109..0000000 --- a/final/world.c +++ /dev/null @@ -1,198 +0,0 @@ -#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/final/world.h b/final/world.h deleted file mode 100644 index 73be057..0000000 --- a/final/world.h +++ /dev/null @@ -1,113 +0,0 @@ -#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