import { useState } from 'react' import { Page } from '../../components/page' import { Title } from '../../components/title' // From https://github.com/lynn/hello-wordl // `dictionary` has all accepted words; `targets` are common-ish words import * as dictionary from './dictionary.json' import * as targets from './targets.json' export default function Wordle() { const WORD_LENGTH = 5 // Find all words of length WORD_LENGTH // const dict = dictionary.filter((word) => word.length === WORD_LENGTH) const words = targets.filter((word) => word.length === WORD_LENGTH) const [input, setInput] = useState('') const pastGuesses: PastGuess[] = parsePastGuesses(input) const placeholder = 'e.g.\nstage BBYBB\nlucre YYGYY' const valids = validHardMode(words, pastGuesses) return (
<p className="text-black"> Given a list of past Wordle guesses, show all possible valid next guesses for Hard Mode </p> Actually for{' '} <a href="https://hellowordl.net/">https://hellowordl.net/</a> <p>Past guesses:</p> <textarea className="h-32 w-full p-2" value={input} onChange={(e) => setInput(e.target.value)} placeholder={placeholder} /> <br /> <br /> <p className="text-black"> {Array(10) .fill(null) .map((_) => chooseRandom(valids)) .join(', ')} </p> <p>Total valid words: {valids.length}</p> <p>All valid words:</p> <pre>{JSON.stringify(valids, null, 2)}</pre> </div> </Page> ) } function chooseRandom(list: any[]) { return list[Math.floor(Math.random() * list.length)] } type PastGuess = { guess: string // Result is a string like 'GYBBG' // G = Green (match), Y = Yellow (somewhere), B = Black (nowhere) result: string } function validHardMode(wordlist: string[], pastGuesses: PastGuess[]) { let candidates = wordlist.slice() const blacks = new Set() for (const { guess, result } of pastGuesses) { candidates = candidates.filter((word) => { // e.g. guess = 'helot', result = 'GGGYB', word = 'hello => true // e.g. guess = 'helot', result = 'GGGYB', word = 'helot => false const guessYellows = [] const wordNonGreens: string[] = [] for (let i = 0; i < result.length; i++) { switch (result[i]) { case 'G': if (word[i] !== guess[i]) return false break case 'Y': if (word[i] === guess[i]) return false guessYellows.push(guess[i]) wordNonGreens.push(word[i]) break case 'B': if (word[i] === guess[i]) return false wordNonGreens.push(word[i]) blacks.add(guess[i]) break } if (blacks.has(word[i])) return false } // Return true if every letter in guessYellows is in wordNonGreens return guessYellows.every((letter) => wordNonGreens.includes(letter)) }) } return candidates } function parsePastGuesses(pastGuesses: string) { return pastGuesses .split('\n') .map((pg) => { const [guess, result] = pg.split(' ') return { guess, result } }) .filter(({ guess, result }) => guess && result) } // Bad target words: witan, sedum // TODO: Maybe just use canonical Wordle dictionaries // DEBUG: { guess: 'lucre', result: 'YYGYY' } // Should produce: ulcer