diff --git a/public/mathematical-wordle-words-list.json b/public/mathematical-wordle-words-list.json new file mode 100644 index 0000000..fbd13a2 --- /dev/null +++ b/public/mathematical-wordle-words-list.json @@ -0,0 +1 @@ +["MINUS","ZEROS","ROUND","THIRD","PROOF","EVENT","MATHS","CUBIC","MONAD","GAUSS","AXIOM","PRISM","CHORD","ANGLE","LITRE","MILES","VALUE","TABLE","HALVE","EXACT","LOCUS","QUART","ARRAY","SOLID","KITES","TRIAL","EMPTY","FIFTH","NINTH","DEPTH","BOOLE","FACES","TENTH","SLOPE","SIXTH","DELTA","SIGMA","LINES","EULER","FIFTY","SCALE","RULER","INDEX","OUNCE","FIRST","SPACE","MONIC","POINT","RIGHT","DIGIT","VALID","TIMES","KLEIN","TWICE","SIXES","METRE","STONE","BAYES","SEVEN","PLANE","CLOCK","THREE","CHAOS","ACUTE","UNITS","HARDY","COUNT","FORTY","TORUS","WIDTH","LOGIC","WILES","POWER","EIGHT","RANGE","PRIME","MODAL","TREND","THETA","CURVE","SIXTY","ERROR","TALLY","PLATO","UNION","KILOS","GRAPH","RATIO","CUBES","DOZEN","EQUAL","ALPHA","NODES","GROUP","ERDOS","KAPPA","LIMIT","ADDED","HERTZ","LATEX","CONIC","RINGS","BOUND","ROOTS","BOREL","ALEPH","SURDS","HELIX","APPEL","EDGES","GAMMA","POLAR","GODEL","FIELD","TUPLE","POLYA","BASIS","UPPER","LEMMA","PROVE","ORDER","SIDES","HASSE","SMALL","BRACE","KNUTH","AREAS","IDEAL","SPACE","DENSE","MODEL","LOWER","OVALS","NOISE","SOLVE","BAIRE","CHAIN","JULIA","FOCUS","KNOTS","DIRAC","HOLES","NORMS","REALS"] diff --git a/src/App.vue b/src/App.vue index 4022284..0386496 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,7 +7,17 @@ export default { data() { return { + // Constants + LETTER_ANIMATION_DURATION: 0.3, + SHAKE_ANIMATION_DURATION: 0.3, + + // Variables + words: [], + + listen: true, + gridState: null, + rowsAnimations: null, keyboardMask: null, currentAttempt: 0, @@ -23,8 +33,7 @@ } }, - created() { - this.setupGame(); + async created() { window.addEventListener('keyup', (e) => { if (e.key === 'Backspace') { this.keyPress('Delete'); @@ -34,6 +43,11 @@ this.keyPress(e.key.toUpperCase()) } }); + + let req = await fetch('./mathematical-wordle-words-list.json'); + this.words = await req.json(); + + this.setupGame(); }, components: { GuessGrid, @@ -42,6 +56,33 @@ PopUp, }, methods: { + generatePair() { + let words = []; + + let validPair = false; + while (!validPair) { + let firstWord = this.words[Math.floor(Math.random() * this.words.length)]; + let possibleSecondWords = [] + for(let i = 0; i < this.words.length; i++) { + let validSecondWord = true; + for (let l = 0; l < firstWord.length; l++) { + if (this.words[i].includes(firstWord[l])) { + validSecondWord = false; + } + } + if (validSecondWord) { + possibleSecondWords.push(this.words[i]); + } + } + + if (possibleSecondWords.length > 0) { + validPair = true; + words = [firstWord, possibleSecondWords[Math.floor(Math.random() * possibleSecondWords.length)]]; + } + } + + return words; + }, setupGame() { this.gridState = Array.from({length: 6}, () => { return Array.from({length: 5}, () => { @@ -49,44 +90,26 @@ letter: '', state: 'unset' }; - }) + }); }); + this.rowsAnimations = new Array(6).fill(false); - this.keyboardMask = { - 'Q': 'unused', - 'W': 'unused', - 'E': 'unused', - 'R': 'unused', - 'T': 'unused', - 'Y': 'unused', - 'U': 'unused', - 'I': 'unused', - 'O': 'unused', - 'P': 'unused', - 'A': 'unused', - 'S': 'unused', - 'D': 'unused', - 'F': 'unused', - 'G': 'unused', - 'H': 'unused', - 'J': 'unused', - 'K': 'unused', - 'L': 'unused', - 'Z': 'unused', - 'X': 'unused', - 'C': 'unused', - 'V': 'unused', - 'B': 'unused', - 'N': 'unused', - 'M': 'unused', - 'Enter': 'unused', - 'Delete': 'unused', - }; + this.keyboardMask = Object.fromEntries( + Array.from({length: 26}, (v, i) => [ + String.fromCharCode(i + 65), 'unused' + ]) + ); + this.keyboardMask['Enter'] = 'unused'; + this.keyboardMask['Delete'] = 'unused'; + console.log(this.keyboardMask); this.currentAttempt = 0; this.currentIndex = 0; - this.secretWords = [ 'SNARK', 'ITCHY' ]; + this.secretWords = this.generatePair(); + console.log(this.secretWords); + console.log(this.secretWords[0]); + console.log(this.secretWords[1]); this.gameOver = false; this.won = false; @@ -125,6 +148,9 @@ this.overlayVisible = true; }, keyPress(event) { + if (!this.listen) { + return; + } if (event === "Delete") { if(this.currentIndex > 0) { this.currentIndex -= 1; @@ -133,19 +159,49 @@ } } else if (event == "Enter") { if(this.currentIndex === 5) { + + // Validate Word + let currentWord = ""; + for(let i = 0; i < 5; i++) { + currentWord += this.gridState[this.currentAttempt][i].letter; + } + if(!this.words.includes(currentWord)) { + // Invalid attempt, signal error + this.listen = false; + this.rowsAnimations[this.currentAttempt] = true; + + setTimeout(() => { + this.listen = true; + this.rowsAnimations[this.currentAttempt] = false; + }, this.SHAKE_ANIMATION_DURATION * 1000); + + return; + } + + // Calculate result + let wordsFlags = [ this.secretWords[0].split(''), this.secretWords[1].split('') ]; let matches = [ [-1,false], [-1,false], [-1,false], [-1,false], [-1,false] ]; - for(let i = 0; i < 5; i++) - { + + for(let i = 0; i < 5; i++) { let letter = this.gridState[this.currentAttempt][i].letter; - for(let j = 0; j < 2; j++) - { - if (this.secretWords[j].includes(letter)) { - let matchType = this.secretWords[j][i] === letter; - matches[i] = [j, matchType]; + for(let j = 0; j < 2; j++) { + if (wordsFlags[j][i] === letter) { + wordsFlags[j][i] = null; + matches[i] = [j, true]; + } + } + } + for(let i = 0; i < 5; i++) { + let letter = this.gridState[this.currentAttempt][i].letter; + for(let j = 0; j < 2; j++) { + for(let k = 0; k < 5; k++) { + if(wordsFlags[j][k] === letter) { + wordsFlags[j][k] = null; + matches[i] = [j, false]; + } } } } - let oneWordMatch = true; for(let i = 0; i < 5; i++) { for(let j = 0; j < 5; j++) { @@ -155,27 +211,49 @@ } } + // Update grid to tease result for(let i = 0; i < 5; i++) { if (matches[i][0] !== -1 && matches[i][1]) { this.gridState[this.currentAttempt][i].state = `correct-${oneWordMatch ? 'full' : 'half'}`; - this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'correct'; } else if (matches[i][0] !== -1 && !matches[i][1]) { this.gridState[this.currentAttempt][i].state = `misplaced-${oneWordMatch ? 'full' : 'half'}`; - this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'misplaced'; } else { this.gridState[this.currentAttempt][i].state = 'wrong'; - this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'wrong'; } } + this.listen = false; + + // Resolve + setTimeout(() => { + for(let i = 0; i < 5; i++) { + if (matches[i][0] !== -1 && matches[i][1]) { + if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused' || + this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'misplaced') { + this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'correct'; + } + } else if (matches[i][0] !== -1 && !matches[i][1]) { + if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused') { + this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'misplaced'; + } + } else { + if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused') { + this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'wrong'; + } + } + } - this.currentAttempt += 1; - this.currentIndex = 0; + this.currentAttempt += 1; + this.currentIndex = 0; - if (this.checkWin(matches, oneWordMatch)) { - this.resolveGame(true); - } else if (this.currentAttempt === 6) { - this.resolveGame(false); - } + + if (this.checkWin(matches, oneWordMatch)) { + this.resolveGame(true); + } else if (this.currentAttempt === 6) { + this.resolveGame(false); + } + + this.listen = true; + }, this.LETTER_ANIMATION_DURATION * 1000 * 5); } } else { if (this.currentIndex < 5) { @@ -190,8 +268,8 @@