Wordle

Introducere

  • Proiectul vine de la jocul Wordle, un joc implementat de New York Times in care trebuie sa ghicesti un cuvant de 5 litere in 6 incercari. Ca indicii, se va efectua o colorare a literelor care sunt in cuvant, dar nu pe aceeasi pozitie ca si cuvantul cautat, cu galben, iar cu verde literele din cuvant pe aceeasi pozitie. Cele care nu exista in cuvant vor fi colorate cu gri.
  • Scopul proiectului este de a implementa acest joc in format fizic.
  • Este important sa avem un vocabular cat mai extins, dar poate fi greu sa il mentinem.
  • Jocul ajuta mentinerea si chiar extinderea acestui vocabular.

Descriere generală

Schema Bloc:

Descriere:

  • Jocul primeste input de la tastatura(un cuvant de 5 litere)
  • Il prelucreza si transmite literele care sunt in cuvant(conform regulilor descrise mai devreme)
  • Jocul se termina cand a ghicit cuvantul sau cand ramane fara incercari

Hardware Design

Listă de piese:

  • 1 x Arduino UNO
  • 1 x LCD de 2.8'' cu SPI și Controller ILI9341
  • 1 x Keyboard
  • 1 x Translator de Nivel Bidirectional cu 4 Canale

Schema Electrica:

Rolul LCD-ului este de a arata interfata pe care se va joca Wordle. Pentru conectarea LCD-ului am folost pinii:

  • GND ↔ GND;
  • VCC ↔ 3.3 V;
  • CLK ↔ Pinul digital 13;
  • MOSI ↔ Pinul digital 11;
  • RES ↔ Pinul digital 8;
  • DC ↔ Pinul digital 9;
  • CS1 ↔ Pinul digital 10;

Rolul tastaturii este de a putea insera caractere intr-un mod cat mai usor. Pentru conectarea tastaturii am taiat cablul acesteia si am conectat 4 fire:

  • Cablul rosu ↔ 5V;
  • Cablul galben ↔ GND;
  • Cablul verde(CLOCK) ↔ Pinul digital 3;
  • Cablul alb(DATA) ↔ Pinul digital 4;

Implementare fizica

wordle_without_keyboard.jpeg

Pentru functionarea ecranului LCD ili9341 a trebuit sa folosesc un Translator de Nivel Bidirectional cu 4 Canale, pentru CLK, MOSI, RES si DC, deoarece display-ul functiona pe 3v3, iar placuta arduino pe 5v. De asemenea, am realizat un divizor de tensiune pentru CS1, deoarce acesta este un canal unidirectional si nu aveam nevoie sa translatam in ambele parti.

wordle_with_keyboard_wide.jpeg

Pentru keyboard, am taiat cablul de ps/2 de la tastatura si am vazut cele 4 fire descrise si mai sus. Dupa ce le-am identificat si am facut un test cu osciloscopul ca trimite bine semnalele, am conectat-o la arduino.

playing_mode.jpeg

Tot ce tine de logica jocului si design-ul acestuia este realizat din software si descris mai jos.

Final Look

wordle_in_box.jpeg

Software Design

Acest cod este un exemplu de implementare a jocului Wordle folosind o placă Arduino și un ecran TFT ILI9341, controlate prin intermediul unei tastaturi PS2. Iată o scurtă descriere a codului:

Mediul de Dezvoltare

Codul este scris în limbajul C++ și este destinat să fie rulat pe o placă Arduino. Utilizează librăriile PS2Keyboard, SPI, Adafruit_GFX, și Adafruit_ILI9341 pentru a comunica cu tastatura PS2 și afișajul TFT ILI9341.

Diagrama de Stari a jocului

Pentru a putea alege intre cele doua optiuni din meniu se vor folosi sagetile de la tastatura (UP si DOWN).

Algoritmi și Structuri Implementate:

  • Codul implementează jocul Wordle, în care jucătorul trebuie să ghicească un cuvânt ascuns de cinci litere.
  • Se utilizează un set predefinit de cuvinte pentru a alege cuvântul ascuns la începutul fiecărei sesiuni de joc.
  • Jucătorul are șase încercări de a ghici cuvântul ascuns.
  • Pentru fiecare ghicire, jucătorul primește feedback vizual sub formă de culori pentru fiecare literă din încercare.
  • Jocul se desfășoară într-un ciclu continuu până când jucătorul câștigă sau pierde, iar apoi are opțiunea de a relua jocul sau de a citi regulile.

Surse și Funcții Implementate:

Codul implementează funcții pentru inițializarea și resetarea jocului, desenarea meniului, afișarea regulilor jocului, gestionarea feedback-ului pentru ghicirea cuvântului, precum și gestionarea intrărilor de la tastatură. Implementează un ciclu loop() care verifică disponibilitatea intrărilor de la tastatură și gestionează comenzile utilizatorului în funcție de starea jocului și a meniului.

resetGame():

Această funcție este responsabilă pentru resetarea jocului la începutul unei sesiuni noi. Alege un cuvânt ascuns aleatoriu din lista de cuvinte și resetează toate variabilele necesare pentru următoarea încercare de ghicire.

void resetGame() {
targetWord = wordList[random(0, wordCount)];
currentGuess = 0;
charIndex = 0;
memset(guess, 0, sizeof(guess));
gameOver = false;
// Clear the display and redraw the grid
display.fillScreen(ILI9341_BLACK);
display.setTextColor(ILI9341_WHITE);
display.setTextSize(2);
// Draw empty grid for guesses
for (int i = 0; i < maxGuesses; i++) {
  for (int j = 0; j < 5; j++) {
    display.drawRect(gridStartX + j * (boxWidth + boxSpacing), gridStartY + i * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_WHITE);
  }
}

}

drawMenu():

Această funcție este responsabilă pentru desenarea meniului pe ecran. Afișează titlul jocului și opțiunile de meniu disponibile.

void drawMenu() {
display.fillScreen(ILI9341_BLACK);
// Draw "WORDLE" title
display.setTextSize(4);
display.setTextColor(ILI9341_WHITE);
for (int i = 0; i < 6; i++) {
  display.fillRect(menuX + i * (boxWidth + 4), menuY - titleSpacing, boxWidthMenu, boxHeightMenu, ILI9341_GREEN);
  display.setCursor(menuX + i * (boxWidth + 4) + 4, menuY - titleSpacing + 8);
  display.print("WORDLE"[i]);
}
// Draw menu options
display.setTextSize(2);
display.setTextColor(ILI9341_WHITE);
display.setCursor(menuX, menuY + titleSpacing);
for (int i = 0; i < menuOptionCount; i++) {
  if (i == currentOption) {
    display.setTextColor(ILI9341_GREEN); // Highlight current option
  } else {
    display.setTextColor(ILI9341_WHITE);
  }
  display.println(menuOptions[i]);
  display.setCursor(menuX, menuY + titleSpacing + (i + 1) * menuSpacing);
  }
}
startWordleGame():

Această funcție conține logica jocului Wordle. Așteaptă intrările de la tastatură, validează ghicirile utilizatorului și oferă feedback vizual pentru fiecare încercare de ghicire.

void startWordleGame() {
// Reset the game
resetGame();
// Game loop
while (!gameOver) {
  if (keyboard.available()) {
    char c = keyboard.read();
    if (c >= 'a' && c <= 'z') {
      c = c - 'a' + 'A'; // convert to uppercase
    }
    if (charIndex < 5 && c >= 'A' && c <= 'Z') {
      guess[charIndex] = c;
      display.setCursor(gridStartX + charIndex * (boxWidth + boxSpacing) + 8, gridStartY + currentGuess * (boxHeight + boxSpacing) + 8);
      display.print(c);
      charIndex++;
    }
    if (c == PS2_ENTER && charIndex == 5) {
      guess[5] = '\0'; // Null-terminate the guess
      // Determine box colors based on the guess
      for (int i = 0; i < 5; i++) {
        if (guess[i] == targetWord[i]) {
          display.fillRect(gridStartX + i * (boxWidth + boxSpacing), gridStartY + currentGuess * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_GREEN);
        } else if (strchr(targetWord, guess[i])) {
          display.fillRect(gridStartX + i * (boxWidth + boxSpacing), gridStartY + currentGuess * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_YELLOW);
        } else {
          display.fillRect(gridStartX + i * (boxWidth + boxSpacing), gridStartY + currentGuess * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_DARKGREY);
        }
        display.setCursor(gridStartX + i * (boxWidth + boxSpacing) + 8, gridStartY + currentGuess * (boxHeight + boxSpacing) + 8);
        display.setTextColor(ILI9341_WHITE);
        display.print(guess[i]);
      }
      if (strcmp(guess, targetWord) == 0) {
        showPopup("You Win!", "");
        gameOver = true;
        return;
      }
      currentGuess++;
      charIndex = 0;
      memset(guess, 0, sizeof(guess));
      if (currentGuess == maxGuesses) {
        char buffer[30];
        sprintf(buffer, "The word is: %s", targetWord);
        showPopup("You lose!", buffer);
        gameOver = true;
        return;
      }
    }
    if (c == PS2_BACKSPACE && charIndex > 0) {
      charIndex--;
      guess[charIndex] = '\0';
      display.fillRect(gridStartX + charIndex * (boxWidth + boxSpacing), gridStartY + currentGuess * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_BLACK);
      display.drawRect(gridStartX + charIndex * (boxWidth + boxSpacing), gridStartY + currentGuess * (boxHeight + boxSpacing), boxWidth, boxHeight, ILI9341_WHITE);
    }
  }
 }
}

Rezultate Obţinute

Rezultatele obținute în urma realizării proiectului a fost implementarea efectiva a jocului Wordle.

Funcționalitatea Jocului Wordle:
  • Am reușit să implementez jocul Wordle, care permite utilizatorilor să ghicească un cuvânt de cinci litere într-un număr maxim de șase încercări.
  • Jocul oferă feedback vizual clar pentru fiecare ghicire, utilizând culorile verde, galben și gri pentru a indica pozițiile corecte, literele corecte dar plasate greșit și literele incorecte.
Interfața Grafică și Interacțiunea cu Utilizatorul:
  • Am realizat o interfață grafică atractivă folosind ecranul TFT Adafruit ILI9341.
  • Utilizatorii pot naviga ușor în meniul principal și pot alege între opțiunile de vizualizare a regulilor jocului sau începerea unui joc nou.
  • Feedback-ul vizual este prezentat clar și într-un mod ușor de înțeles pentru utilizatori.
Meniul și Opțiunile de Joc:
  • Meniul principal permite utilizatorilor să acceseze regulile jocului sau să înceapă un nou joc.
  • Am implementat și un popup pentru afișarea regulilor jocului, oferind utilizatorilor o experiență informativă și intuitivă.

Concluzii

Proiectul a demonstrat că este posibil să fie implementat un joc interactiv și educativ pe o platformă de microcontrolere, utilizând ecranul TFT și tastatura PS2.

De asemenea, de la inceput am vrut ca jocul sa fie cat mai usor de jucat, de aceea am implementat inserarea cuvintelor prin tastatura.

Sper ca prin acest proiect o sa invete si alti oameni de acest joc si o sa fie placut surprinsi de el ^_^.

Download

Jurnal

  1. 05.05.2024 : A creat pagina de wiki intitulata Wordle
  2. 05.05.2024 : Am comandat piesele
  3. 15.05.2024 : Am incercat sa leg display-ul si tastatura(aici aveam tastatura usb si incercam sa o leg cu un cablu de usb mama taiat)
  4. 15.05.2024 : Realizat ca nu ajunge curent la tastatura, comandat tastatura ps/2
  5. 22.05.2024 : Implementat pentru display un level shifter ca sa poata mearga display-ul si intr-un final a mers si tastatura
  6. 22.05.2024-ongoing : Implementat software descris mai sus.
  7. 27.05.2024 : Prezentare proiect PM Fair.

Bibliografie/Resurse

pm/prj2024/tdicu/alina_diana.pintoiu.txt · Last modified: 2024/05/26 18:48 by alina_diana.pintoiu
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