Problem Set #6: Mastermind

Ciele

  • Naučiť sa pracovať s prototypovacou doskou Arduino

Logik a.k.a. Mastermind

Mastermind je hra pre dvoch hráčov, ktorá je v našich končinách skôr známa pod názvom Logik. Predpokladám, že ste ju už hrali. Ak však patríte do skupiny hráčo, ktorí pod Quake 3 nejdú, tak vám odporúčam pred týmto zadaním niekoľko partií tejto hry odohrať. Napríklad online verziu tu alebo si nainštalujte verziu pre OS Android.

Mastermind hracie pole

Pravidlá hry

  • Na začiatku si jeden z hráčov umiestni pod striešku (viď obrázok vyššie) kombináciu farebných kolíkov. Ich počet je obyčajne 4, ale v závislosti od prevedenia hry a jej obtiažnosti ich môže byť viac. V závislosti od dohody hráčov sa farby kolíkov môžu opakovať.
  • Cieľom hry je uhádnuť farebnú kombináciu druhým hráčom vrátane poradia jednotlivých farieb. Prvý hráč každý jeho pokus vyhodnotí nasledovne:
    • za každý hrací kolík, ktorý hádajúci hráč umiestnil v správnej farbe na správne miesto, pridá čierny kolík
    • za každý hrací kolík, ktorý hádajúci hráč umiestnil v správnej farbe, ale na zlé miesto, pridá biely kolík
  • Hádajúci hráč vyhrá, ak uhádne celú kombináciu. To znamená, že uhádne farby všetkých kolíkov na správnych pozíciách (jeho ťah bude ohodnotený štyrmi čiernymi kolíkmi).
  • Hádajúci hráč prehrá, ak sa mu nepodarí uhádnuť farebnú kombináciu za povolený počet pokusov.

Následne si hráči vymenia role a hrajú znova. Hru vyhráva hráč, ktorému sa podarí uhádnuť súperovu kombináciu za menší počet ťahov.

Zadanie

Áno - vašou úlohou je vytvoriť implementáciu hry Logik v jazyku C. Aby to však nebolo až také jednoduché, tu je niekoľko zmien:

  • Vaše riešenie bude postavené na prototypovacej doske Arduino.
  • Úlohu hráča, ktorý generoval tajnú farebnú kombináciu bude vždy zastupovať Arduino.
  • Miesto farebných kolíkov bude potrebné uhádnuť číselnú kombináciu pozostávajúcu zo štyroch číslic v rozsahu od 09.
  • Pre komunikáciu s hráčom sa bude používať display.
  • Pre zadávanie kombinácie bude hráč používať tlačidlá - pre každú číslicu kódu jedno, takže dokopy 4 tlačidlá. Po jeho stlačení sa bude hodnota číslice meniť postupne od hodnoty 0 až po hodnotu 9. Po dosiahnutí hodnoty 9 a opätovnom stlačení tlačidla sa hodnota číslice na display-i opäť zmení na hodnotu 0, následne na 1, atď. Pozor však - pri stlačení tlačidla sa číslica zmení práve o 1. Ak chcem teda z východzej hodnoty 0 spraviť hodnotu 5, musím tlačidlo stlačiť 5x.
  • Pre ukončenie ťahu je potrebné ťah potvrdiť stlačením tlačidla ENTER - piate tlačidlo.
  • Po ukončení ťahu Arduino ohodnotí hráčov ťah pomocou štyroch RGB lediek:
    • ak hráč uhádne číslicu a súčasne uhádne aj jej pozíciu, zasvieti červenú farbu
    • ak hráč síce uhádne číslicu, ale neuhádne jej pozíciu, zasvieti modrú farbu
  • Ak hráč uhádne celú kombináciu, môžete tento stav reprezentovať rozličnými efektami vzhľadom na použité súčiastky.
  • V prípade, že hráč stlačí prvé tlačidlo (BTN_1_PIN) a následne bude stláčať druhé (BTN_2_PIN) alebo tretie (BTN_3_PIN) tlačidlo, bude sa môcť pohybovať v histórii predchádzajúcich pokusov dopredu (pri stlačení tretieho tlačidla) a dozadu (pri stlačení druhého tlačidla).

Ukážková hra

Pre názornejšiu predstavu toho, ako môže vyzerať jedna partia sa môžete pozrieť napríklad na toto video na YouTube. Alebo vám k tomu môže pomôcť nasledovný výpis:

9347
---- ----
1234 0A2B
5678 0A1B
9012 1A0B
9340 3A0B
9345 3A0B
9346 3A0B
9347 4A0B

Následná komunikácia v rámci dvojriadkového LCD display-u môže vyzerať napríklad takto:

  • Úvodná obrazovka po zapnutí:

    Welcome to MasterMind
    Your goal is to guess my secret combination.
  • Následné spustenie hry a výzva pre hráča:

    I am thinking a number:
    Your guess: 0000
  • Pri stláčaní tlačidiel, ktoré sú vyvedené na piny BTN_1_PINBTN_2_PIN sa budú postupne meniť hodnoty jednotlivých zobrazených číslic na hráčov tip:

    I am thinking a number:
    Your guess: 1234
  • Po stlačení tlačidla vyvedeného na pin BTN_ENTER_PIN dôjde k vyhodnoteniu hráčovho ťahu (na display-i a súčasne aj príslušnou kombináciou RGB diód) a zobrazenie ďalšej výzvy:

    01: 1234 0A2B
    Your guess: 0000
  • Po zadaní ďalšieho tipu a jeho potvrdení dôjde k jeho vyhodnoteniu:

    02: 5678 0A1B
    Your guess: 0000
  • Ak v tomto prípade hráč začne listovať históriou späť (podržaním tlačidla v kombinácii s tlačidlom), zobrazí sa v riadku histórie predchádzajúci ťah a adekvátne sa rozsvietia aj RGB diódy. Riadok s aktuálne zadávaným tipom sa však nijako nezmení:

    01: 1234 0A2B
    Your guess: 0000
  • Po zadaní posledného tipu vedúceho k správenmu riešeniu hry sa na displayi zobrazí vhodný text a RGB diódy môžu vydávať rôzne farby:

    07: 9347 4A0B
    Well done! You win in 7 guesses!
  • V prípade, že by hráč vyčerpal všetky pokusy, zobrazí sa smutná správa:

    10: 9348 3A0B
    Looser! My secret combination was 9347.

Vybavenie

Pre potreby vytvorenia hry budete potrebovať:

  • 1x Arduino UNO
  • 1x breadboard
  • 1x display s i2c moduom
  • 4x dvojfarebné alebo RGB LED diódy
  • 5x tlačidlo
  • 8x rezistor 220 Ohm
  • 5x rezistor 10 kOhm
  • prepojovacie káble (vrátane USB kabla)

Vývojové prostedie

Vývojové prostredie (IDE) pre Arduino je možné stiahnuť priamo zo stránky www.arduino.cc. Pokiaľ však používate niektorú linuxovú distribúciu, môžete si tento nástroj nainštalovať priamo z repozitára:

  • V prípade, že používate Fedoru (RedHat):

    sudo dnf install arduino
  • V prípade, že používate Ubuntu (Debian):

    sudo apt-get install

Miesto Arduino IDE môžete použiť aj nástroj Fritzing, ktorý ponúka viac možností, ako len vývojové prostredie pre programovanie mikrokontroléra. Pomocou neho môžete napríklad nakresliť schému zapojenia vášho riešenia.

Podobne, ako Arduino IDE môžete aj Fritzing nájsť v repozitároch vašej distribúcie alebo si ho môžete stiahnuť priamo z domovskej stránky projektu.

Tí najväčší makači však budú určite pre vývoj používať textový editor Vim. V tom prípade im určite pomôže napríklad aj tento článok.

Schéma zapojenia

Na obrázku nižšie sa nachádza schéma celého zapojenia. V tomto prípade je veľmi dôležité, aby vaše pripojené vstupy aj výstupy zodpovedali uvedeným PIN-om.

mastermind - schematic

Modul LCD

Tento modul sa týka vášho LCD display-a. Sám osobe nebude kontrolovaný, pretože jeho funkcionalita závisí od typu vášho LCD display-a. Jednotlivé funkcie a ich zoznam sa nachádza v hlavičkovom súbore lcd_wrapper.h.

Dôležitou je funkcia lcd_init(), ktorá slúži na inicializovanie display-a. Túto funkciu volajte podľa potreby z funkcie setup(). Pokiaľ si použitie vašej knižnice vyžaduje aj nejakú globálnu premennú, vytvorte, resp. príslušné volanie zapíšte do súboru lcd_wrapper.cpp, pretože celá práca a všetky volania display-a sa budú nachádzať len v tomto súbore (module).

Modul Mastermind

Tento modul obsahuje samotnú logiku celej hry.

Úloha #1: Funkcia generate_code()

Táto funkcia slúži na vygenerovanie tajného kódu, ktorý má byť uhádnutý. Vygenerovaný kód vráti ako referenciu na reťazec znakov, ktorý je zložený len zo znakov číslic.

Funkcia má tieto pozičné parametre:

  • bool repeat - Ak je nastavený na hodnotu true, jednotlivé číslice sa vo výslednom kóde môžu opakovať. V opačnom prípade sa opakovať nemôžu.
  • int length - Určuje dĺžku vygenerovaného kódu (počet číslic, z ktorých sa má výsledný kód skladať). Ak je dĺžka menšia ako 1, funkcia vráti NULL.

Funkcia vráti referenciu na vygenerovaný reťazec alebo NULL, ak sa tento reťazec vygenerovať nepodarilo. Funkcia vráti NULL aj v prípade, ak parameter repeat bude mať hodnotu false a dĺžka reťazca bude väčšia ako 10.

Príklad použitia

char* code = NULL;

// code will be generated as sequence not repeating digits of length 4
code = generate_code(false, 4);
// code = "1234";
free(code)

// code will be generated as sequence of repeating digits of length 5
code = generate_code(true, 5);
// code = "65656";
free(code);

// no code will be generated
code = generate_code(true, -10);
// code = NULL;

Úloha #2: Funkcia get_score()

Pomocou tejto funkcie dôjde k vyhodnoteniu aktuálneho pokusu. Výsledkom bude nastavenie správnych hodôt pre počet uhádnutých číslic nachádzajúcich sa na správnej pozícii, ako aj pre počet uhádnutých číslic, ktoré nie sú na správnej pozícii.

Funkcia má tieto pozičné parametre:

  • char* secret - Referencia na číselnú kombináciu, ktorú je potrebné uhádnuť. Vstupný parameter.
  • char* guess - Referencia na číselnú kombináciu, ktorá reprezentuje aktuálny hráčov tip. Vstupný parameter.
  • int* peg_a - Referencia na číslo, ktoré reprezentuje počet uhádnutých číslic nachádzajúcich sa na správnej pozícii. Výstupný parameter.
  • int* peg_b - Referencia na číslo, ktoré reprezentuje počet uhádnutých číslic, ktoré sa nenachádzajú na správnej pozícii. Výstupný parameter.

Funkcia nevracia žiadnu hodnotu.

Príklad použitia

int peg_a;
int peg_b;

get_score("9347", "1234", &peg_a, &peg_b);
assert(peg_a == 0 && peg_b == 2);

get_score("9347", "9348", &peg_a, &peg_b);
assert(peg_a == 3 && peg_b == 0);

get_score("9347", "1256", &peg_a, &peg_b);
assert(peg_a == 0 && peg_b == 0);

get_score("9347", "9436", &peg_a, &peg_b);
assert(peg_a == 1 && peg_b == 2);

Úloha #3: Funkcie turn_off_leds() a render_leds()

Obe tieto funkcie slúžia na prácu s RGB diódami. Funkcia turn_off_leds() nemá žiadny parameter a po jej zavolaní všetky diódy zhasnú.

Funkcia render_leds() naopak na základe toho, koľko číslic hráč uhádol, rozsvieti príslušné RGB diódy - za každú uhádnutú číslicu na pozícii, rozsvieti jednu RGB diódu na červeno, a za každú uhádnutú číslicu, ktorá sa nenchádza na správnej pozícii, rozsvieti jednu RGB diódu na modro.

Funkcia render_leds() má nasledovné pozičné parametre:

  • const int peg_a - Počet uhádnutých číslic na správnej pozícii.
  • const int peg_b - Počet uhádnutých číslic na nesprávnej pozícii.

Funkcie nevracajú žiadnu hodnotu.

Príklad použitia

turn_off_leds();

render_leds(2, 1);
// two leds will have red color, one will have blue and last one will be off

Úloha #4: Funkcia render_history()

Úlohou tejto funkcie je vypísať na display príslušný záznam z histórie spolus jeho hodnotením.

Funkcia render_history() má nasledovné pozičné parametre:

  • char* secret - Referencia na číselnú kombináciu, ktorú je potrebné uhádnuť. Vstupný parameter.
  • char** history - Referencia na históriu pokusov.
  • const int entry - Index pozície v histórii, ktorá má byť vypísaná.

Funkcia nevracia žiadnu hodnotu.

Príklad použitia

char* history[3][4];

history[0][0] = "1234";
history[1][0] = "5678";
history[2][0] = "9012";

render_history("9347", history, 2);
// renders and evaluates "9012"

Úloha #5: Funkcia play_game()

Funkcia, ktorá reprezentuje samotnú hru od jej spustenia až po jej dohranie.

Táto funkcia je špecifická kvôli tomu, že hernú slučku bude obsahovať sama v sebe a nebude využívať funkciu loop(), ktorú ponúka Arduino. Týmto prístupom sa totiž dokážeme vyhnúť nadmernému používaniu globálnych premenných, k čomu nás väčšina príkladov/tutoriálov/knižiek venovaných Arduinu priamo povzbudzuje.

Funkcia má jeden pozičný parameter:

  • char* secret - Referencia na reťazec, ktorý reprezentuje tajný kód, ktorý treba uhádnuť v danej hre.

Funkcia po skončení nič nevracia.

Príklad použitia

void loop(){
    char* code = generate_code(false, 4);
    play_game(code);
    free(code);
}

Odovzdávanie projektu

Zadanie sa odovzdáva prostredníctvom systému na správu verzií Git na serveri git.kpi.fei.tuke.sk. Riešenie tejto úlohy odovzdáte ako súčasť vášho projektu s názvom prog-2021.

Štruktúra vášho projektu bude vyzerať nasledovne:

.
├── ps6
│   ├── ps6.ino
│   ├── lcd_wrapper.cpp
│   ├── lcd_wrapper.h
│   ├── mastermind.cpp
│   └── mastermind.h
└── README

kde význam súborov v priečinku ps6/ je nasledovný:

  • mastermind.cpp, mastermind.h - Zdrojový kód a hlavičkový súbor knižnice pre hru Mastermind (Logik).

  • lcd_wrapper.cpp, lcd_wrapper.h - Zdrojový kód a hlavičkový súbor modulu pre prácu s LCD display-om.

  • ps6.ino - Zdrojový kód (sketch) obsahujúci funkciu main().

  • README - Súbor, v ktorom bude uvedené označenie vašej skupiny, ktorú navštevujete na cvičeniach v tvare:

    GROUP : A1

Ak ste opakujúci študent, uveďte v README skupinu v tvare:

GROUP : O<P>

kde <P> nahradíte písmenom paralelky, ktorá podľa rozvrhu zodpovedá vášmu študijnému programu (napr. A pre informatikov).

Kostra projektu

Tentokrát je kostra projektu reprezentovaná len jedným hlavičkovým súborom, ktorý si môžete stiahnuť z tohto odkazu.

Hodnotenie a testovanie

Vaše hodnotenie sa bude odvíjať od výsledku automatických testov (ak sa ich podarí pripraviť) a od osobného hodnotenia vášho cvičiaceho. Overovať sa bude:

  • Štruktúra vášho projektu (či sa v ňom nachádzajú všetky potrebné súbory).
  • Statická analýza vášho kódu pomocou nástroja cppcheck.
  • Prítomnosť globálnych premenných vo vašom kóde.
  • Funkčnosť vašej implementácie.

Testovanie vašich riešení sa bude vykonávať automaticky každé 3 hodiny a to konkrétne o 0300, 0600, 0900, 1200, 1500, 1800, 2100 a 2400.

Vaše riešenia opäť prejdú kontrolou originality. Preto sa pri práci na vašom zadaní správajte podľa pravidiel etického kódexu! V prípade, že odovzdáte zadanie, ktoré nie je vaše, budete vylúčení z predmetu!

Ďalšie zdroje