This is an old revision of the document!


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.

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

Care au fost rezultatele obţinute în urma realizării proiectului vostru.

Concluzii

Download

wordle.zip 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.

Jurnal

Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.

Bibliografie/Resurse

Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe Resurse Software şi Resurse Hardware.

Export to PDF

pm/prj2024/tdicu/alina_diana.pintoiu.1716718742.txt.gz · Last modified: 2024/05/26 13:19 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