import { Controller } from "https://unpkg.com/@hotwired/stimulus@v3.2.2/dist/stimulus.js" import { GUESS_RESULT, MARKERS, GameController } from "../models/gamecontroller.js"; import { WordSource } from "../models/words.js"; export default class extends Controller { static targets = ["row", "playfield", "topMessage", "nextPuzzleButtons"]; static outlets = ["overlay"]; async connect() { this._wordSource = new WordSource(); this._gameController = new GameController(this._wordSource); await this._gameController.start(); this._buildPlayfield(); } tappedKey(key) { console.log(`Key ${key} was tapped via outliet`); this._addLetter(key); } _addLetter(letter) { if (this._activeRowIndex < 0) { return; } else if (this._activeLetter >= this._gameController.wordLength()) { return; } let rowElem = this.rowTargets[this._activeRowIndex]; let colElem = rowElem.querySelectorAll("span")[this._activeLetter]; colElem.innerText = letter.toUpperCase(); colElem.classList.remove("hint"); this._activeLetter += 1; } enterGuess() { if (this._activeLetter >= this._gameController.wordLength()) { let rowElem = this.rowTargets[this._activeRowIndex]; this._verifyGuess(rowElem); } } loadDef(ev) { ev.preventDefault() let word = this._gameController.currentWord(); window.open(`https://www.ecosia.org/search?q=define+${word}`, "_blank"); } tappedBackspace() { if (this._activeLetter == 0) { return; } this._activeLetter -= 1; let rowElem = this.rowTargets[this._activeRowIndex]; let colElem = rowElem.querySelectorAll("span")[this._activeLetter]; let colHint = colElem.dataset["hint"]; if (colHint) { colElem.classList.add("hint"); colElem.innerText = colHint; } else { colElem.innerText = ""; } } _verifyGuess(rowElem) { let guessedWord = Array.from(rowElem.querySelectorAll("span")).map((x) => x.innerText).join(""); console.log("The guessed word is: " + guessedWord); let results = this._gameController.submitGuess(guessedWord); switch (results.guessResult) { case GUESS_RESULT.FOUL: this.overlayOutlet.showMessage("Not in dictionary"); let newRow = this._buildPlayfieldRow(this._gameController.wordLength()); this._showHints(newRow); rowElem.replaceWith(newRow); this._activeLetter = 0; window.dispatchEvent(new CustomEvent("guessResults", { detail: results })); break; case GUESS_RESULT.MISS: this._colorizeRow(rowElem, results); this._activeRowIndex += 1; if (this._activeRowIndex >= this._gameController.guesses()) { this._revealAnswer(); } else { this._activeLetter = 0; this._showHints(this.rowTargets[this._activeRowIndex], results.markers); } break; case GUESS_RESULT.WIN: this._colorizeRow(rowElem, results); this._showWin(); break; } } async loadNextPuzzle(ev) { ev.preventDefault(); if (await this._gameController.nextWord()) { this._buildPlayfield(); } else { this.overlayOutlet.showMessage("No more words available."); } } _showWin() { this.topMessageTarget.innerText = "Hooray! You did it."; this.nextPuzzleButtonsTarget.classList.remove("hide"); } _revealAnswer() { this.topMessageTarget.innerText = this._gameController.currentWord().toUpperCase(); this.nextPuzzleButtonsTarget.classList.remove("hide"); } _buildPlayfield() { let rows = this._gameController.guesses(); let wordLength = this._gameController.wordLength(); let {currentGuesses, wasWin} = this._gameController.currentState(); this._activeRowIndex = currentGuesses.length; this._activeLetter = 0; window.dispatchEvent(new CustomEvent("resetKeyColors")); let newRows = []; for (let r = 0; r < rows; r++) { let currentGuess = null; let currentGuessResults = null; if (r < currentGuesses.length) { currentGuess = currentGuesses[r]; currentGuessResults = this._gameController.checkGuess(currentGuess); } newRows.push(this._buildPlayfieldRow(wordLength, currentGuess, currentGuessResults)); if (currentGuessResults) { window.dispatchEvent(new CustomEvent("guessResults", { detail: currentGuessResults })); } } if (wasWin) { this._showWin(); } else if (currentGuesses.length >= rows) { // User has already used up all their guesses so just show the results; this._revealAnswer(); } else { this._showHints(newRows[currentGuesses.length]); this.topMessageTarget.innerHTML = " " this.nextPuzzleButtonsTarget.classList.add("hide"); } this.playfieldTarget.replaceChildren.apply(this.playfieldTarget, newRows); } _buildPlayfieldRow(wordLength, currentGuess, currentGuessResults) { let divElem = document.createElement("div"); divElem.classList.add("row"); divElem.setAttribute("data-playfield-target", "row"); for (let c = 0; c < wordLength; c++) { let letterSpan = document.createElement("span"); if (currentGuess) { letterSpan.innerText = currentGuess[c].toUpperCase(); } divElem.appendChild(letterSpan); } if (currentGuess) { this._colorizeRow(divElem, currentGuessResults); } return divElem; } _colorizeRow(row, results) { let markers = results.markers; for (let i = 0; i < this._gameController.wordLength(); i++) { switch (markers[i]) { case MARKERS.RIGHT_POS: row.children[i].classList.add("right-pos"); break; case MARKERS.RIGHT_CHAR: row.children[i].classList.add("right-char"); break; case MARKERS.MISS: row.children[i].classList.add("miss"); break; } } window.dispatchEvent(new CustomEvent("guessResults", { detail: results })); } _showHints(row) { let hint = this._gameController.showHint(); for (let i = 0; i < this._gameController.wordLength(); i++) { if (hint[i]) { let colElem = row.children[i]; colElem.classList.add("hint"); colElem.innerText = hint[i].toUpperCase(); colElem.dataset["hint"] = hint[i].toUpperCase(); } } } }