fast anagram solver
exact, subset, and multi‑word phrases. completely private, all computation in browser.
examples: dormitory astronomer listen santa
advanced options
worker pushes progress; typed arrays are transferred, not copied.
wildcards: include
? in the letters box; they cover any deficit.performance: we index once, then queries are fast. phrases stop at a solution/time cap to stay snappy.
caching: dictionary is permanently cached in IndexedDB. first load downloads once; every subsequent visit is instant.
loading dictionary…
results: –
how it works (short)
three related problems, three slightly different hammers:
- exact anagrams (single word) — compute a word’s signature (letters sorted). all words with the same signature are mutual anagrams. O(1) map lookup.
- subset anagrams (single word) — 26‑bit presence mask rejects non‑candidates, then a 26‑byte counts check (with wildcards) verifies multiplicities.
- phrases (many words) — prefilter with mask+counts, then a bucketed dfs that always pivots on the rarest remaining letter. we track used candidates and normalize each phrase so permutations collapse; optional memoization still prunes repeated dead states.
we keep data in typed arrays for cache‑friendliness; the heavy indexing runs in a web worker.
svg diagram of the pipeline
deep dive — why these choices
think of the dictionary as a field of tall grass. we don’t mow it; we lay narrow paths:
- signature map (exact): sorting is cheap; hashing is constant; end of story.
- mask + counts (subset): a 26‑bit and a 26‑byte stroll. most words die on the mask gate; counts is a tiny formality.
- phrase dfs: it’s exponential in theory, but in practice the rarest letter pivot (most‑constraining variable) brutalizes branching. buckets mean we only iterate words that contain the pivot letter, not the entire candidate set. we track already‑used candidates and normalize finished phrases so permutations collapse. flip memoization on and repeated dead‑ends vanish behind a door we refuse to reopen.
- web worker: the big arrays (masks/counts/scores) are built off‑thread and transferred (not copied) to the ui. no jank, no drama.