Problem Set #6: Mastermind
Ciele
- Naučiť sa pracovať s prototypovacou doskou Arduino
Upozornenie
Toto zadanie je potrebné odovzdať do 26. may. 2024
23:59:59. Na diskusiu používajte kanál na slack-u
#arduino
.
Upozornenie
Pokiaľ ste sa tak dohodli so svojim cvičiacim, môžete zadanie vytvoriť aj na serveri Tinkercad.
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.
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 0 až 9.
- 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_PIN
ažBTN_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
Poznámka
Históriou sa je možné pohybovať dozadu len po prvý pokus a dopredu len po posledný pokus.
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.
Poznámka
Keďže sa na to určite budete pýtať, či má komunikácia s hráčom vyzerať presne takto, tak si všimnite v úvode výpisu text “môže vyzerať napríklad takto”: nie, vaša implementácia môže vyzerať ináč a môže zobrazovať iné texty.
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
Poznámka
Je veľmi pravdepodobné, že verzia Arduino IDE v repozitároch vašej distribúcie bude staršia, ako tá, ktorá je dostupná na oficiálnej stránke. Preto vám odporúčame miesto inštalovania Arduino IDE z repozitárov si nainštalovať najnovšiu verziu priamo zo stránky www.arduino.cc.
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.
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 hodnotutrue
, 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átiNULL
.
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
= generate_code(false, 4);
code // code = "1234";
(code)
free
// code will be generated as sequence of repeating digits of length 5
= generate_code(true, 5);
code // code = "65656";
(code);
free
// no code will be generated
= generate_code(true, -10);
code // 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;
("9347", "1234", &peg_a, &peg_b);
get_scoreassert(peg_a == 0 && peg_b == 2);
("9347", "9348", &peg_a, &peg_b);
get_scoreassert(peg_a == 3 && peg_b == 0);
("9347", "1256", &peg_a, &peg_b);
get_scoreassert(peg_a == 0 && peg_b == 0);
("9347", "9436", &peg_a, &peg_b);
get_scoreassert(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.
Poznámka
Žiadna dióda nie je spätá so žiadnou pozíciou číslice. To znamená, že hráč nesmie vedieť, že ak svieti RGB dióda č. 1, že uhádol číslicu na prvej pozícii.
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
(2, 1);
render_leds// 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
// let's have following history DYNAMICALLY allocated and initialized
char** history = {
"1234",
"5678",
"9012"
};
// then we can render it
("9347", history, 2);
render_history// 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);
(code);
play_game(code);
free}
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.
Š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 funkciumain()
.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).
Upozornenie
Ak ste sa dohodli so svojím cvičiacim, že pre riešenie tohto zadania použijete službu Tinkercad, budete obmedzení ako dostupnými komponentmi tak aj nemodulárnym prístupom k programovaniu - celý program napíšete do jedného súboru.
V tomto prípade odovzdávajte svoj projekt s nasledovnou štruktúrou:
.
├── ps6
│ └── ps6.ino
└── README
Upozornenie
Je dôležité, aby vaše súbory zachovali uvedenú štruktúru. Ak sa niektorý zo súborov síce v repozitári nachádza, ale v inom priečinku, bude to považované za chybu a takýto projekt nebude považovaný za správny! Ak sa naopak vo vašom projekte nachádzajú súbory alebo priečinky navyše, tieto nebudú považované za chybu.
Upozornenie
Pri názvoch priečinkov, súborov a obsahu súboru README
záleží na veľkosti písmen!
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
Toto zadanie sa bude odovzdávať a hodnotiť prezenčne! Za úspešné odovzdanie sa považuje také zadanie, ktoré bolo úspešne ohodnotené na minimálne 51%! Nestačí teda zadanie do termínu odovzdania len nahrať do systému na správu verzií Git, ale musí byť dovtedy aj ohodnotené!
Pri hodnotení sa bude hodnotiť:
- Štruktúra vášho projektu (či sa v ňom nachádzajú všetky potrebné súbory).
- Prítomnosť globálnych premenných vo vašom kóde.
- Funkčnosť vašej implementácie.
- Komunikácia s riešiteľom a jeho schopnosť reagovať na položené otázky prípadne jeho programátorské skúsenosti.
Upozornenie
V prípade, že skúšajúci nadobudne dojem, že odovzdávanému projektu nerozumiete, nebude vaše zadanie ohodnotené. To zároveň znamená, že nezískate zápočet za predmet a to aj napriek tomu, že budete mať dostatočný počet bodov z predchádzajúcich zadaní!
Ďalšie zdroje
Arduino: 6. Tlačítko podruhé, aneb stiskem zapni, stiskem vypni