diff --git a/final/.gitignore b/final/.gitignore new file mode 100644 index 0000000..ecf4432 --- /dev/null +++ b/final/.gitignore @@ -0,0 +1,54 @@ +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 new file mode 100644 index 0000000..39d1664 --- /dev/null +++ b/final/LICENSE @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..bf0933d --- /dev/null +++ b/final/Makefile @@ -0,0 +1,14 @@ +CFLAGS=-std=c99 -Wall -g + +all: game + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +clean: + rm *.o + rm hra + +game: main.o game.o world.o + gcc main.o game.o world.o -lcurses -lm -o hra + diff --git a/final/README.md b/final/README.md new file mode 100644 index 0000000..c3799a6 --- /dev/null +++ b/final/README.md @@ -0,0 +1,78 @@ +# PiÅ¡kvorky - hra + +## Obsah + +- Predstavenie hry +- Kompilácia a spustenie hry +- Priebeh hry a jej koniec +- Å truktúry a funkcie hry +- Zdroje + +## Predstavenie hry + +PoÄ�ítaÄ�ová verzia hry piÅ¡kvorky je urÄ�ená pre dvoch hráÄ�ov. Títo hráÄ�i sa poÄ�as hrania hry pri poÄ�ítaÄ�i striedajú. Cieľom hry je vytvoriÅ¥ piÅ¡kvorku. HráÄ�, ktorý vytvorí piÅ¡kvorku, vyhráva. Po vytvorení piÅ¡kvorky sa hra ukonÄ�í a oznámi výherného hráÄ�a. Hra je naprogramovaná v jazyku C. + +## Kompilácia a spustenie hry + +Pre kompiláciu hry je potrebné použiÅ¥ pripravený Makefile, ktorý sa nachádza v rovnakom prieÄ�inku, ako zdrojové kódy programu. Pre kompiláciu programu je potrebné maÅ¥ nainÅ¡talovanú knižnicu ncurses. + +Hru skompilujeme pomocou nasledujúceho príkazu: + + make all + +A následne ju spustíme pomocou príkazu: + + ./hra + +## Priebeh hry + +Po spustení hry sa na obrazovku vykreslí herný plán a pod ním sa zobrazia oznamy o aktuálnom stave hry. + +Herný plán tvorí sieÅ¥, ktorej veľkosÅ¥ sa mení v závislosti od veľkosti výstupnej obrazovky. Každé políÄ�ko v tejto sieti je má svoje Ä�íslo, ktoré hráÄ� zadáva ako vstup do programu poÄ�as hrania hry. + +Ako už bolo vyššie spomenuté, tak táto verzia hry je urÄ�ená pre dvoch hráÄ�ov. HráÄ�i sa poÄ�as hrania striedajú pri poÄ�ítaÄ�i. HráÄ� zadá do programu Ä�íslo políÄ�ka, ktoré chce obsadiÅ¥. Následne sa na danom políÄ�ku namiesto Ä�ísla vyobrazí znak hráÄ�a. Ak hráÄ� zadá Ä�íslo políÄ�ka, ktoré je obsadené, príp. Ä�íslo mimo rozsah, alebo iný znak, tak prichádza o pokus a nasleduje další hráÄ�. Hru vyhráva hráÄ�, ktorý ako prvý úspeÅ¡ne zostaví piÅ¡kvorku. + +Na hernej obrazovke sa následne objaví oznam o skonÄ�ení hry a potom v termináli OS aj oznam oznamujúci, ktorý hráÄ� vyhral. + +## Å truktúry a funkcie hry + +Hra je naprogramovaná pre použitie knižnicou world.h. + +Obsahuje základnú riadiacu Å¡truktúru celej hry. Teraz si podrobnejÅ¡ie popíšeme jej jednotlivé premenné. Pri premenných, pri ktroých je z popisu jasné, na Ä�o sú urÄ�ené, nebudeme popis uvádzaÅ¥: + + int vyskaPolicka + int sirkaPolicka + + int poslednePolickoX //premenná uchováva súradnicu X posledného políÄ�ka + int poslednePolickoY //rovnako ako predchádzajúca premenná, ale súradnicu Y + + int pocetPolicokX //poÄ�et políÄ�ok v 1 riadku + int pocetPolicokY //poÄ�et políÄ�ok v 1 stĺpci + int celkovyPocetPolicok + + int** hernePole //v dvojrozmernom poli je uložený aktuálny herný plán + + char hrac1 + char hrac2 + char aktualnyHrac + char nasledujuciHrac + +Teraz si struÄ�ne popíšeme jednotlivé funkcie hry: + +- **void*** inicializaciaHry(): každá hra, ktorá využíva knižnicu world, musí obsahovaÅ¥ funkciu, ktorá na zaÄ�iatku nainicializuje hru; v tomto prípade táto funkcia nainicializuje riadiacu Å¡truktúru hry, jednotlivé položky Å¡truktúry a herný plán +- **void** vykreslenieHry(struct hra* hra): funkcia vykreslí aktuálny stav hry na základe herného a vypíše informaÄ�né hlásenia +- **int** hernaSlucka(struct event* udalost, void* hra): okrem inicializaÄ�nej funkcie musí každá hra naprogramovaná v knižnici world obsahovaÅ¥ aj riadiacu funkciu, táto funkcia riadi stav celej hry, Å¡truktúra event obsahuje vstup z knižnice world +- **int**** dvojrozmernePole(int prvyRozmer, int druhyRozmer): funkcia nainicializuje dvojrizmerné pole typu int +- **void** stavPolicka(struct hra* hra, int vstup): funkcia skontroluje, Ä�i zadaný vstup je platný a Ä�i je políÄ�ko v hernom poli je obsadené +- **void** zmenaHraca(struct hra* hra): funkcia zmení aktuálneho hráÄ�a po vykonaní jednej hernej sluÄ�ky +- **void** vertikalneVytvoreniePiskvorky(struct hra* hra): hra skontroluje vytvorenie piÅ¡kvorky vo vertikálnom smere +- **void** horizontalneVytvoreniePiskvorky(struct hra* hra): skontroluje vytvorenie piÅ¡kvorky vo horizontálnom smere +- **void** krizoveVytvoreniePiskvorkyZlava(struct hra* hra): skontroluje vytvorenie Å¡ikmej piÅ¡kvorky z ľavej strany +- **void** krizoveVytvoreniePiskvorkySprava(struct hra* hra): skontroluje vytvorenie Å¡ikmej piÅ¡kvorky spravej strany +- **void** koniecHry(char* sprava): funkcia obsahuje príkazy potrebné pre ukonÄ�enie hry, funkcia musí po ukonÄ�ení hry vypísaÅ¥ informáciu (ľubovoľnú) + +Kvôli výskytu dvojciferných Ä�ísel sme museli upraviÅ¥ aj spôsob naÄ�ítavania Ä�ísel do pamäte, keÄ�že pôvodná verzia dokázala naÄ�ítaÅ¥ iba jeden znak. Po úprave dokáže knižnica world naÄ�ítaÅ¥ trojciferné Ä�íslo a pred potvrdením ho je možné aj editovaÅ¥. + +## Zdroje + +[How to clear a specific line with NCurses?] (https://stackoverflow.com/questions/5072881/how-to-clear-a-specific-line-with-ncurses) \ No newline at end of file diff --git a/final/README.pdf b/final/README.pdf new file mode 100644 index 0000000..600e91e Binary files /dev/null and b/final/README.pdf differ diff --git a/final/game.c b/final/game.c new file mode 100644 index 0000000..01b5ce4 --- /dev/null +++ b/final/game.c @@ -0,0 +1,199 @@ +#include //pripojím potrebné knižnice +#include +#include +#include "world.h" +#include "game.h" + +#define DLZKA_HLASENIA 500 //zadefinujem maximálnu dåžku hlásenia + +void* inicializaciaHry() { //vytvorím funkciu pre prvotnú inicializáciu hry + struct hra* hra = (struct hra*) malloc(sizeof(struct hra)); //nainicializujem riadiacu štruktúru pre celú hru + hra->vyskaPolicka = (LINES / 10); //nainicializujem jednotlivé prvky štruktúry + hra->sirkaPolicka = (COLS / 10); + hra->pocetPolicokX = 4; + hra->pocetPolicokY = 6; + hra->poslednePolickoX = (COLS / 10) * hra->pocetPolicokX; //vypoèítam koncové súradnice hracieho po¾a v osi X a Y + hra->poslednePolickoY = (LINES / 10) * hra->pocetPolicokY; + hra->celkovyPocetPolicok = hra->pocetPolicokX * hra->pocetPolicokY; + hra->hraciePole = dvojrozmernePole(hra->pocetPolicokY, hra->pocetPolicokX); + hra->hrac1 = 'X'; + hra->hrac2 = 'O'; + hra->aktualnyHrac = hra->hrac1; + hra->nasledujuciHrac = hra->hrac2; + + int cisloPolicka = 1, i, j; + for (i = 0; i < hra->pocetPolicokY; i++) { + for (j = 0; j < hra->pocetPolicokX; j++) { + hra->hraciePole[i][j] = cisloPolicka; //nainicializujem hracie poli poziènými èíslami + cisloPolicka++; + } + } + + return hra; +} + +void vykreslenieHry(struct hra* hra) { //funkcia vykreslí aktuálny stav hry + int i, j; + + clear(); //vyèistím predchádzajúci plán hry + for (i = 0; i < hra->poslednePolickoY + hra->vyskaPolicka; i += hra->vyskaPolicka) { + for (j = 0; j < hra->poslednePolickoX; j++) set_cell('-', j, i); //nakreslím hranice plánu na osi X + } + + for (i = 0; i < hra->poslednePolickoX + hra->sirkaPolicka; i += hra->sirkaPolicka) { + for (j = 0; j < hra->poslednePolickoY; j++) set_cell('|', i, j); //nakreslím hranice plánu na osi Y + } + + int k, l; //zadeklarujem premenné pre riadenie výpisu z herného po¾a + for (j = 0, l = 0; j < hra->poslednePolickoY; j += hra->vyskaPolicka, l++) { //v rámci herného plánu je potrebné posúva� sa aj v rámci osi Y, zaèiatok je v prvej polovici políèka a posúva sa o jedno políèko + for (i = 0, k = 0; i < hra->poslednePolickoX; i += hra->sirkaPolicka, k++) { // poèiatok vykres¾ovania je v polovici prvého políèka herného plánu v osi X, plán sa posúva o jedno políèko + /*index prvého hráèa: -5 + index druhého hráèa: -6*/ + if (hra->hraciePole[l][k] == -5) mvprintw(j + hra->vyskaPolicka / 2, i + hra->sirkaPolicka / 2, "%c", hra->hrac1); //ak sa namiesto písla políèka nachádza na príslušnej pozícii index prvého hráèa, tak na jeho miesto vykreslím znak prvého hráèa + else if (hra->hraciePole[l][k] == -6) mvprintw(j + hra->vyskaPolicka / 2, i + hra->sirkaPolicka / 2, "%c", hra->hrac2); //ak sa namiesto písla políèka nachádza na príslušnej pozícii index druhého hráèa, tak na jeho miesto vykreslím znak druhého hráèa + else mvprintw(j + hra->vyskaPolicka / 2, i + hra->sirkaPolicka / 2, "%d", hra->hraciePole[l][k]); + } + } + + mvprintw(LINES - (2 * (LINES / 10)), 10, "Aktualny hrac: %c", hra->aktualnyHrac); //zobrazím aktuálneho hráèa + mvprintw(LINES - (2 * (LINES / 10)) + 1, 10, "Zadajte cislo neobsadeneho policka: "); //hláškou vyzvem hráèa na zadanie èísla políèka + + refresh(); //vyobrazím novovygenerovaný plán hry +} + +int hernaSlucka(struct event* udalost, void* hra) { //funkcia je riadiaca štruktúra pre knižnicu world + struct hra* vstupneData = (struct hra*) hra; //vstupnú štruktúru pre hru prevediem na príslušný dátový typ + + stavPolicka(vstupneData, udalost->key); //zmením stav herného plánu + + zmenaHraca(vstupneData); //zmením hráèa + vykreslenieHry(vstupneData); //a nakoniec vykreslím aktuálny stav hry + + vertikalneVytvoreniePiskvorky(hra); //skontrolujem, èi je piškvorka vytvorená + horizontalneVytvoreniePiskvorky(hra); + krizoveVytvoreniePiskvorkyZlava(hra); + krizoveVytvoreniePiskvorkySprava(hra); + + return 0; +} + +int** dvojrozmernePole(int prvyRozmer, int druhyRozmer) { //funkcia vytvorí dvojrozmerné pole typu int + int i; + int **pole = (int**) malloc(prvyRozmer * sizeof(int*)); //nainicializujem prvý rozmer po¾a + for (i = 0; i < prvyRozmer; i++) pole[i] = (int*) malloc(druhyRozmer * sizeof(int)); //nainicializujem druhý rozmer po¾a + + return pole; +} + +void stavPolicka(struct hra* hra, int vstup) { //funkcia skontroluje, èi bolo zadané platné èíslo políèka, priradí ho príslušnému hráèovi a príslušne zmení herný plán + int i, j; + + for (i = 0; i < hra->pocetPolicokY; i++) { //postupne prejdem celé pole + for (j = 0; j < hra->pocetPolicokX; j++) { + if (hra->hraciePole[i][j] <= 0 && hra->hraciePole[i][j] > hra->celkovyPocetPolicok) break; //ak hráè zadal neplatné èíslo políèka, tak sa v hernom pláne nevykoná žiadna zmena + if (hra->hraciePole[i][j] == vstup) { //ak sa zadané èíslo zhoduje s kontrolovaným èíslom, tak zmením herný plán + if (hra->aktualnyHrac == hra->hrac1) hra->hraciePole[i][j] = -5; //zmením èíslo políèka na príslušný index + else hra->hraciePole[i][j] = -6; + } + } + } +} + +void zmenaHraca(struct hra* hra) { //funkcia zmení hráèa po vykonaní jednej hernej sluèky + if (hra->aktualnyHrac == hra->hrac1) { //zmena z 1. hráèa na druhého + hra->aktualnyHrac = hra->nasledujuciHrac; + hra->nasledujuciHrac = hra->hrac1; + } else { //a naopak + hra->aktualnyHrac = hra->nasledujuciHrac; + hra->nasledujuciHrac = hra->hrac2; + } +} + +/*nasledujúce funkcie kontrolujú vytvorenie piškvorky (jednotlivé funkcie sa líšia matematickými výpoètami pre urèenie, +èi sa piškvorka vytvorila), komentáre budú uvedené len pri prvej funkcii a na zaèiatku každej funkcie*/ +void vertikalneVytvoreniePiskvorky(struct hra* hra) { //funkcia kontroluje vytvorenie piškvorky vo vertikálnom smere + int i, j; + char sprava[DLZKA_HLASENIA]; //v správe oznámim hráèa, ktorý vyhral + + for (i = 0; i < hra->pocetPolicokX; i++) { + for (j = 0; j + 2 < hra->pocetPolicokY; j++) { + if ((hra->hraciePole[j][i] == -5 && hra->hraciePole[j + 1][i] == -5 && hra->hraciePole[j + 2][i] == -5)) { //kontrolujem, èi vyhral hráè è. 1 + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac1); + koniecHry(sprava); //hru ukonèím + } + else if (hra->hraciePole[j][i] == -6 && hra->hraciePole[j + 1][i] == -6 && hra->hraciePole[j + 2][i] == -6) { //kontrolujem, èi vyhral hráè è. 1 + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac2); + koniecHry(sprava); //hru ukonèím + } + } + } +} + +void horizontalneVytvoreniePiskvorky(struct hra* hra) { //funkcia kontroluje vytvorenie piškvorky vo horizontálnom smere + int i, j; + char sprava[DLZKA_HLASENIA]; + + for (i = 0; i < hra->pocetPolicokY; i++) { + for (j = 0; j + 2 < hra->pocetPolicokX; j++) { + if ((hra->hraciePole[i][j] == -5 && hra->hraciePole[i][j + 1] == -5 && hra->hraciePole[i][j + 2] == -5)) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac1); + koniecHry(sprava); + } + else if (hra->hraciePole[i][j] == -6 && hra->hraciePole[i][j + 1] == -6 && hra->hraciePole[i][j + 2] == -6) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac2); + koniecHry(sprava); + } + } + } +} + +void krizoveVytvoreniePiskvorkyZlava(struct hra* hra) { //funkcia kontroluje vytvorenie piškvorky krížom z ¾avej strany + int i, j; + char sprava[DLZKA_HLASENIA]; + + for (i = 0; i < hra->pocetPolicokX; i++) { + for (j = 0; j < hra->pocetPolicokY; j++) { + if ((hra->hraciePole[i][j] == -5 && hra->hraciePole[i + 1][j + 1] == -5 && hra->hraciePole[i + 2][j + 2] == -5)) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac1); + koniecHry(sprava); + } + else if (hra->hraciePole[i][j] == -6 && hra->hraciePole[i + 1][j + 1] == -6 && hra->hraciePole[i + 2][j + 2] == -6) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac2); + koniecHry(sprava); + } + } + } +} + +void krizoveVytvoreniePiskvorkySprava(struct hra* hra) { //funkcia kontroluje vytvorenie piškvorky krížom spravej strany + int i, j; + char sprava[DLZKA_HLASENIA]; + + for (i = 0; i < hra->pocetPolicokX; i++) { + for (j = hra->pocetPolicokY - 1; j - 2 >= 0; j--) { + if ((hra->hraciePole[i + 2][j - 2] == -5 && hra->hraciePole[i + 1][j - 1] == -5 && hra->hraciePole[i][j] == -5)) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac1); + koniecHry(sprava); + } + else if (hra->hraciePole[i + 2][j - 2] == -6 && hra->hraciePole[i + 1][j - 1] == -6 && hra->hraciePole[i][j] == -6) { + sprintf(sprava, "Hru vyhral hrac %c.\n", hra->hrac2); + koniecHry(sprava); + } + } + } +} +//tu konèia funkcie kontrolujúce vytvorenie piškvorky + +void koniecHry(char* sprava) { //funkcia vykoná príkazy potrebné pre ukonèenie hry + //zmažem riadiace hlášky + move(LINES - (2 * (LINES / 10)), 0); //nastavím kurzor na príslušný riadok + clrtoeol(); //a zmažem ho + + move(LINES - (2 * (LINES / 10)) + 1, 0); //rovnako aj tu + clrtoeol(); + + mvprintw(LINES - (2 * (LINES / 10)), 10, "Koniec hry."); //hráèom oznámim koniec hry + refresh(); //vyobrazím hru + napms(2000); //zobrazím koncový stav hry + abort_game(sprava); //a hru ukonèím +} diff --git a/final/game.h b/final/game.h new file mode 100644 index 0000000..a7679db --- /dev/null +++ b/final/game.h @@ -0,0 +1,39 @@ +#include "world.h" + +struct hra { //vytvorím štruktúru riadiacu celú hru + int vyskaPolicka; + int sirkaPolicka; + + int poslednePolickoX; + int poslednePolickoY; + + int pocetPolicokX; + int pocetPolicokY; + int celkovyPocetPolicok; + + int** hraciePole; + + char hrac1; + char hrac2; + char aktualnyHrac; + char nasledujuciHrac; +}; + +//funkcia pre inicializáciu hry +void* inicializaciaHry(); + +int hra(struct event* udalost, void* hra); +void vykreslenieHry(struct hra* hra); +int hernaSlucka(struct event* udalost, void* hra); + +int** dvojrozmernePole(int prvyRozmer, int druhyRozmer); + +void stavPolicka(struct hra* hra, int vstup); +void zmenaHraca(struct hra* hra); + +void vertikalneVytvoreniePiskvorky(struct hra* hra); +void horizontalneVytvoreniePiskvorky(struct hra* hra); +void krizoveVytvoreniePiskvorkyZlava(struct hra* hra); +void krizoveVytvoreniePiskvorkySprava(struct hra* hra); + +void koniecHry(char* sprava); diff --git a/final/hra b/final/hra new file mode 100755 index 0000000..04e8d3d Binary files /dev/null and b/final/hra differ diff --git a/final/main.c b/final/main.c new file mode 100644 index 0000000..3aed949 --- /dev/null +++ b/final/main.c @@ -0,0 +1,7 @@ +#include "game.h" +#include "world.h" + +int main(int argc, char** argv){ + start_world(inicializaciaHry,hernaSlucka,free); + return 0; +} \ No newline at end of file diff --git a/final/world.c b/final/world.c new file mode 100644 index 0000000..679faa2 --- /dev/null +++ b/final/world.c @@ -0,0 +1,182 @@ +#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; + } + + curs_set(FALSE); // Neviditeľný kurzor + 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; + + //zaÄ�iatok upravenej Ä�asti programu + //upravená Ä�asÅ¥ programu naÄ�ítava Ä�íselný vstup od používateľa + char buff[4]; + const int VELKOST_BUFF = 4; + memset(buff, '\0', VELKOST_BUFF); + int i = 0; + + while (true) { + int buff_char = (char) getchar(); + + //zadaný vstup vyobrazujem + if (i > 0 && buff_char == 127) { + buff[i - 1] = '\0'; + i -= 2; + mvprintw(LINES - (2 * (LINES / 10)) + 1, 10 + 1 + strlen("Zadajte cislo neobsadeneho policka: "), " "); + mvprintw(LINES - (2 * (LINES / 10)) + 1, 10 + 1 + strlen("Zadajte cislo neobsadeneho policka: "), "%s", buff); //po zmazaní znaku sa odstráni aj z obrazovky + } + else if (buff_char >= '0' && buff_char <= '9') { + buff[i] = buff_char; + mvprintw(LINES - (2 * (LINES / 10)) + 1, 10 + 1 + strlen("Zadajte cislo neobsadeneho policka: "), "%s", buff); + } + i++; + refresh(); + + if (i == VELKOST_BUFF) break; + else if (buff_char == '\r') break; + } + + event.key = atoi(buff); + //zaÄ�iatok upravenej Ä�asti programu + + // 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 new file mode 100644 index 0000000..95a0242 --- /dev/null +++ b/final/world.h @@ -0,0 +1,123 @@ +#ifndef _WORLD_H_ +#define _WORLD_H_ + +#include +#include +#include +#include +#include +#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; +}; + +void abort_game(const char* message); + +/** + * 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); +void check_bounds(const char* source,int x, int y); +void game_speed(int value); +void set_message(const char* message,int x,int y); +void assert_message(int event,const char* message); + +/** + * + * @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