Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2021:dbrigalda:2048-deluxe [2021/05/23 14:51]
ionut.ranja [Hardware Design]
pm:prj2021:dbrigalda:2048-deluxe [2021/05/27 00:30] (current)
ionut.ranja [Rezultate Obţinute]
Line 34: Line 34:
  
 === Schema Electrică === === Schema Electrică ===
-{{ :​pm:​prj2021:​dbrigalda:​schema_eagle_2048_deluxe.png?​nolink&​800 |}}+{{ :​pm:​prj2021:​dbrigalda:​schema_eagle_2048_deluxe.png?​nolink&​725 |}} 
 + 
 + 
 +=== Hardware === 
 +Mai jos se găsesc poze cu montajul hardware realizat și cu câteva imagini din joc: 
 +  * **Montaj** 
 +{{ :​pm:​prj2021:​dbrigalda:​montaj_2048_deluxe.jpg?​nolink&​800 ​|}} 
 +  * **Meniu principal** 
 +{{ :​pm:​prj2021:​dbrigalda:​menu_2048_deluxe.jpg?​nolink&​350 |}} 
 +  * **Highscores** 
 +{{ :​pm:​prj2021:​dbrigalda:​scores_2048_deluxe.jpg?​nolink&​350 |}} 
 +  * **Start Game** 
 +{{ :​pm:​prj2021:​dbrigalda:​gameinit_2048_deluxe.jpg?​nolink&​350 |}} 
 +  * **Game Won** 
 +{{ :​pm:​prj2021:​dbrigalda:​won_2048_deluxe.jpg?​nolink&​350 ​|}}
 ===== Software Design ===== ===== Software Design =====
 <​note>​ <​note>​
Line 79: Line 93:
 </​note>​ </​note>​
 == Funcții folosite == == Funcții folosite ==
-<​note>​ 
-Funcții specifice jocului 
-    * **GAME_GameLogic** 
-      * se apelează în loop și apelează diverse funcții în funcție de starea curentă a jocului 
-    * **GAME_MoveUp/​Down/​Left/​Right** 
-      * mută piesele în direcția specifică funcției (+ merge numere cu aceeași valoare) și generează o piesă nouă pe tabla de joc 
-    * **GAME_GeneratePiece** 
-      * generează o piesă nouă (2 sau 4) într-o poziție liberă de pe tabla de joc 
-    * **GAME_CheckIfLost/​Won** 
-      * verifică dacă jocul s-a terminat (cu victoria sau înfrângerea jucătorului) 
-    * **ISR(TIMER1_COMPA_vect)** 
-      * întrerupere după timer1 la valoare din OCR1A; la fiecare 3 secunde se scad 10 puncte din scor 
-</​note>​ 
 <​note>​ <​note>​
 Funcții specifice Arduino Funcții specifice Arduino
Line 107: Line 108:
     * **DISPLAY_ResetGame**     * **DISPLAY_ResetGame**
       * realizează resetarea întregului joc și reafișarea frame-ului de la începutul jocului       * realizează resetarea întregului joc și reafișarea frame-ului de la începutul jocului
 +    * **DISPLAY_GameLogic**
 +      * se apelează în loop și apelează diverse funcții în funcție de starea curentă a jocului
 +    * **DISPLAY_MoveUp/​Down/​Left/​Right**
 +      * mută piesele în direcția specifică funcției (+ merge numere cu aceeași valoare) și generează o piesă nouă pe tabla de joc
 +    * **DISPLAY_GeneratePiece**
 +      * generează o piesă nouă (2 sau 4) într-o poziție liberă de pe tabla de joc
 +    * **DISPLAY_CheckIfLost/​Won**
 +      * verifică dacă jocul s-a terminat (cu victoria sau înfrângerea jucătorului)
 +    * **ISR(TIMER1_COMPA_vect)**
 +      * întrerupere după timer1 la valoare din OCR1A; la fiecare 3 secunde se scad 10 puncte din scor
 </​note>​ </​note>​
 <​note>​ <​note>​
Line 123: Line 134:
       * întrerupere pentru conversia ADC; folosită pentru a citi valorile specifice axelor Ox sau Oy ale joystick-ului       * întrerupere pentru conversia ADC; folosită pentru a citi valorile specifice axelor Ox sau Oy ale joystick-ului
 </​note>​ </​note>​
 +
 +=== Analiza programului ===
 +
 +În funcția de **setup** se pregătește configurația inițială a jocului:
 +  * se pornesc //AD//C și //​întreruperea de ADC//
 +  * se setează întreruperea după //timer1// la valoarea din //OCR1A//, adică la fiecare 3 secunde
 +  * se creează două piese de **1024** pe tabla de joc pentru a putea analiza rapid toate funcțiile apelate în caz de victorie. Când jocul este resetat folosind funcția **DISPLAY_ResetGame** aceste două piese amplasate special nu se vor mai afla în tabla de joc.
 +  * se realizează inițializarea led-ului, a buzzerului, a celor 3 butoane, a joystick-ului și a display-ului
 +  * se activează întreruperile externe pentru //​PCINT//​-uri
 +  * se setează led-ul RGB pe alb și display-ul printează meniul principal apelând **DISPLAY_PrintMenu**
 +
 +În funcția de **loop** se apelează doar **DISPLAY_GameLogic** care se va ocupa de toată logica jocului.
 +În funcția de //​GameLogic//​ se apelează diverse alte funcții după valoarea variabilei //​g_state//​. La începutul programului variabila are valoarea
 +//​quit_state//​ care indică faptul că fie ne aflăm la începutul rulării, fie că s-a apăsat butonul //quit//, iar jocul a fost resetat. În această
 +stare se citește cu **ARDUINO_MyRead** valoarea de pe axa Oy a joystick-ului. Dacă scade/​crește față de pragul de repaus, atunci se schimbă
 +valoarea variabilei //​g_option//​ fie în //scores// (joystick-ul a fost mutat în jos și a fost selectat //​Highscores//​),​ fie în //start//
 +(joystick-ul a fost mutat în sus și a fost selectat //Start Game//). În această stare se printează meniul principal cu selecția conform //​g_option//,​
 +se redă un sunet specific operației de //select// și se schimbă culoarea led-ului.
 +
 +Cât timp jocul se află în starea de //​quit_state//​ singurele butoane care pot schimba starea sunt **quit** (care duce la resetarea jocului și, implicit,
 +la întoarcerea în //​quit_state//​ cu //​g_option//​ setat pe //start//) sau **continue** care va schimba starea fie în //​score_state//,​ fie în //​game_state//​.
 +
 +În cazul //​score_state//​ se apelează funcția **DISPLAY_PrintScores** care va afișa primele 5 cele mai mari scoruri obținute în joc sub forma
 +//X. [][][] - SCORE// unde **X** reprezintă un număr de la 1 la 5, **[]** reprezintă un caracter de la A la Z iar **SCORE** reprezintă scorul jucătorului
 +identificat de cele 3 caractere. Aceste date sunt preluate din memoria EEPROM a plăcuței Arduino, iar fiecare intrare reprezintă 5 bytes (3 pentru
 +numele jucătorului și 2 pentru scor - //int// este reprezentat pe 2 bytes).
 +Din această stare se poate reveni doar la starea //​quit_state//​ apăsând **quit**.
 +
 +În cazul //​game_state//​ se citesc atât valoarea pe Oy cât și valoarea pe Ox a joystick-ului pentru a ști ce funcție trebuie apelată în continuare.
 +Este posibil să se apeleze o singură funcție la un moment dat dintre cele 4 funcții **DISPLAY_MoveUp/​Down/​Left/​Right** în funcție de valorile citite
 +pe x și pe y, apoi se va apela funcția **DISPLAY_PrintBoard** care va afișa scorul și piesele curente de pe tabla de joc. //​PrintBoard//​ apelează
 +**DISPLAY_PrintPiece** pentru a afișa centrat orice piesă indiferent de valoare folosind calcule care țin cont de valorile posibile ale pieselor și
 +de numărul de pixeli ocupați pe axa Ox a display-ului (3 pixeli + 1 pixel spațiu).
 +
 +Funcțiile //MoveXYZ// folosesc același algoritm cu modificări în funcție de direcție, pentru simplitate voi explica ce se întâmplă în cazul //MoveUp//, pentru
 +celelalte cazuri ideea este asemănătoare. //MoveUp// iterează prin fiecare linie, coloană cu coloană căutând o piesă validă (valoarea != 0). Când
 +întâlnește o astfel de piesă începe să o „tragă” în sus până la o linie de stop; aici există două cazuri:
 +  - nu există o altă piesă până la linia de stop sau, există o altă piesă, dar de valoare diferită de piesa curentă
 +    {{ :​pm:​prj2021:​dbrigalda:​caz1_2048_deluxe.png?​nolink&​800 |}}
 +  - există o altă piesă de aceeași valoare cu piesa curentă, se va executa combinarea pieselor și se va actualiza linia de stop
 +    {{ :​pm:​prj2021:​dbrigalda:​caz2_2048_deluxe.png?​nolink |}}
 +În cazul 2. se verifică dacă prin combinarea celor 2 piese s-a obținut **2048** apelând **DISPLAY_CheckIfWon**.
 +La final după ce toate piesele au fost mutate în locul corespunzător se redă un sunet specific acțiunii de //move//, led-ul își schimbă culoarea
 +și se generează o noua piesă apelând **DISPLAY_GeneratePiece**.
 +
 +//​GeneratePiece//​ iterează prin vectorul g_empty_tiles selectând doar spațiile goale (valoarea == //empty//) din tabla de joc și apoi selectează
 +aleatoriu un spațiu din cele goale în care să pună un 2 sau un 4 (90% șansă pentru 2 și 10% pentru 4). Dacă în urma generării unei piese noi nu
 +mai există niciun spațiu liber pe tabla de joc se verifică dacă jocul a fost sau nu pierdut apelând **DISPLAY_CheckIfLost**. //​CheckIfLost//​ verifică
 +dacă se poate realiza cel puțin o combinație mutând sus/​jos/​stânga/​dreapta,​ caz în care jocul nu a fost încă pierdut, altfel jocul s-a terminat și
 +jucătorul a pierdut.
 +
 +//​CheckIfWon//​ este o funcție simplă în care se verifică dacă jucătorul a obținut **2048**, caz în care starea curentă se schimbă în //​win_state//​.
 +Alte stări posibile din //​game_state//​ sunt //​pause_state//​ (a fost apăsat butonul //pause//), //​quit_state//​ (a fost apăsat butonul //quit//) sau,
 +conform celor menționate mai sus, în stare //​lose_state//​.
 +
 +Starea //​pause_state//​ afișează pe ecran un mesaj corespunzător (//GAME PAUSED!//) și setează //g_pause// pe 1, oprind scăderea scorului cu 10 puncte
 +care se întâmplă în timpul stării //​game_state//​. Această stare ascunde tabla de joc pentru a nu oferi jucătorului timp de gândire fără penalizarea
 +scorului. Din //​pause_state//​ se poate reveni în //​game_state//​ apăsând pe butonul //​continue//​ care va afișa tabla de joc de la momentul de timp anterior
 +apăsării butonului de //pause//.
 +
 +În starea //​lose_state//​ se afișează un mesaj corespunzător,​ se redă o melodie scurtă specifică înfrângerii și se setează led-ul pe roșu. În final se
 +resetează jocul apelând **DISPLAY_ResetGame** care zeroizează tabla de joc, resetează starea la //​quit_state//,​ precum și celelalte variabile la valorile
 +inițiale.
 +
 +Starea //​win_state//​ este mai specială (funcția **DISPLAY_PrintWin**). Inițial, se urmează pașii de la //​lose_state//​ afișând un mesaj corespunzător,​ melodia din //​g_win_melody//​
 +și schimbând culorile led-ului; după ce se termină această etapă, se realizează citirea valorilor de pe Ox și Oy ale joystick-ului pentru a itera
 +prin 3 caractere '​A''​A''​A'​ care pot fi schimbate în intervalul A-Z. Când jucătorul și-a ales numele, acesta va apăsa pe butonul //​continue//​
 +pentru a începe operația de înregistrare a scorului său în top. Dacă se apasă pe //quit// în loc de //​continue//,​ atunci se va reseta jocul, iar
 +scorul nu va fi înregistrat.
 +Înregistrarea scorului presupune obținerea datelor din memoria EEPROM și identificarea primului scor mai mic decât cel obținut de jucător. Dacă
 +nu există niciun scor mai mic decât cel curent, atunci nu se înregistrează,​ în caz contrar, scorul curent îl înlocuiește pe cel din top, iar restul
 +scorurilor mai mici ca acesta sunt coborâte cu o poziție (inclusiv cel înlocuit).
 +
 +După ce jucătorul a câștigat/​pierdut jocul, se realizează resetarea acestuia și întoarcerea în meniul principal. Acum acesta poate porni un joc nou
 +sau poate vedea noul top.
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
-TODO +Proiectul a ieșit în mare parte exact cum mi-am propus de la început. Din păcate am rămas foarte rapid fără pini liberi pe plăcuța Arduino și a trebuit 
-<note tip> +să renunț la ideea originală ​în care foloseam mai multe led-uri și buzzere pentru //quality of life//, dar am reușit să mă încadrez în pinii 
-Care au fost rezultatele obţinute ​în urma realizării proiectului vostru+puși la dispoziție de plăcuță. În afară de acest mic inconvenient am realizat exact tot ceea ce am dorit să fac pentru acest proiect. Personal, consider 
-</​note>​+că rezultatul final este mult mai bun față de imaginea pe care o aveam la început ;-).
  
 +== Link YouTube 4K ==
 +[[https://​www.youtube.com/​watch?​v=4oP4yuQnGWk|{{:​pm:​prj2021:​dbrigalda:​montaj_2048_deluxe.jpg?​500|}}]]
 ===== Concluzii ===== ===== Concluzii =====
-TODO+Când am început lucrul efectiv pentru proiect am avut multe momente când nu știam cu siguranță dacă ceea ce mi-am propus era în totalitate posibil 
 +de realizat, majoritatea problemelor venind din partea lucrului cu LCD-ul; am trecut prin multe iterații ale mesajelor afișate și ale reprezentării 
 +pieselor pe ecran. Am căutat foarte multe biblioteci care să ofere suport pentru un font mai mic astfel încât să încapă 4 numere pe 4 cifre pe o 
 +linie. Din păcate, majoritatea bibliotecilor disponibile pentru lucrul cu Nokia 5110 nu aveau nici măcar pe aproape la fel de multe funcționalități 
 +precum biblioteca din partea ADAFRUIT. Pe această problemă am pierdut cel mai mult timp, în final alegând să rămân la ADAFRUIT și găsind după foarte 
 +multe căutări o bibliotecă de fonturi compatibile cu //​Adafruit_GFX//​. 
 + 
 +Un alt **challenge**,​ din nefericire, a venit încă de la început când am primit piesele. Ecranul Nokia 5110 nu a venit lipit (nu mai există modelul 
 +gata lipit) și a trebuit să realizez lipirea ecranului pe coloana de pini :-(. Rezultatul putea fi mai bun, dar cel puțin funcționează cum trebuie :-). 
 + 
 +Cu toate acestea, am reușit să duc proiectul la bun sfârșit și consider că am reușit să aprofundez mai mult și mai bine noțiunile prezentate la 
 +laborator. Proiectul a fost într-adevăr o provocare foarte bună care a venit ca un suport pentru ce ne-a fost prezentat atât la curs cât și în 
 +cadrul laboratoarelor. 
 + 
 +De-a lungul procesului de realizare a proiectului am obținut motivația de a face și alte astfel de proiecte orientate pe partea de hardware. Concluzionând,​ 
 +consider că proiectul a fost un challenge bine-venit și sunt foarte satisfăcut de rezultatul final :-D.
 ===== Download ===== ===== Download =====
-TODO +<​note>​ 
-<​note ​warning+Arhiva ​cu sursele
-O arhivă (sau mai multe dacă este cazul) ​cu fişierele obţinute în urma realizării proiectuluisurse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). + 
-Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:​prj20??:​c?:​nume_student** (dacă este cazul)**Exemplu:​** Dumitru Alin, 331CC -> **:​pm:​prj2009:​cc:​dumitru_alin**.+{{:pm:prj2021:dbrigalda:ranja_ionut_335cc_pm_2048_deluxe.zip|2048_Deluxe.zip}}
 </​note>​ </​note>​
 ===== Jurnal ===== ===== Jurnal =====
Line 141: Line 244:
   * 23.04.2021 - Am creat pagina de wiki.   * 23.04.2021 - Am creat pagina de wiki.
   * 25.04.2021 - Am completat secțiunile necesare din wiki conform assignment-ului de pe moodle.   * 25.04.2021 - Am completat secțiunile necesare din wiki conform assignment-ului de pe moodle.
 +  * 07.05.2021 - Am finalizat în mare parte jocul 2048.
 +  * 13.05.2021 - Am terminat proiectul + adăugat toate componentele.
 +  * 22.05.2021 - Am făcut clean up codului sursă + coding style + completat pagina de wiki.
 +  * 23.05.2021 - Am terminat pagina de wiki.
 +  * 26.05.2021 - Am pus poze + link youtube.
 </​note>​ </​note>​
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
-TODO +=== Biblioteci externe === 
-<​note>​ +  * [[ https://​github.com/​adafruit/​Adafruit-GFX-Library|Adafruit_GFX.h ]] 
-Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse ​Software** şi **Resurse Hardware**. +  * [[ https://​github.com/​adafruit/​Adafruit-PCD8544-Nokia-5110-LCD-library|Adafruit_PCD8544.h ]] 
-</note> +  ​[[ https://​github.com/​robjen/​GFX_fonts|Font4x7Fixed.h ]] 
 +=== Resurse ​Eagle === 
 +  ​[[ https://​github.com/​adafruit/​Adafruit-Eagle-Library | adafruit.lbr ]] 
 +    ​schema Eagle pentru Arduino Uno R3 
 +  ​[[ https://​www.diymodules.org/​eagle|diy-modules.lbr ]] 
 +    ​diverse scheme Eagle compatibile cu Arduino (cum ar fi display-ul Nokia 5110) 
 +  ​[[ https://​github.com/​sparkfun/​SparkFun-Eagle-Libraries/​blob/​master/​SparkFun-LED.lbr|SparkFun-LED.lbr ]] 
 +    ​led RGB catod comun 
 +=== Bibliografie/​alte resurse === 
 +  * Laboratoarele de pe OCW 
 +  * Google ;-) 
 +  * [[ https://​ocw.cs.pub.ro/​courses/​_media/​pm/​lab/​uno.jpg?​cache=|Pinout Arduino Uno ]] 
 +  * [[ https://​ww1.microchip.com/​downloads/​en/​DeviceDoc/​Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf|Datasheet ATMEGA328P ]] 
 +  * [[ https://​app.diagrams.net/​|draw.io ]] 
 +  * [[ https://​www.autodesk.com/​products/​eagle/​free-download|Eagle ]] 
 +  * [[ https://​www.arduino.cc/​en/​software|Arduino IDE ]]
 ==== Pagina în format PDF ==== ==== Pagina în format PDF ====
 ---- ----
 <​note>​[[https://​ocw.cs.pub.ro/​courses/​pm/​prj2021/​dbrigalda/​2048-deluxe?​do=export_pdf | 2048-deluxe.pdf]]</​note>​ <​note>​[[https://​ocw.cs.pub.ro/​courses/​pm/​prj2021/​dbrigalda/​2048-deluxe?​do=export_pdf | 2048-deluxe.pdf]]</​note>​
  
pm/prj2021/dbrigalda/2048-deluxe.1621770703.txt.gz · Last modified: 2021/05/23 14:51 by ionut.ranja
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0