export const GUESS_RESULT = { MISS: 'm', WIN: 'w', FOUL: 'f' }; export const MARKERS = { MISS: 'm', RIGHT_POS: 'g', RIGHT_CHAR: 'y', ATTEMPTED: 'a', }; class ProgressionState { getProgression() { let prog = localStorage.getItem('progression'); if (prog) { return JSON.parse(prog); } this.clearProgression(""); return prog; } clearProgression(shuffleId) { let prog = { shuffleId: shuffleId, wordLength: 4, wordIndex: {"4": 0, "5": 0, "6": 0, "7": 0}, currentGuesses: [] }; localStorage.setItem('progression', JSON.stringify(prog)); return prog; } saveProgression(prog) { localStorage.setItem('progression', JSON.stringify(prog)); } } export class GameController { constructor(wordSource) { this._wordSource = wordSource; this._progressionState = new ProgressionState(); } async start() { let prog = this._progressionState.getProgression(); if (await this._wordSource.needToResetProgression(prog)) { console.log("Clearing patten shuffle id") prog = this._progressionState.clearProgression(await this._wordSource.getPattenShuffleID()); } this._currentWord = await this._wordSource.getCurrentWord(prog); this._guesses = 6; console.log("The current word: " + this._currentWord); } wordLength() { this._checkHasStarted(); return this._currentWord.length; } guesses() { this._checkHasStarted(); return this._guesses; } currentState() { let prog = this._progressionState.getProgression(); if (!prog || !prog.currentGuesses) { return []; } return { wasWin: prog.wasWin, currentGuesses: prog.currentGuesses }; } currentWord() { this._checkHasStarted(); return this._currentWord; } async nextWord() { // Increment the progress let prog = this._progressionState.getProgression(); prog.wordIndex[prog.wordLength + ""] += 1; //prog.wordLength = (((Math.random() * 23) | 0) / 10 | 0) + 4; prog.wordLength = ((Math.random() * 4) | 0) + 4; prog.currentGuesses = []; prog.wasWin = false; this._progressionState.saveProgression(prog); this._currentWord = await this._wordSource.getCurrentWord(prog); //this._guesses = Math.max(this._currentWord.length, 5) + 1; this._guesses = 6; return true; } showHint() { let hints = new Array(this._currentWord.length); let priorGuesses = this._progressionState.getProgression().currentGuesses; hints[0] = this._currentWord[0]; for (let i = 1; i < this._currentWord.length; i++) { for (let guess of priorGuesses) { if (guess[i] === this._currentWord[i]) { hints[i] = this._currentWord[i]; } } } return hints; } submitGuess(guess) { guess = guess.toLowerCase(); let results = this.checkGuess(guess); // Add this guess to the progression state if (results.guessResult !== GUESS_RESULT.FOUL) { let prog = this._progressionState.getProgression(); prog.currentGuesses.push(guess); prog.wasWin = results.guessResult === GUESS_RESULT.WIN; this._progressionState.saveProgression(prog); } return results; } checkGuess(guess) { this._checkHasStarted(); guess = guess.toLowerCase(); if (guess.length != this._currentWord.length) { throw Error(`Expected length to be ${this._currentWord.length} but was ${guess.length}`); } // Check correct placements let guessResult; let markers = new Array(guess.length); let misses = {}; let hits = {}; for (let i = 0; i < guess.length; i++) { if (guess[i] == this._currentWord[i]) { markers[i] = MARKERS.RIGHT_POS; hits[guess[i]] = MARKERS.RIGHT_POS; } else { if (this._currentWord[i] in misses) { misses[this._currentWord[i]] += 1; } else { misses[this._currentWord[i]] = 1; } } } // Check words that are wrong placement but are in the word // Distribute based on the words position for (let i = 0; i < guess.length; i++) { if (markers[i]) { continue; } if (misses[guess[i]] && misses[guess[i]] > 0) { misses[guess[i]] -= 1; markers[i] = MARKERS.RIGHT_CHAR; if (!hits[guess[i]]) { hits[guess[i]] = MARKERS.RIGHT_CHAR; } } else { if (!hits[guess[i]]) { hits[guess[i]] = MARKERS.MISS; } markers[i] = MARKERS.MISS; } } let isRight = markers.filter((x) => x == MARKERS.RIGHT_POS).length == this._currentWord.length; if (isRight) { guessResult = GUESS_RESULT.WIN; } else { guessResult = GUESS_RESULT.MISS; } return { guessResult: guessResult, hits: hits, markers: markers }; } _checkHasStarted() { if (!this._currentWord) { throw new Error("call start() first"); } } }