Table of Contents

Wordle

Nume: Marian Melania-Valentina

Grupă: 331CC

Introducere

Proiectul este bazat pe faimosul joc Wordle. Ideea jocului este următoarea: utilizatorul are 6 încercări pentru a ghici un cuvânt în limba engleză, format din 5 litere - în urma fiecărui cuvânt introdus, utilizatorul primește indicii legate de literele ce aparțin cuvântului, prin colorarea căsuței corespunzătoare fiecărei litere astfel:

Descriere generală

Utilizatorul interacționează cu jocul prin intermediul tastaturilor matriceale 4×4, fiecare literă fiind reprezentată printr-un buton al tastaturilor. De asemenea, există pe a doua tastatură un buton ce are asociată acțiunea de Enter (înregistrarea cuvântului în joc) și un buton cu acțiunea de ștergere a unei litere din cuvânt. Pe ecranul LCD există un buton de reset, a cărui apăsare declanșează reînceperea jocului. Întregul joc este afișat pe ecranul LCD, iar în momentul finalizării jocului se aprinde unul dintre cele două led-uri, în funcție de rezultatul jucătorului: dacă cuvântul a fost ghicit, se aprinde led-ul verde, iar dacă jucătorul nu a ghicit cuvântul, se aprinde cel roșu.

Hardware Design

Listă de piese utilizate:

Schema electrică, realizată în Fusion:

Close-up label-uri:

Componentele sunt conectate la placă astfel:

Software Design

Am realizat implementarea software în mediul de dezvoltare PlatformIO. Limbajul utilizat pentru dezvoltarea proiectului este C++.

Biblioteci utilizate:

Selectarea cuvântului

La începutul fiecărui joc, programul alege în mod aleator un cuvânt pe care utilizatorul trebuie să îl ghicească. Pentru stocarea cuvintelor de ghicit, am creat o matrice de caractere, pe fiecare linie a acesteia aflându-se un cuvânt. Pentru alegerea aleatoare a unui cuvânt, am utilizat funcția analogRead() pe un pin analogic care nu era conectat la nimic, aceasta întorcând un număr random.

// selectarea unui cuvânt random
  random_row = analogRead(A15) % 50;
  for(int i = 0; i < 6; i ++) {
      selected_word[i] = all_words[random_row][i];
  }

Implementarea desfășurării jocului

În funcția loop() am implementat desfășurarea unui joc complet. Utilizatorul are 6 încercări pentru a ghici cuvântul, interacționând în fiecare rundă cu tastaturile astfel:

Voi introduce bucăți din codul funcției loop(), pentru o înțelegere mai aprofundată a implementării, unde:

Afișarea unei litere pe ecran

if(pressedLetter1 && pressedLetter1 != '#' && pressedLetter1 != '*' && pressedLetter1 != '1' && pressedLetter1 != '2'
              && pressedLetter1 != '3' && pressedLetter1 != '4' && i < 5) {
 
          // afișarea literei apăsate
          tft.setTextColor(TFT_WHITE);
          tft.setCursor(letter_x, letter_y);
          tft.setTextFont(1);
          tft.setTextSize(3);
          tft.print(pressedLetter1);
 
          // updatarea coordonatelor pentru următoarea literă
          letter_x += 60;
          box_x += 60;
 
          // updatarea cuvântului curent
          guess[i] = pressedLetter1;
          i ++;
          continue;
        }

Ștergerea unei litere

if(pressedLetter2 && pressedLetter2 == '#') {
 
          // verificăm să nu ieșim din parametrii zonei de joc
          if(letter_x >= 92 && letter_x <= 332 && i >= 1 && i <= 5) {
            // updatăm coordonatele pentru a ne întoarce la litera anterioară
            box_x -= 60;
            letter_x -= 60;
            i --;
            // ștergerea literei prin desenarea unui pătrat peste cel existent
            tft.drawRect(box_x, box_y, 50, 50, SQUARE_INITIAL);
            tft.fillRect(box_x, box_y, 50, 50, SQUARE_INITIAL);
            // updatare cuvânt ghicit
            guess[i] = '0';
          }
          continue;
        }

Apăsarea tastei ENTER

if(pressedLetter2 && pressedLetter2 == '*' && i == 5) {
          valid_enter = 1;
          box_x = 15;
          letter_x = 32;
          // verificăn ce litere din cuvântul introdus corespund cu cele din cuvântul care trebuie ghicit
          validateGuess(selected_word, guess, box_x, box_y, letter_x, letter_y);
 
          // verficăm dacă s-a ghicit cuvântul
          if(isGuessCorrect(selected_word, guess)) {
            end_game = true;
            delay(1000);
 
            // aprindem led-ul verde pentru câștig
            digitalWrite(ledPinGreen, HIGH);
            continue;
          }
          // verificam dacă s-a terminat jocul și cuvântul nu a fost ghicit 
          if(!isGuessCorrect(selected_word, guess) && tries == 0) {
            end_game = true;
            delay(1000);
 
            // aprindem led-ul roșu pentru pierdere
            digitalWrite(ledPinRed, HIGH);
            continue;
          }
        }

Verificarea cuvintelor

Pentru verificarea literelor comune dintre cuvântul introdus și cel care trebuie ghicit, am creat funcția checkWord(), care returnează un șir ce conține caracterele 0, 1 sau 2 corespunzătoare celor 5 litere, care este folosit de funcția validateGuess() pentru a crea animația astfel:

Funcția de realizare a animației

void validateGuess(char selected_word[], char guess[], int box_x, int box_y, int letter_x, int letter_y) {
  String color_codes = checkWord(selected_word, guess);
  for(int i = 0; i < 5; i ++) {
      delay(500);
 
      colorBox(color_codes, box_x, box_y, i);
      writeLetter(guess, letter_x, letter_y, i);
 
      box_x += 60;
      letter_x += 60;
    }
}

Afișarea rezultatelor

În urma finalizării jocului, pe ecran apare un mesaj în funcție de rezultatul obținut:

Am implementat această funcționalitate folosind întreruperi, care se declanșau în urma detectării trecerii pinilor led-urilor din starea LOW în starea HIGH. De asemenea, am configurat led-urile pe pinii 2 și 3, care suportă întreruperi pe ATMEGA.

// în funcția setup()
  attachInterrupt(digitalPinToInterrupt(ledPinGreen), ISRCastig, RISING);
  attachInterrupt(digitalPinToInterrupt(ledPinRed), ISRPierdere, RISING);
 
// funcția ISR pentru câștig
void ISRCastig() {
  tft.setTextColor(TFT_GREEN);
  tft.setCursor(50, 420);
  tft.setTextFont(1);
  tft.setTextSize(4);
  tft.print("YOU WIN!:)");
}
 
// funcția ISR pentru pierdere
void ISRPierdere() {
  tft.setTextColor(TFT_RED);
  tft.setCursor(70, 420);
  tft.setTextFont(1);
  tft.setTextSize(3);
 
  tft.print("YOU LOSE!:(");
 
  tft.setTextColor(TFT_WHITE);
  tft.setCursor(55, 450);
  tft.setTextFont(1);
  tft.setTextSize(2);
 
  tft.print("The word was ");
  tft.setTextColor(TFT_GREEN);
  tft.print(selected_word);
}

Rezultate Obţinute

În aceste poze se observă aspectul jocului în urma câștigării sau pierderii unui joc.

Am înregistrat, de asemenea, și un videoclip cu o demonstrație a jocului: Wordle - Proiect PM

Concluzii

Pentru mine, realizarea acestui proiect a fost foarte interesantă, atât datorită faptului că am avut ocazia de a implementa unul dintre jocurile mele preferate, dar și deoarece am experimentat pentru prima oară realizarea unui proiect ce implică o placă Arduino de la 0, realizând atât conectarea acesteia de celelalte componente hardware, cât și implementarea codului.

Download

marian_melania_proiect_pm.zip - Arhivă Proiect

Jurnal

Bibliografie/Resurse

Resurse Hardware

Resurse Software

  1. TFT_HX8357 - bibliotecă LCD
  2. Keypad - bibliotecă tastaturi matriceale
  3. Laborator 0 - LED-uri
  4. Laborator 2 - Întreruperi
  5. Laborator 5 - SPI, folosit de ecranul LCD