From 539534ad904737697909c3fd4e96b6f04c82c141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20R=C3=B6ger?= Date: Fri, 21 Aug 2026 17:57:45 +0200 Subject: [PATCH] feat(web): optional wordle-answers --- src/lib/wasm.rs | 13 +++++++-- web/src/App.svelte | 41 +++++++++++++++++++++++--- web/src/solver/solver.ts | 62 ++++++++++++++++++++++++++++++++++++---- web/src/solver/types.ts | 15 ++++++++++ web/src/solver/worker.ts | 24 ++++++++++++---- 5 files changed, 137 insertions(+), 18 deletions(-) diff --git a/src/lib/wasm.rs b/src/lib/wasm.rs index 19c5823..f0c26a5 100644 --- a/src/lib/wasm.rs +++ b/src/lib/wasm.rs @@ -48,12 +48,19 @@ impl WordStats { #[allow(dead_code)] #[wasm_bindgen] impl Solver { - pub fn new() -> Result { + pub fn new(use_wordle_answers: bool) -> Result { let valid_words = WordList::try_from(io::BufReader::new(io::Cursor::new(DEFAULT_VALID_WORDS)))?; - let answers = WordList::try_from(io::BufReader::new(io::Cursor::new(DEFAULT_ANSWERS)))?; - Ok(Solver(solver::Solver::new(valid_words, answers))) + if use_wordle_answers { + let answers = WordList::try_from(io::BufReader::new(io::Cursor::new(DEFAULT_ANSWERS)))?; + Ok(Solver(solver::Solver::new(valid_words, answers))) + } else { + Ok(Solver(solver::Solver::new( + valid_words.clone(), + valid_words, + ))) + } } pub fn guess(&mut self, word: &str, colors: Vec) -> Result<(), String> { diff --git a/web/src/App.svelte b/web/src/App.svelte index 3ef2f63..8d42466 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -4,6 +4,7 @@ import { solver_evaluate_words, solver_guess, + solver_reset, solver_solution_space, } from "./solver/solver.ts"; import type { @@ -29,18 +30,35 @@ let infos_gained: (Promise | null)[] = $state([null]); + let use_default_wordle_answers: boolean = $state(true); + let solution_space: Promise = $state( solver_solution_space(), ); - self.setTimeout(() => { - solution_space = solver_solution_space(); - }, 300); let best_words: Promise | null = $state(null); let best_words_progress: EvaluateWordsProgress | null = $state(null); let cursor = $state(0); + function reset() { + guesses = [ + { + letters: ["", "", "", "", ""], + colors: [ + Color.GREY, + Color.GREY, + Color.GREY, + Color.GREY, + Color.GREY, + ], + }, + ]; + infos_gained = [null]; + best_words = null; + solution_space = solver_solution_space(); + } + function handleKey(event: KeyboardEvent) { if (event.key === "Enter" && event.shiftKey) { best_words = solver_evaluate_words(5, (p) => { @@ -85,7 +103,22 @@

Wordle Solver

- {#await solution_space then s} + Use Wordle-Answers: + { + solver_reset(use_default_wordle_answers).then(() => { + reset(); + }); + }} + /> +

+ +

+ {#await solution_space} + loading + {:then s} Solution-space: {s.size}, Uncertainty: {s.uncertainty.toFixed( 2, )}bits diff --git a/web/src/solver/solver.ts b/web/src/solver/solver.ts index 1fbcb17..6deb46d 100644 --- a/web/src/solver/solver.ts +++ b/web/src/solver/solver.ts @@ -3,6 +3,7 @@ import SolverWorker from "./worker?worker"; import type { GuessResult, SolutionSpaceResult, EvaluateWordsResult, SolverRequest, SolverResponse, EvaluateWordsProgress } from "./types"; let solver_worker = new SolverWorker(); +await init_solver(); let msg_id = 0; @@ -13,6 +14,25 @@ const pending = new Map void>(); +function init_solver(): Promise { + return new Promise((resolve) => { + solver_worker.onmessage = (event: any) => { + if (event.data.type === "ready") { + solver_worker.onmessage = workerHandleMsg; + resolve(); + } else { + workerHandleMsg(event); + } + }; + }); +} + +function create_solver_worker(): Promise { + solver_worker = new SolverWorker(); + + return init_solver(); +} + export function solver_guess(word: string[], colors: Color[]): Promise { const id = msg_id++; @@ -47,11 +67,11 @@ export function solver_solution_space(): Promise { export function solver_evaluate_words(n: number, progress: ((p: EvaluateWordsProgress) => void) | null): Promise { const id = msg_id++; - + if (progress) { progresses.set(id, progress); } - + return new Promise((resolve, reject) => { pending.set(id, { resolve, reject }); @@ -65,13 +85,40 @@ export function solver_evaluate_words(n: number, progress: ((p: EvaluateWordsPro }); } +export async function solver_reset(wordle_answers: boolean): Promise { + solver_worker.terminate(); -solver_worker.onmessage = (event: MessageEvent) => { + await create_solver_worker(); + console.log("Created: ans=" + wordle_answers); + + pending.forEach((v, _) => { + v.reject("Solver was reset"); + }); + pending.clear(); + progresses.clear(); + + const id = msg_id++; + + return new Promise((resolve, reject) => { + pending.set(id, { resolve, reject }); + + const r: SolverRequest = { + type: "reload_wordlist", + id: id, + input: { use_wordle_ansers: wordle_answers }, + }; + + solver_worker.postMessage(JSON.parse(JSON.stringify(r))); + }); +} + + +function workerHandleMsg(event: MessageEvent) { let res = event.data; - + if (res.type == "evaluate_words_progress") { let progress = progresses.get(res.id); - + if (progress) { progress(res.result); } @@ -79,6 +126,8 @@ solver_worker.onmessage = (event: MessageEvent) => { return; } + console.log("Rcv msg: ", res.type + " " + res.id); + const pendingRequest = pending.get(res.id); if (!pendingRequest) { @@ -95,4 +144,5 @@ solver_worker.onmessage = (event: MessageEvent) => { } else { pendingRequest.reject("No result"); } -}; +} + diff --git a/web/src/solver/types.ts b/web/src/solver/types.ts index bb3b374..3147c72 100644 --- a/web/src/solver/types.ts +++ b/web/src/solver/types.ts @@ -15,6 +15,11 @@ export type SolverRequest = type: "solution_space", id: number, input: null, + } + | { + type: "reload_wordlist", + id: number, + input: ReloadWordlist }; export type SolverResponse = @@ -33,6 +38,7 @@ export type SolverResponse = | { type: "evaluate_words_progress", id: number, + error: null, result: EvaluateWordsProgress } | { @@ -40,6 +46,12 @@ export type SolverResponse = id: number, error: string | null, result: SolutionSpaceResult | null + } + | { + type: "reload_wordlist", + id: number, + error: string | null + result: boolean | null, }; export type Guess = { @@ -56,6 +68,9 @@ export type EvaluateWordsProgress = { i: number, n: number }; +export type ReloadWordlist = { + use_wordle_ansers: boolean +}; export type WordStats = { word: string, solution_probability: number, diff --git a/web/src/solver/worker.ts b/web/src/solver/worker.ts index aaa3398..83f123a 100644 --- a/web/src/solver/worker.ts +++ b/web/src/solver/worker.ts @@ -1,7 +1,11 @@ import { Solver, } from "wordle-solver"; import type { SolverRequest, SolverResponse, WordStats } from "./types"; -let solver = Solver.new(); +let solver = Solver.new(true); + +self.postMessage({ + type: "ready", +}); self.onmessage = (event: MessageEvent) => { const request = event.data; @@ -40,6 +44,7 @@ self.onmessage = (event: MessageEvent) => { let p: SolverResponse = { type: "evaluate_words_progress", id: request.id, + error: null, result: { i, n } }; self.postMessage(JSON.parse(JSON.stringify(p))); @@ -77,10 +82,19 @@ self.onmessage = (event: MessageEvent) => { type: "solution_space", id: request.id, error: null, - result: { - size: solver.solution_space(), - uncertainty: solver.solution_space_uncertainty() - } + result: { size: solver.solution_space(), uncertainty: solver.solution_space_uncertainty() } + }; + self.postMessage(JSON.parse(JSON.stringify(response))); + break; + }; + case "reload_wordlist": { + solver.free(); + solver = Solver.new(request.input.use_wordle_ansers); + const response: SolverResponse = { + type: "reload_wordlist", + id: request.id, + error: null, + result: true }; self.postMessage(JSON.parse(JSON.stringify(response))); break;