$sloprun.dev

Word Guess

demo sandbox: allow-scripts · csp: default-src 'none'

sandboxed and isolated in your browser · never enter a real password in a demo

▶ 7 ran · ✓ 0 worked
i ran it — no login needed:
share: preview embed ↗
post it anywhere:
email the card:

0 reported it broke · the ▶ count is distinct visitors who ran it, counted once each, anonymously

Five letters, six tries, and a counter that tells you exactly how much you still don't know: the page opens mid-round with an opening guess already scored on the board, and beside it sits the honest number — how many of the 815 built-in answers are still consistent with the colours you can see. Watch it collapse (815 → 41 → 6 → 1) and the game stops feeling like luck and starts feeling like search. Try Suggest a guess: it scores every word by how far it would cut the remaining candidates on average, tells you what it expects to be left with, and played straight through it cracks all 815 answers in five guesses or fewer, averaging a shade over three. Word lists, scorer and solver all run offline inside this one file, and the end-of-round grid is just there to look at — no share button, no clipboard, nothing to post.

Embed this demo — put a runnable demo in your blog post

Paste this where you write. It renders a live, runnable demo inline anywhere raw HTML / iframes are allowed — Ghost, WordPress, Notion, Discourse, your own site.

<iframe src="https://sloprun.dev/embed/word-guess" width="100%" height="640" loading="lazy" allow="" style="border:1px solid #E3E2DC;border-radius:10px" title="Word Guess — a runnable demo on sloprun.dev"></iframe>
preview ↗

On Medium and dev.to the plain link becomes a rich preview card that links back here — they don't run third-party iframes, so paste the URL there and the reader clicks through to run it. https://sloprun.dev/p/word-guess

Source

the code you see is the code that just ran raw ↗
Source — the code you see is the code that just ran 1072 lines 59.5 KB index.html
demos/word-guess/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Word Guess — sloprun.dev</title>
<style>
/* ── sloprun design tokens (verbatim from demos/tokens.css) ───────────────── */
:root {
  --bg: #F6F6F3;          /* neutral paper, not cream */
  --surface: #FFFFFF;
  --ink: #1A1D21;
  --muted: #5A6068;
  --line: #E3E2DC;
  --accent: #C05600;      /* phosphor amber, darkened for light bg */
  --accent-soft: #FFF3E6;
  --run: #1A7F37;         /* earned green */
  --run-soft: #E7F4EA;
  --danger: #C93C37;
  --radius: 10px;
  --font-sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #14161A; --surface: #1C1F26; --ink: #E8E6E1; --muted: #9AA0A8;
    --line: #2A2E36; --accent: #FFB454; --accent-soft: #2A2118;
    --run: #3FB950; --run-soft: #16281B; --danger: #F47067;
  }
}
:root[data-theme="dark"] {
  --bg: #14161A; --surface: #1C1F26; --ink: #E8E6E1; --muted: #9AA0A8;
  --line: #2A2E36; --accent: #FFB454; --accent-soft: #2A2118;
  --run: #3FB950; --run-soft: #16281B; --danger: #F47067;
}
body { background: var(--bg); color: var(--ink); font-family: var(--font-sans); }
/* ── end tokens ───────────────────────────────────────────────────────────── */

/* demo-local additions (alpha shadows + tile inks; tokens are opaque hex) */
:root {
  --shadow: 0 1px 2px rgba(26,29,33,.06);
  --lift: 0 8px 24px rgba(26,29,33,.10);
  --ok-fg: #FFFFFF;
  --near-fg: #FFFFFF;
  --off-bg: #6F6D66;
  --off-fg: #FFFFFF;
  --off-key: #6F6D66;
  --empty: #FFFFFF;
  --ring: rgba(192,86,0,.30);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --shadow: 0 1px 2px rgba(0,0,0,.35);
    --lift: 0 8px 24px rgba(0,0,0,.45);
    --ok-fg: #0C1A10;
    --near-fg: #2A1B05;
    --off-bg: #343943;
    --off-fg: #9AA0A8;
    --off-key: #2E323B;
    --empty: #1C1F26;
    --ring: rgba(255,180,84,.35);
  }
}
:root[data-theme="dark"] {
  --shadow: 0 1px 2px rgba(0,0,0,.35);
  --lift: 0 8px 24px rgba(0,0,0,.45);
  --ok-fg: #0C1A10;
  --near-fg: #2A1B05;
  --off-bg: #343943;
  --off-fg: #9AA0A8;
  --off-key: #2E323B;
  --empty: #1C1F26;
  --ring: rgba(255,180,84,.35);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body { min-height: 100%; overflow-x: hidden; }

.wrap {
  max-width: 782px; margin: 0 auto; padding: 22px 16px 26px;
  display: flex; flex-direction: column; gap: 16px;
}

/* ── header ───────────────────────────────────────────────────────────────── */
h1 {
  margin: 0 0 6px; font-family: var(--font-mono);
  font-size: clamp(26px, 6vw, 36px); letter-spacing: -.03em; line-height: 1; font-weight: 700;
}
.lede { margin: 0; max-width: 64ch; color: var(--muted); font-size: 14.5px; line-height: 1.55; }
.lede b { font-weight: 600; }
.lede .g { color: var(--run); font-family: var(--font-mono); font-weight: 600; }
.lede .a { color: var(--accent); font-family: var(--font-mono); font-weight: 600; }

/* ── layout ───────────────────────────────────────────────────────────────── */
.stage {
  display: grid; gap: 16px; align-items: start;
  grid-template-columns: minmax(0, 1fr) 260px;
  grid-template-areas: "play panel";
}
.playcol { grid-area: play; min-width: 0; display: flex; flex-direction: column; gap: 10px; align-items: center; }
.panel { grid-area: panel; display: flex; flex-direction: column; gap: 10px; }
@media (max-width: 760px) {
  .stage { grid-template-columns: minmax(0,1fr); grid-template-areas: "play" "panel"; }
  .panel { width: 100%; max-width: 420px; margin: 0 auto; }
}

/* ── board ────────────────────────────────────────────────────────────────── */
.board {
  display: grid; grid-template-rows: repeat(6, 1fr);
  gap: clamp(4px, 1.2vw, 6px);
  width: 100%; max-width: min(330px, 78vw);
}
@media (max-width: 400px) { .board { max-width: 100%; } }
.row { display: grid; grid-template-columns: repeat(5, 1fr); gap: clamp(4px, 1.2vw, 6px); }
.tile {
  position: relative; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line); border-radius: 8px; background: var(--empty);
  font-family: var(--font-mono); font-weight: 700; letter-spacing: -.02em;
  font-size: clamp(19px, 5.6vw, 27px); text-transform: uppercase; line-height: 1;
  transition: border-color 90ms ease, transform 90ms ease;
  will-change: transform;
}
.tile.filled { border-color: var(--muted); }
.tile.pop { animation: pop 110ms ease-out; }
@keyframes pop { 0% { transform: scale(1); } 45% { transform: scale(1.08); } 100% { transform: scale(1); } }
.tile.flip { animation: flip 380ms ease-in-out; }
@keyframes flip { 0% { transform: rotateX(0deg); } 50% { transform: rotateX(90deg); } 100% { transform: rotateX(0deg); } }
.tile[data-s="2"] { background: var(--run);    border-color: var(--run);    color: var(--ok-fg); }
.tile[data-s="1"] { background: var(--accent); border-color: var(--accent); color: var(--near-fg); }
.tile[data-s="0"] { background: var(--off-bg); border-color: var(--off-bg); color: var(--off-fg); }
.row.bad { animation: shake 380ms ease; }
@keyframes shake {
  10%,90% { transform: translateX(-2px); } 20%,80% { transform: translateX(4px); }
  30%,50%,70% { transform: translateX(-6px); } 40%,60% { transform: translateX(6px); }
}
.tile.hop { animation: hop 460ms ease; }
@keyframes hop {
  0% { transform: translateY(0); } 22% { transform: translateY(-12px); }
  44% { transform: translateY(0); } 60% { transform: translateY(-5px); } 100% { transform: translateY(0); }
}

/* ── toast ────────────────────────────────────────────────────────────────── */
.toast {
  margin: 0; min-height: 20px; font-family: var(--font-mono); font-size: 11.5px;
  letter-spacing: .05em; color: var(--muted); text-align: center; line-height: 1.6;
}
.toast.warn { color: var(--danger); }
.toast.win { color: var(--run); }
.toast b { color: var(--ink); }

/* ── keyboard ─────────────────────────────────────────────────────────────── */
.kb { width: 100%; max-width: min(430px, 100%); display: flex; flex-direction: column; gap: clamp(4px, 1.3vw, 6px); }
.krow { display: flex; gap: clamp(3px, 1.1vw, 6px); justify-content: center; }
.key {
  flex: 1 1 0; min-width: 0; height: clamp(40px, 10.5vw, 50px);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: clamp(11px, 3vw, 14px); font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 7px; box-shadow: var(--shadow);
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease, transform 70ms ease;
  padding: 0;
}
.key.wide { flex: 1.6 1 0; font-size: clamp(9px, 2.3vw, 11px); letter-spacing: .08em; }
.key:hover { border-color: var(--muted); }
.key:active { transform: translateY(1px); }
.key[data-s="2"] { background: var(--run);    border-color: var(--run);    color: var(--ok-fg); }
.key[data-s="1"] { background: var(--accent); border-color: var(--accent); color: var(--near-fg); }
.key[data-s="0"] { background: var(--off-key); border-color: var(--off-key); color: var(--off-fg); }
.spacer { flex: .5 1 0; }

/* ── panel boxes ──────────────────────────────────────────────────────────── */
.box {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 11px 12px 12px; box-shadow: var(--shadow);
}
.box .h {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 8px;
}
.stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.stat { min-width: 0; }
.stat.wide { grid-column: 1 / -1; }
.sk {
  display: block; font-family: var(--font-mono); font-size: 9px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.sv {
  display: block; font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 19px; font-weight: 700; letter-spacing: -.02em; margin-top: 1px; line-height: 1.2;
}
.sv.small { font-size: 13px; font-weight: 600; letter-spacing: .01em; }
.sv.ok { color: var(--run); }
.sv.warn { color: var(--danger); }
.sv.amber { color: var(--accent); }

.trail {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12.5px; line-height: 1.9; color: var(--ink); word-break: break-word;
}
.trail .arw { color: var(--muted); margin: 0 4px; }
.trail .n0 { color: var(--muted); }
.trail .cur { color: var(--accent); font-weight: 700; }
.note { margin: 8px 0 0; font-size: 11.5px; color: var(--muted); line-height: 1.55; }
.note b { color: var(--ink); font-family: var(--font-mono); font-weight: 600; }

/* ── buttons ──────────────────────────────────────────────────────────────── */
.acts { display: flex; gap: 8px; }
.btn {
  flex: 1 1 0; appearance: none; cursor: pointer; font-family: var(--font-sans);
  font-size: 13px; font-weight: 600; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: 8px; padding: 9px 10px; box-shadow: var(--shadow);
  transition: background 120ms ease, border-color 120ms ease, transform 70ms ease;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { border-color: var(--muted); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn.primary { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.hintline {
  margin: 9px 0 0; font-family: var(--font-mono); font-size: 12px; line-height: 1.6;
  color: var(--muted); min-height: 19px;
}
.hintline b { color: var(--accent); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }

/* ── result grid ──────────────────────────────────────────────────────────── */
.grid { display: flex; flex-direction: column; gap: 3px; margin-bottom: 9px; }
.grow { display: flex; gap: 3px; }
.gcell { width: 15px; height: 15px; border-radius: 3px; background: var(--off-bg); }
.gcell[data-s="2"] { background: var(--run); }
.gcell[data-s="1"] { background: var(--accent); }
.gline {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
}
.gline.ok { color: var(--run); }
.gline.miss { color: var(--danger); }
.reveal { font-family: var(--font-mono); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--ink); }

.tally { display: flex; gap: 14px; flex-wrap: wrap; }
.tally div { min-width: 0; }

.hint {
  margin: 0; font-family: var(--font-mono); font-size: 10.5px; color: var(--muted);
  letter-spacing: .04em; text-align: center; line-height: 1.7;
}
.hint .sep { opacity: .45; margin: 0 5px; }

footer {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  letter-spacing: .05em; padding-top: 2px;
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.board:focus-visible { outline-offset: 6px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .001ms !important;
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
  }
}
</style>
</head>
<body>
<div class="wrap">

  <header>
    <h1>Word Guess</h1>
    <p class="lede">Find the five-letter word in six tries. <span class="g">Green</span> means right letter in the right spot; <span class="a">amber</span> means right letter, wrong spot; grey means the letter isn't in the word at all. <b>An opening guess is already on the board</b> — take it from there.</p>
  </header>

  <div class="stage">

    <div class="playcol">
      <div class="board" id="board" tabindex="0" role="group" aria-label="Guess board, six rows of five letters" aria-describedby="kbhelp"></div>
      <p class="toast" id="toast" role="status" aria-live="polite"></p>
      <div class="kb" id="kb" role="group" aria-label="On-screen keyboard"></div>
      <p class="hint" id="kbhelp">
        <span>type letters</span><span class="sep">·</span><span>enter to submit</span><span class="sep">·</span><span>backspace to delete</span>
      </p>
    </div>

    <div class="panel">

      <div class="box">
        <div class="h">This round</div>
        <div class="stats">
          <div class="stat"><span class="sk">Guess</span><span class="sv" id="stGuess">1 / 6</span></div>
          <div class="stat"><span class="sk">Candidates</span><span class="sv" id="stPool">815</span></div>
          <div class="stat"><span class="sk">Ruled out</span><span class="sv" id="stOut">0 letters</span></div>
          <div class="stat"><span class="sk">Status</span><span class="sv small" id="stState">in play</span></div>
        </div>
        <div class="acts" style="margin-top:11px">
          <button class="btn primary" id="newBtn" type="button">New word</button>
          <button class="btn" id="giveBtn" type="button">Give up</button>
        </div>
      </div>

      <div class="box">
        <div class="h">Narrowing</div>
        <div class="trail" id="trail"></div>
        <p class="note">Counted live against the built-in list of <b>815</b> possible answers — every word still consistent with the colours on the board.</p>
      </div>

      <div class="box">
        <div class="h">Solver</div>
        <div class="acts">
          <button class="btn" id="hintBtn" type="button">Suggest a guess</button>
        </div>
        <p class="hintline" id="hintOut">Scores every word by how far it would cut the candidate list, on average.</p>
      </div>

      <div class="box" id="resultBox" hidden>
        <div class="h">Your grid</div>
        <div class="grid" id="grid" aria-hidden="true"></div>
        <div class="gline" id="gline"></div>
        <p class="note" id="gnote"></p>
      </div>

      <div class="box">
        <div class="h">This session</div>
        <div class="stats tallywrap">
          <div class="stat"><span class="sk">Played</span><span class="sv" id="tPlayed">0</span></div>
          <div class="stat"><span class="sk">Solved</span><span class="sv" id="tSolved">0</span></div>
          <div class="stat"><span class="sk">Streak</span><span class="sv" id="tStreak">0</span></div>
          <div class="stat"><span class="sk">Avg guesses</span><span class="sv" id="tAvg">—</span></div>
        </div>
      </div>

    </div>
  </div>

  <footer>demo · sloprun.dev</footer>
</div>

<div class="sr-only" role="status" aria-live="polite" id="live"></div>

<script>
(function () {
  "use strict";

  /* ── word data ──────────────────────────────────────────────────────────── */
  var ANS_PACK =
      "aboutaboveactoracuteadmitadoptadultafteragainagentagreeaheadalarmalbumalertalikealiveallowalonealongalteramong"
    + "angerangleangryankleapartappleapplyarenaarguearisearrayarrowasideassetavoidawakeawardawareawfulbaconbadgebadly"
    + "bakerbasicbasisbatchbeachbeardbeastbeganbeginbeingbellybelowbenchberrybirthblackbladeblameblankblastblendbless"
    + "blindblinkblockbloodbloomblownbluesboardbonusboostboundbrainbrakebrandbravebreadbreakbreedbrickbridebriefbring"
    + "broadbrokebrownbrushbuddybuildbuiltbunchburstbuyercabincablecandycarrycatchcauseceasechainchairchalkcharmchart"
    + "chasecheapcheatcheckcheekcheerchesschestchiefchildchillchirpchoirchokechordchorechosechunkcidercigarclaimclamp"
    + "clashclaspclasscleanclearclerkclickcliffclimbclingcloakclockclonecloseclothcloudclowncoachcoastcocoacolorcomet"
    + "comiccoralcouchcoughcouldcountcourtcovercraftcranecrashcrawlcrazycreamcreekcrispcrosscrowdcrowncruelcrushcrust"
    + "curlycurvecycledailydancedealtdebutdecaydelaydensedepthdiarydirtydoingdonordoubtdoughdozendraftdraindramadrank"
    + "drawndreamdressdrieddriftdrilldrinkdrivedronedrovedrowndustyeagereagleearlyeartheateneightelboweldereliteemail"
    + "emberemptyenjoyenterentryequalequiperroressayeventeveryexactexcelexistextrafairyfaithfalsefancyfatalfaultfavor"
    + "feastfencefeverfieldfifthfiftyfightfinalfirstflairflakeflameflashfleetfleshfloatfloodfloorflownfluidflutefocus"
    + "folksforceforthfortyforumfoundframefraudfreshfriedfrontfrostfruitfullyfunnygaugeghostgiantgivenglareglassglide"
    + "globegloryglovegoinggoosegracegradegraingrandgrantgrapegraphgraspgrassgravegreatgreengreetgriefgrillgrindgroan"
    + "groomgrossgroupgrownguardguessguestguideguildguilthabithairyhandyhappyharshhastehatchhauntheardheartheavyhedge"
    + "hellohencehobbyhoneyhonorhorsehotelhoundhousehoverhumanhumidhumorhurryidealimageindexinputissuejellyjeweljoint"
    + "judgejuicejuicykneelknifeknockknownlabellaborlargelaserlaterlaughlayerleafylearnleaseleashleastleaveledgelegal"
    + "lemonlevellightlimitlinenliverlobbylocallodgelogiclooseloserloverlowerloyalluckylunarlunchlyingmagicmajormaker"
    + "mangomaplemarchmarshmatchmayormeantmedalmediamelonmergemerrymetalmightminorminusmixermodelmoistmoneymonthmoral"
    + "motelmotormountmousemouthmoviemusicnastyneedynervenevernewernewlyninjaninthnoblenoisenoisynorthnotchnovelnurse"
    + "occuroceanofferoftenoliveonionoperaorbitorderorganotherouterownerpaintpanelpanicpaperpartypastapastepatchpatio"
    + "pausepeacepeachpearlpedalpennypetalphasephonephotopianopiecepilotpinchpizzaplaceplainplaneplankplantplateplaza"
    + "plumpplushpointpolarporchpouchpoundpowerprankpresspriceprideprimeprintpriorprizeproofproudproveprunepulsepunch"
    + "pupilpuppyqueenqueryquestqueuequickquietquiltquitequoteradarradioraiserallyranchrangerapidratiorazorreachreact"
    + "readyrealmreferrelaxrelayrenewrepayreplyresetrhinoriderridgerightrivalriverroastrobinrobotrockyrodeoroguerough"
    + "roundrouterulerrumorruralrustysaladsalonsaltysandyscalescarfscaryscenescentscoopscopescorescoutsenseserveseven"
    + "shadeshakeshallshameshapesharesharksharpshavesheepsheersheetshelfshellshiftshineshinyshirtshockshoreshortshout"
    + "shownsightsillysincesixthsixtyskateskillskirtskullslatesleepsleptsliceslideslopesmallsmartsmashsmellsmilesmoke"
    + "snacksnailsnakesolarsolidsolvesorrysoundsouthspacesparesparkspeakspeedspellspendspentspicespicyspikespillspine"
    + "spitesplitspoilspokespoonsportspraystackstaffstagestainstairstakestampstandstarestartstatesteakstealsteamsteel"
    + "steepsteersternstickstiffstillstingstinkstockstolestonestoodstoolstorestormstorystovestrawstripstuckstudystuff"
    + "stuntstylesugarsuitesunnysupersurgeswampswearsweatsweepsweetsweptswiftswingtabletakentastetastyteachtenththank"
    + "theirthemetherethesethickthiefthingthinkthirdthosethreethrowthumbtigertighttimertiredtitletoasttodaytokentooth"
    + "topictotaltouchtoughtoweltowertoxictracetracktradetrailtraintrashtreattrendtrialtricktriedtrucktrulytrunktrust"
    + "truthtuliptutortweettwicetwistultrauncleunderunionuniteuntilupperupseturbanusualvaguevalidvaluevalvevaultvenue"
    + "videovinylvirusvisitvitalvividvocalvoicevoterwagonwaistwastewatchwaterweighweirdwhalewheatwheelwherewhichwhile"
    + "whitewholewhosewiderwidthwittywomanwomenworldworryworseworstworthwouldwoundwritewrongwroteyachtyieldyoungyours"
    + "youth";

  var EXT_PACK =
      "abaciabackabaftabaseabashabateabbeyabbotabeamabetsabhorabideablerabodeabortabuseabutsabuzzabyssachedachesachoo"
    + "acidsacingacmesacornacresacridactedadageadaptaddedadderaddleadeptadieuadmanadmenadminadobeadoreadornadzesaegis"
    + "aeonsaerieaffixafireafootafoulagapeagateagaveagileagingagismaglowagonyaidedaidesailedaimedairedaislealderalgae"
    + "aliasalibialienalignalineallayalleyallotalloyaloesaloftalohaaloofaloudalphaaltaralthoaltosalumsamassamazeamber"
    + "ambleamebaameeramendamigoaminoamirsamissamityamourampleamplyampulamuckamuseangelangstanimeanionaniseankhsannex"
    + "annoyannulanodeanonsantedantesanticantisanvilaortaapaceaphidapingappalapronapsesapteraptlyaquaeaquasarborarced"
    + "ardorareasargonargotariasaromaarosearsonartsyascotashedashenashesaskedaskewaspenaspicassayassesassocasterastir"
    + "atlasatollatomsatoneatriaattaratticaudioauditaugeraughtaugurauntsauraeauralaurasautosavailavastaversavertavian"
    + "avowsawaitawashawingawokeaxialaxingaxiomaxlesaxonsazurebaaedbabelbabesbacksbagelbaggybailsbaitsbaizebakedbakes"
    + "baldsbaledbalesbalksbalkybalmsbalmybalsabanalbandsbandybanesbangsbanjobanksbannsbarbsbardsbaredbarerbaresbarfs"
    + "bargebarksbarnsbaronbasalbasedbaserbasesbasilbasinbasksbassibassobastebatedbatesbathebathsbatikbatonbattybauds"
    + "bawdybawlsbayedbayoubeadsbeadybeaksbeamsbeansbearsbeatsbeausbeauxbebopbecksbeechbeefsbeefybeepsbeersbeetsbefit"
    + "befogbegatbegetbegotbegunbeigebelaybelchbeliebellebellsbeltsbendsbentsberetbergsbermsberthberylbesetbesombesot"
    + "bestsbetasbevelbiblebicepbiddybidedbidesbidetbiersbiffsbightbigotbikedbikerbikesbilgebilksbillsbillybindsbinge"
    + "bingobipedbirchbirdsbisonbitesblabsblandblareblatsblazebleakbleatbleedbleepblentblestblimpblingblipsblissblitz"
    + "bloatblobsblocsblogsblondblotsblowsbluedbluerbluffbluntblurbblursblurtblushboarsboastboatsbobbybodedbodesbogey"
    + "boggybogiebogonbogusboilsboinkbolasbolesbollsboltsbondsbonedbonesboneybongobongsbonnybooedbooksboomsboonsboors"
    + "boothbootsbootyboozeboraxboredborerboresborneboronbosombossybosunbotchboughboutsbowedbowelbowerbowlsboxedboxen"
    + "boxerboxesbozosbracebractbradsbragsbraidbrashbrassbratsbravobrawlbrawnbraysbrewsbriarbribebrierbrigsbrimsbrine"
    + "brinkbrinybriskbroilbroodbrookbroombrothbrowsbruinbruntbruskbrutebucksbudgebuffsbuggybuglebulbsbulgebulgybulks"
    + "bulkybullsbullybumpsbumpybungsbunksbunnybuntsbuoysburgsburkaburlyburnsburntburpsburroburrsbusbybusedbusesbushy"
    + "bustsbutchbuttebuxombylawbytesbywaycabalcabbycacaocachecacticaddycadgecadrecagedcagescageycairncakedcakescalfs"
    + "califcalkscallscalmscalvecalyxcamelcameocampscampycanalcanedcanescannycanoecanoncantocantscapedcapercapescapon"
    + "caratcarbscardscaredcarescaretcargocarolcaromcarpicarpscartscarvecasedcasescaskscastecastscatercattycaulkcaved"
    + "cavescavilcawedcedarcededcedescellicellocellscentschadschafechaffchampchantchaoschapschaptcharscharychasmchats"
    + "cheepchefschewschewychickchidechilechilichimechimpchinachinkchinochinschipschitschivechockchompchopschowschuck"
    + "chugschumpchumschurlchurnchuteciliacinchcircacitedcitescivetciviccivilclackclamsclangclankclansclapsclawscleat"
    + "clefscleftclewsclimeclinkclipscliptclitsclodsclogsclompclopsclotscloutclovecloysclubscluckcluedcluesclumpclung"
    + "clunkclviiclxiiclxivclxixclxvicoalscoatscobracoccicockscockycodascodedcodescodexcoedscoifscoilscoinscokedcokes"
    + "colascoldscoliccoloncoltscomascombocombscomercomescomfycommacompoconchcondoconescongaconicconkscontdcooedcooks"
    + "cookycoolscoonscoopscootscopedcopescopracopsecordscoredcorescorkscormscornscornycostscotescoupecovencovescovet"
    + "coveycowedcowercowlscoyercoylycozencrabscragscrampcramscrankcrapecrasscratecravecrawscrayscrazecreakcredocreed"
    + "creelcreepcrepecreptcresscrestcrewscribscrickcriedcriercriescrimecrimpcroakcrocicrockcronecronycrookcrooncrops"
    + "croupcrowscrudecruetcruftcrumbcryptcubedcubescubiccubitcuffscuingcullscultscumincupidcurbscurdscuredcurercures"
    + "curiecuriocurlscurrycursecurstcurvycushycuspscutercutupcyniccystsczarsdachadaddydadosdaffydairydaisydalesdally"
    + "damesdampsdandydareddaresdarnsdartsdateddatesdatumdaubsdauntdavitdawnsdazeddazesddingdealsdeansdearsdeathdebar"
    + "debitdebtsdebugdecafdecaldecksdecordecoydecrydeedsdeemsdeepsdeersdeferdeicedeifydeigndeismdeitydelisdellsdelta"
    + "delvedemondemosdemurdenimdentsdepotderbydesksdeterdetoxdeucedevildhotidialsdiceddicesdiceydickydictadietsdiffs"
    + "digitdikeddikesdillsdillydimerdimesdimlydineddinerdinesdingodingsdingydinkydiodedirerdirgedirksdiscodiscsdisks"
    + "ditchdittodittydivandivasdiveddiverdivesdivotdivvydizzydjinndocksdodgedodgydodosdoersdoffsdoggydogiedogmadoily"
    + "doleddolesdollsdollydoltsdomeddomesdonutdoomsdoorsdopeddopesdopeydorksdorkydormsdoseddosesdoteddotesdottydouse"
    + "dovesdowdydoweldownsdownydowrydowsedoyendozeddozesdrabsdragsdrakedramsdrapedrawldrawsdraysdreaddregsdrierdries"
    + "drilydripsdroiddrolldrooldroopdropsdrossdrubsdrugsdruiddrumsdrunkdryaddryerdrylyducalducatduchyducksductsduded"
    + "dudesduelsduetsdukesdullsdullydummydumpsdumpyduncedunesdungsdunksdunnodupeddupesduskydustsduvetdwarfdwelldwelt"
    + "dyersdyingdykedearlsearnseasedeaseleaseseatereavesebbedebonyechosedemaedgededgeredgesedictedifyeditseerieegged"
    + "egreteiderejectekingelateelectelegyelfinelideelopeeludeelvesembedemceeemendemeryemirsemitsemojiemoteenactended"
    + "endowendueenemaenemyennuienrolensueenureenvoyepicsepochepoxyeraseerecterodeerrederuptesteretherethicethoseuros"
    + "evadeevensevictevilsevokeewersexaltexamsexecsexertexileexitsexpelexposextolexudeexulteyingfablefacedfacesfacet"
    + "factsfadedfadesfagotfailsfaintfairsfakedfakerfakesfakirfallsfamedfangsfarcefaredfaresfarmsfastsfatedfatesfatty"
    + "faunafaunsfawnsfaxedfaxesfazedfazesfearsfeatsfecalfecesfeedsfeelsfeignfeintfellsfelonfeltsfemurfendsferalferns"
    + "ferryfestsfetalfetchfetedfetidfetusfeudsfewerfezesfiatsfiberfichefiefsfiendfieryfifesfilchfiledfilesfiletfills"
    + "fillyfilmsfilmyfilthfinchfindsfinedfinerfinesfinisfinksfinnyfiordfiredfiresfirmsfirthfishyfistsfitlyfiverfives"
    + "fixedfixerfixesfizzyfjordflackflagsflailflakyflankflapsflareflaskflatsflawsflaysfleasfleckfleesflickfliedflier"
    + "fliesflingflintflipsflirtflitsflockfloesflogsflopsfloraflossflourfloutflowsflubsfluesfluffflukeflukyflumeflung"
    + "flunkflushflybyflyerfoalsfoamsfoamyfocalfogeyfoggyfoilsfoistfoldsfoliofollyfondufontsfoodsfoolsfootsforayfords"
    + "foresforgeforgoforksformsfortefortsfoulsfountfoursfowlsfoxedfoxesfoyerfrackfragsfrailfrancfrankfratsfraysfreak"
    + "freedfreerfreesfretsfriarfrierfriesfrillfriskfrizzfrockfrogsfrondfrothfrownfrozefrumpfryerfudgefuelsfuguefulls"
    + "fumedfumesfundsfungifunksfunkyfurlsfurorfurryfurzefusedfusesfussyfustyfutonfuzedfuzesfuzzygabbygablegaffegaffs"
    + "gagedgagesgailygainsgaitsgalasgalesgallsgamedgamergamesgameygamingammagamutgangsgapedgapesgarbsgasesgaspsgassy"
    + "gatedgatesgaudygauntgauzegauzygavelgawksgawkygayergaylygazedgazergazesgearsgeckogeeksgeekygeesegeldsgelidgenes"
    + "geniegeniigenregentsgenusgeodegermsgetupghoulgibedgibesgiddygiftsgildsgillsgiltsgimmegimpygipsygirdsgirlsgirth"
    + "girtsgismogivesgizmogladegladsglandglazegleamgleanglensglintglitzgloatglobsgloomglossglowsgluedgluesglueygluts"
    + "glyphgnarlgnashgnatsgnawngnawsgnomegoadsgoalsgoatsgodlygofergoldsgolfsgollygonadgonergongsgonksgonnagonzogoods"
    + "goodygooeygoofsgoofygooksgoonsgoredgoresgorgegorpsgorsegottagougegourdgoutygownsgrabsgradsgraftgrailgramsgrate"
    + "gravygraysgrazegrebegreedgrepsgreysgridsgrimegrimygrinsgripegripsgristgritsgroingroksgropegroutgrovegrowlgrows"
    + "grubsgruelgruesgruffgruntguanoguavaguileguisegulaggulchgulfsgullsgullygulpsgumbogummygunnyguppygurusgushygusto"
    + "gustsgustygutsyguyedgybedgybesgypsygyroshackshaftshaikuhailshairshakeshaledhalerhaleshallshalonhaloshaltshalve"
    + "handshangshankshankyhardyharedharemharesharksharmsharpsharpyharryhartshaspshastyhatedhaterhateshaulshavenhaves"
    + "havochawedhawkshayedhazedhazelhazesheadsheadyhealsheapshearsheathheatsheaveheedsheelsheftsheftyheirsheisthelix"
    + "helmshelothelpshennaherbsherdsheronheroshertzhewedhewerhexedhexeshickshidedhideshighshikedhikerhikeshillshilly"
    + "hiltshindshingehingshintshippohippyhiredhireshitchhivedhiveshoagyhoardhoaryhoboshockshoganhoisthokeyhokumholds"
    + "holedholeshollyhomedhomerhomeshomeyhomiehonedhoneshonkshoochhoodshooeyhoofshookshookyhoopshootshopedhopeshorde"
    + "hornshorsyhosedhoseshostshotlyhourshovelhowdyhowlshubbyhuffshuffyhugerhulashulkshullshumpshumushunchhunkshunts"
    + "hurlshurtshuskshuskyhutchhydrahyenahyinghymenhymnshypedhyperhypeshyposiambsiciericilyicingiconsideasidiomidiot"
    + "idledidleridlesidolsidyllidylsiglooikonsillusimamsimbedimbueimpelimplyinaneinaptinboxincedincurindueineptinert"
    + "inferinfixingotinkedinlayinletinnerinsetintelinterintroinureioctliotasirateirkedironsironyislesisletitchyitems"
    + "iviesivoryjabotjacksjadedjadesjailsjambsjapanjapedjapesjauntjawedjazzyjeansjeepsjeersjehadjellojellsjerksjerky"
    + "jestsjettyjibedjibesjiffyjihadjiltsjimmyjinnijinnsjivedjivesjocksjohnsjoinsjoistjokedjokerjokesjollyjoltsjoule"
    + "joustjowlsjoyedjulepjumbojumpsjumpyjuncojunksjunkyjurorkabobkapokkaputkaratkarmakayakkazookebabkebobkeelskeens"
    + "keepsketchkeyedkhakikhanskickskickykiddokiddykillskilnskiloskiltskindakindskingskinkskioskkitedkiteskittykiwis"
    + "klugeklutzknackknavekneadkneedkneesknellkneltknitsknobsknollknotsknowskoalakoanskookskookykopekkronekudoskudzu"
    + "labialacedlaceslacksladedladenladesladlelagerlairslaitylakeslamaslambslamedlamerlameslampslancelandslaneslanky"
    + "lapellapselarchlardslargolarkslarvalasedlaseslassolastslatchlatexlathelathslattelaudslawnslaxerlaxlylazedlazes"
    + "leachleadsleafsleaksleakyleansleapsleaptleechleeksleersleeryleftsleftyleggylegitlemmalemmelemurlendsleperletup"
    + "leveeleverlexerliarslibellicitlicksliegeliensliferliftslikedlikenlikerlikeslilacliltslimbolimbslimedlimeslimns"
    + "limoslimpslinedlinerlineslingolinkslintslionslipidliraslislelispslistsliterlithelivedlivenliveslividllamallano"
    + "loadsloafsloamyloansloathlobedlobeslockslocuslodesloftsloftylogesloginlogonlogosloinslollslonerlongslookslooms"
    + "loonsloonyloopsloopylootslopedlopeslordslorryloseslottolotuslouselousyloutslovedloveslowedlowlyloxesluauslubed"
    + "lubeslucidluckslucrelullslumpslumpylungelungslupinlupuslurchluredluresluridlurkslustsluteslxviilymphlynchlyres"
    + "lyricmacawmacedmacesmachomacromadammadlymagmamaidsmailsmaimsmainsmaizemakesmalesmallsmaltsmamasmambomammamanes"
    + "mangamangemangymaniamanicmanlymannamanormansemaresmariamarksmarrymartsmasksmasonmastsmatedmatesmattemattsmatzo"
    + "maulsmauvemavenmavinmaxedmaxesmaximmaybemazesmealsmealymeansmeatsmeatymeccameetsmeldsmeltsmemesmemosmendsmenus"
    + "meowsmercymeresmeritmesasmessymetedmetermetesmetromewedmewlsmiaowmicramiddymidgemidstmiensmiffsmikedmikesmilch"
    + "milermilesmilfsmilksmilkymillsmimedmimesmimicmincemindsminedminerminesminimminisminksmintsmintymiredmiresmirth"
    + "misdomisermistsmistymitermitesmittsmixedmixesmoansmoatsmochamocksmodalmodemmodesmogulmoiremolarmoldsmoldymoles"
    + "mollsmoltsmommamommymonksmoochmoodsmoodymooedmoonsmoorsmoosemootsmopedmopesmoraymoresmornsmoronmoseymossymotes"
    + "mothsmotifmottomoundmournmousymovedmovermovesmowedmowermucksmuckymucusmuddymuffsmuftimuggymulchmulesmullsmulti"
    + "mummymumpsmunchmungsmuralmurksmurkymusedmusesmushymuskymussymustsmustymutedmutermutesmuttsmynahmynasmyrrhmyths"
    + "nabobnachonacrenadirnaiadnailsnaivenakednamednamesnannynapesnappynarcsnarksnasalnatalnattynavelnavesnearsneath"
    + "necksneedsneighnerdsnerdynervynestsnewelnewsynewtsnexusnicernichenicksnieceniftynightnimbininesninnynippyniter"
    + "nitesnixednixesnoblynodalnoddynodesnoelsnomadnoncenooksnoosenormsnosednosesnoseynotednotesnounsnovaenovasnoway"
    + "nudernudgenukednullsnumbsnuttynylonnymphoakenoakumoaredoasesoasisoatenoathsobeseobeysobitsoboesocherochreoctal"
    + "octetodderoddlyodiumodorsoffaloffedogledoglesogresoiledoinksokaysokrasoldenolderoldieomegaomensomitsonsetoozed"
    + "oozesopalsopensopineopiumoptedopticoralsorateosierotteroughtounceoustsoutdooutedoutgoovalsovaryovensoversovert"
    + "ovoidovuleowingowletownedoxbowoxideozonepacedpacespackspactspaddypadrepaeanpaganpagedpagerpagespailspainspairs"
    + "paledpalerpalespallspalmspalmypalsypandapanespangspansypantspantypapalpapaspapawparchparedparesparkaparksparry"
    + "parsepartspashapastspastypatespathspatsypattypavedpavespawedpawlspawnspayedpayeepayerpeakspealspearspeasepecan"
    + "peckspeekspeelspeepspeerspeevepekoepeltspenalpencependspenespeonspeonypeppyperchperilperksperkypermspeskypesos"
    + "pestspeterpettypeweephagephialphishphloxphonyphylapickspickypierspietypiggypigmypiingpikedpikerpikespilafpilau"
    + "pilawpiledpilespillspinedpinespingspinkspinkypintopintspinuppiouspipedpiperpipespipitpiquepitchpithypitonpivot"
    + "pixelpixieplaidplaitplansplayspleadpleaspleatpliedpliesplodsplonkplopsplotsplowsployspluckplugsplumbplumeplums"
    + "plunkpoachpockspodiapoemspoesypoetspoisepokedpokerpokespokeypoledpolespoliopolkapollspolyppondsponespoochpoohs"
    + "poolspoopspopespoppapoppyporedporesportsposedposerposespositpossepostspottypourspoutspoxesprateprawnprayspreen"
    + "prepspreyspricypriedpriesprigsprimpprismprivyprobeprodsprofspromopromsproneprongpropsproseprosyprowlprowsproxy"
    + "prudepsalmpshawpsychpubicpuckspudgypuffspuffypukedpukespullspulpspulpypumaspumpspunkspuntspupaepupalpupaspuree"
    + "purerpurgepurlspurrspursepushyputtsputtypwnedpygmypylonpyrespyxesquackquadsquaffquailquakequalmquarkquartquash"
    + "quasiquaysquellquidsquillquinequipsquirequirkquitsquoitquotaquothrabbirabidracedracerracesracksradiiradonrafts"
    + "ragasragedragesraidsrailsrainsrainyrajahrajasrakedrakesrampsrangyranksrantsraredrarerraresraspsraspyratedrates"
    + "rattyravedravelravenravesrawerrayonrazedrazesreadsrealsreamsreapsrearmrearsrebelrebusrebutrecaprectarecurredid"
    + "reedsreedyreefsreeksreelsreeverefitregalrehabreignreinsrelicremitrenalrendsrentsreorgrepelreranrerunresinrests"
    + "retchretryreuserevelrevuerheasrheumrhymericedricesricksridesriferriffsriftsrigidrigorriledrilesrillsrimedrimes"
    + "rindsringsrinksrinseripenriperrisenriserrisesrisksriskyritesritzyrivenrivetroachroadsroamsroansroarsrobedrobes"
    + "rocksrogerroilsrolesrollsromanrompsroodsroofsrooksroomsroomyroostrootsropedropesrosesrosinrotorrougerouserouts"
    + "rovedroverrovesrowdyrowedrowelrowerroyalrubesrubleruddyruderruffsrugbyruingruinsruledrulesrumbarummyrumpsrunes"
    + "rungsrunicrunnyruntsrupeerusesrusksrustssablesackssadessadlysafersafessagassagersagessahibsailssaintsaithsales"
    + "sallysalsasaltssalvesambasamessandssanersappysareesarissassysataysatedsatessatinsatyrsaucesaucysaunasavedsaver"
    + "savessavorsavvysawedsaxesscabsscadsscagsscaldscalpscalyscampscamsscansscantscarescarsscatsschwascionscoffscold"
    + "sconescootscornscourscowlscowsscramscrapscrewscripscrodscrogscrubscubascudsscuffscullscumsscurfsealsseamsseamy"
    + "searsseatssectssedansedgeseedsseedyseeksseemsseepsseerssegueseizesellssemissendssennasepalsepiaseptasererserfs"
    + "sergeserumservosetupseversewedsewersexedsexesshackshadsshadyshaftshahsshakyshaleshaltshamsshankshardshawlsheaf"
    + "shearshedssheensheiksherdshiedshiesshillshimsshinsshipsshireshirkshirrshlepshoalshoedshoesshoneshookshoonshoos"
    + "shootshopsshornshotsshoveshowsshowyshredshrewshrubshrugshtikshuckshunsshuntshushshutsshyershylysibylsickssided"
    + "sidessidlesievesiftssighssigmasignssilkssilkysillssilossiltssinewsingesingssinkssinussiredsirensiressirupsisal"
    + "sisessissysitarsitedsitessixessizedsizersizesskeetskeinskewsskidsskiedskierskiesskiffskimpskimsskinsskipsskits"
    + "skulkskunkskyedslabsslackslagsslainslakeslamsslangslantslapsslashslatsslayssledssleeksleetslewsslickslierslily"
    + "slimeslimsslimyslingslinkslipsslitsslobssloesslogssloopslopssloshslothslotsslowssluedsluesslugsslumpslumsslung"
    + "slunkslurpslursslushslyerslylysmearsmeltsmirksmitesmithsmocksmokysmotesmurfsmutssnafusnagssnakysnapssnaresnarf"
    + "snarksnarlsneaksneersnidesniffsnipssnitssnobssnoopsnootsnoresnortsnotssnoutsnowssnowysnubssnucksnugssoakssoaps"
    + "soapysoarssobersockssodassofassoftysoggysoilssoledsolessolossonarsongssonicsonnysoothsootysoppysorersoressorta"
    + "sortssoughsoulssoupssoupysourssousesowedsowerspacyspadespakespamsspankspanssparsspasmspatespatsspawnspaysspeck"
    + "specsspeltspewsspiedspielspiesspikyspiltspinsspinyspirespitssplatsplayspoofspookspoolspoorsporespotsspoutsprat"
    + "spreesprigspudsspumespurnspursspurtsquabsquatsquawsquidstabsstagsstaidstalestalkstallstankstaphstarkstarsstash"
    + "statsstavestaysstdiosteadsteedsteinstemsstentstepsstewsstiesstilestiltstintstirsstoatstoicstokestompstonystoop"
    + "stopsstorkstoutstowsstrapstraystrepstrewstropstrumstrutstubsstudsstumpstungstunkstunsstyesstylisuavesuckssudsy"
    + "suedesuingsuitssulkssulkysullysumacsumpssunupsurersurfssurlysushiswabsswagsswainswamiswankswansswapsswardswarm"
    + "swashswathswatsswaysswellswigsswillswimsswineswipeswirlswishswoonswoopswopssworeswornswungsylphsynchsyncssynod"
    + "syrupsysoptabbytabootabustacittackstackytacostaffytailstainttakertakestalestalkstallytalontamedtamertamestamps"
    + "tangotangstangytansytapedtapertapestapirtardytaredtarestarostarottarpstarrytasertaskstattytaunttaupetawnytaxed"
    + "taxestaxisteakstealsteamstearstearyteaseteatstechsteemsteensteenyteethtelextellstempitempotempstempttendstenet"
    + "tenontenortensetentstepeetepidtermsternsterryterseteststestytextsthawstheestheftthetathighthinethinsthongthorn"
    + "thousthrewthrobthroethrumthudsthugsthumpthunkthymethymitiaratibiatickstidaltidedtidestierstiffstikestildetiled"
    + "tilestillstiltstimedtimestimidtinestingetingstinnytintstipistipsytirestirostitantithetizzytoadstoadytoddytoffy"
    + "togaetogastoilstokedtokestollstombstomestonaltonedtonertonestongstonictonnetoolstootstopaztoquetorchtorsitorso"
    + "tortetortstorustotedtotemtotestourstoutstowedtownstoxintoyedtracttraittramstranstrapstrawltraystreadtreastreed"
    + "treestrekstresstriadtribetricetriestriketrilltrimstriostripetripstritetrolltromptronstropetrothtrotstrouttroys"
    + "trucetruedtruertruestrumptrusstrysttsarstubastubbytubedtubertubestuckstuftstulletumidtummytumortunastunedtuner"
    + "tunestunictunnyturfsturnstuskstutustuxestwaintwangtweaktweedtwerktwerptwigstwilltwinetwinktwinstwirltwitstying"
    + "tykestypedtypestypostyrostzarsudderulcerulnaeulnasumbelumberumiakumpedunbaruncutundidundueunfitunifyunitsunity"
    + "unmanunpinunsayunsetuntieunwedunzipupenduppedurgedurgesurineusageusersusherusingusurpusuryuteriutteruvulavacua"
    + "valesvaletvalorvampsvanesvapedvapesvapidvaporvasesvastsvauntveepsveersveganveilsveinsveldsveldtvenalvendsvenom"
    + "ventsverbsvergeversevervevestsvetchvexedvexesvialsviandvibesvicarvicedvicesviewsvigilvigorvilervillavinesviola"
    + "violsviperviralvireovisasvisedvisesvisorvistavivasvixenvizorvodkavoguevoidsvoilevolesvoltsvomitvotedvotesvouch"
    + "vowedvowelvulvavyingwackowackswackywadedwaderwadeswadiswaferwaftswagedwagerwageswaifswailswaitswaivewakedwaken"
    + "wakeswaldowaledwaleswalkswallswaltzwandswanedwaneswanlywannawantswardswareswarezwarmswarnswarpswartswartywasps"
    + "wattswavedwaverwaveswaxedwaxenwaxeswealsweanswearswearyweavewedgeweedsweedyweeksweepsweepyweestweftsweirswelch"
    + "weldswellswelshweltswendswetlywhackwhamswharfwhatswhealwhelkwhelpwhenswhetswhiffwhimswhinewhinywhipswhirlwhirr"
    + "whirswhiskwhistwhitswhizzwhoopwhorlwickswidenwidowwieldwightwikiswildswiledwileswillswiltswimpswimpywincewinch"
    + "windswindywinedwineswingswinkswinoswipedwiperwipeswiredwireswiserwiseswispswispywitchwiveswizeswokenwolfswombs"
    + "wonkywoodswoodywooedwooerwoofswoolywoozywordswordyworkswormswormywovenwowedwrackwrapswraptwrathwreakwreckwrens"
    + "wrestwrierwringwristwritswrothwrungwryerwrylyxcviixenonxrefsxtermxviiixxiiixxviixxxiixxxivxxxixxxxvixylemyacks"
    + "yahooyanksyardsyarnsyawedyawlsyawnsyeahsyearnyearsyeastyellsyelpsyesesyocksyodelyoginyogisyokedyokelyokesyolks"
    + "yowlsyuccayucksyuckyyummyyuppyzebrazebuszeroszestszilchzincszingszippyzombizonalzonedzoneszoomszorch";

  function unpack(s) { var out = [], i; for (i = 0; i < s.length; i += 5) out.push(s.substr(i, 5)); return out; }
  var ANSWERS = unpack(ANS_PACK);
  var ALLOWED = Object.create(null);
  (function () {
    var i, ex = unpack(EXT_PACK);
    for (i = 0; i < ANSWERS.length; i++) ALLOWED[ANSWERS[i]] = 1;
    for (i = 0; i < ex.length; i++) ALLOWED[ex[i]] = 1;
  })();
  var TOTAL = ANSWERS.length;
  var OPENERS = ["crane", "slate", "trace", "least", "roast", "stare", "raise", "later",
                 "alter", "trail", "learn", "stone", "noise", "paint", "cheat", "train",
                 "score", "adore", "trade", "solar"];

  /* ── pattern scoring: 0 = absent, 1 = elsewhere, 2 = exact spot ─────────── */
  var _r = [0, 0, 0, 0, 0], _u = [0, 0, 0, 0, 0];
  function patternCode(g, a) {
    var i, j;
    for (i = 0; i < 5; i++) { _r[i] = 0; _u[i] = 0; }
    for (i = 0; i < 5; i++) if (g.charCodeAt(i) === a.charCodeAt(i)) { _r[i] = 2; _u[i] = 1; }
    for (i = 0; i < 5; i++) {
      if (_r[i] !== 0) continue;
      for (j = 0; j < 5; j++) {
        if (_u[j] === 0 && g.charCodeAt(i) === a.charCodeAt(j)) { _r[i] = 1; _u[j] = 1; break; }
      }
    }
    return (((_r[0] * 3 + _r[1]) * 3 + _r[2]) * 3 + _r[3]) * 3 + _r[4];
  }
  function decode(code) {
    var out = [0, 0, 0, 0, 0], i;
    for (i = 4; i >= 0; i--) { out[i] = code % 3; code = (code - out[i]) / 3; }
    return out;
  }
  function narrow(pool, guess, code) {
    var out = [], i;
    for (i = 0; i < pool.length; i++) if (patternCode(guess, pool[i]) === code) out.push(pool[i]);
    return out;
  }

  /* ── solver: pick the guess that shrinks the candidate list the most ────── */
  var _counts = new Int32Array(243);
  function bestGuess(pool) {
    if (!pool.length) return null;
    if (pool.length === 1) return { word: pool[0], exp: 1 };
    var cands = pool.length > 260 ? pool : ANSWERS;
    var inPool = Object.create(null), i, j, c, sum, exp, isIn;
    for (i = 0; i < pool.length; i++) inPool[pool[i]] = 1;
    var best = pool[0], bestExp = Infinity, bestIn = -1;
    for (i = 0; i < cands.length; i++) {
      var g = cands[i];
      _counts.fill(0);
      for (j = 0; j < pool.length; j++) _counts[patternCode(g, pool[j])]++;
      sum = 0;
      for (j = 0; j < 243; j++) { c = _counts[j]; if (c) sum += c * c; }
      exp = sum / pool.length;
      isIn = inPool[g] ? 1 : 0;
      if (exp < bestExp - 1e-9 || (exp < bestExp + 1e-9 && isIn > bestIn)) {
        best = g; bestExp = exp; bestIn = isIn;
      }
    }
    return { word: best, exp: bestExp };
  }

  /* ── DOM ────────────────────────────────────────────────────────────────── */
  var root = document.documentElement;
  var boardEl = document.getElementById("board");
  var kbEl = document.getElementById("kb");
  var toastEl = document.getElementById("toast");
  var liveEl = document.getElementById("live");
  var trailEl = document.getElementById("trail");
  var hintOut = document.getElementById("hintOut");
  var resultBox = document.getElementById("resultBox");
  var gridEl = document.getElementById("grid");
  var glineEl = document.getElementById("gline");
  var gnoteEl = document.getElementById("gnote");
  var newBtn = document.getElementById("newBtn");
  var giveBtn = document.getElementById("giveBtn");
  var hintBtn = document.getElementById("hintBtn");
  var el = {
    guess: document.getElementById("stGuess"), pool: document.getElementById("stPool"),
    out: document.getElementById("stOut"), state: document.getElementById("stState"),
    played: document.getElementById("tPlayed"), solved: document.getElementById("tSolved"),
    streak: document.getElementById("tStreak"), avg: document.getElementById("tAvg")
  };

  var ROWS = 6, COLS = 5;
  var tiles = [], rowEls = [];
  (function buildBoard() {
    var r, c;
    for (r = 0; r < ROWS; r++) {
      var row = document.createElement("div");
      row.className = "row";
      row.setAttribute("role", "group");
      row.setAttribute("aria-label", "Row " + (r + 1) + ", empty");
      var rt = [];
      for (c = 0; c < COLS; c++) {
        var t = document.createElement("div");
        t.className = "tile";
        row.appendChild(t);
        rt.push(t);
      }
      boardEl.appendChild(row);
      rowEls.push(row); tiles.push(rt);
    }
  })();

  var KEYS = {};
  var KROWS = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
  (function buildKeyboard() {
    var i, j;
    for (i = 0; i < 3; i++) {
      var row = document.createElement("div");
      row.className = "krow";
      if (i === 1) row.appendChild(mkSpacer());
      if (i === 2) row.appendChild(mkKey("enter", "Enter", true));
      for (j = 0; j < KROWS[i].length; j++) {
        var ch = KROWS[i].charAt(j);
        var k = mkKey(ch, ch, false);
        KEYS[ch] = k;
        row.appendChild(k);
      }
      if (i === 1) row.appendChild(mkSpacer());
      if (i === 2) row.appendChild(mkKey("back", "Del", true));
      kbEl.appendChild(row);
    }
    function mkSpacer() { var s = document.createElement("div"); s.className = "spacer"; return s; }
    function mkKey(code, label, wide) {
      var b = document.createElement("button");
      b.type = "button";
      b.className = "key" + (wide ? " wide" : "");
      b.textContent = label;
      b.setAttribute("aria-label", code === "back" ? "Delete letter" : code === "enter" ? "Submit guess" : "Letter " + code.toUpperCase());
      b.addEventListener("click", function (e) { press(code); if (e.detail > 0) b.blur(); });
      return b;
    }
  })();

  /* ── motion ─────────────────────────────────────────────────────────────── */
  var mqRM = window.matchMedia ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
  var reduced = mqRM ? mqRM.matches : false;

  /* ── game state ─────────────────────────────────────────────────────────── */
  var state = null;
  var session = { played: 0, solved: 0, streak: 0, sum: 0 };
  var STATUS = { play: "in play", won: "solved", lost: "out of guesses", gave: "revealed" };

  function newGame() {
    var answer = ANSWERS[(Math.random() * TOTAL) | 0];

    /* pick an opener that leaves a genuinely interesting board: at least one
       coloured tile to read at a glance, but nowhere near a giveaway. */
    var order = OPENERS.slice(), i, j, sw;
    for (i = order.length - 1; i > 0; i--) {
      j = (Math.random() * (i + 1)) | 0; sw = order[i]; order[i] = order[j]; order[j] = sw;
    }
    var opener = null, alt = "crane", altScore = -Infinity;
    for (i = 0; i < order.length; i++) {
      var o = order[i];
      if (o === answer || !ALLOWED[o]) continue;
      var marks = decode(patternCode(o, answer));
      var lit = 0, green = 0, m;
      for (m = 0; m < COLS; m++) { if (marks[m] > 0) lit++; if (marks[m] === 2) green++; }
      var n = narrow(ANSWERS, o, patternCode(o, answer)).length;
      var coloured = lit >= 1 && green <= 2;
      if (coloured && n >= 5 && n <= 140) { opener = o; break; }
      /* fallback ranking: colour first, then a candidate count inside the band */
      var score = (coloured ? 100 : 0) + (n >= 5 && n <= 140 ? 50 : 0) - Math.abs(n - 60) / 1000;
      if (score > altScore) { altScore = score; alt = o; }
    }
    if (!opener) opener = alt;

    state = {
      answer: answer, rows: [], cur: "", pool: ANSWERS.slice(), trail: [TOTAL],
      keys: Object.create(null), over: false, won: false, busy: false, status: STATUS.play
    };

    var r, c;
    for (r = 0; r < ROWS; r++) {
      rowEls[r].classList.remove("bad");
      rowEls[r].setAttribute("aria-label", "Row " + (r + 1) + ", empty");
      for (c = 0; c < COLS; c++) {
        var t = tiles[r][c];
        t.textContent = "";
        t.removeAttribute("data-s");
        t.className = "tile";
      }
    }
    for (var ch in KEYS) {
      KEYS[ch].removeAttribute("data-s");
      KEYS[ch].setAttribute("aria-label", "Letter " + ch.toUpperCase());
    }
    resultBox.hidden = true;
    hintOut.textContent = "Scores every word by how far it would cut the candidate list, on average.";
    setToast("");
    updatePanel();
    commit(opener);
  }

  function setToast(msg, cls) {
    toastEl.textContent = msg;
    toastEl.className = "toast" + (cls ? " " + cls : "");
  }
  function say(msg) { liveEl.textContent = msg; }

  var NAMES = ["not in the word", "in the word, wrong spot", "exact spot"];

  function commit(word) {
    var idx = state.rows.length;
    var code = patternCode(word, state.answer);
    var arr = decode(code);
    var i;
    state.rows.push({ w: word, a: arr });
    state.pool = narrow(state.pool, word, code);
    state.trail.push(state.pool.length);
    state.cur = "";
    for (i = 0; i < COLS; i++) {
      tiles[idx][i].textContent = word.charAt(i);
      tiles[idx][i].classList.add("filled");
      tiles[idx][i].classList.remove("pop");
    }
    state.busy = true;
    var mine = state;
    revealRow(idx, arr, function () {
      if (state !== mine) return;
      applyKeys(word, arr);
      state.busy = false;
      var won = word === state.answer;
      if (won) finish(true);
      else if (state.rows.length >= ROWS) finish(false);
      else if (idx === 0) setToast("opening guess played for you — your turn");
      else setToast("");
      updatePanel();
      announce(word, arr);
    });
  }

  function revealRow(idx, arr, done) {
    var i;
    if (reduced) {
      for (i = 0; i < COLS; i++) tiles[idx][i].setAttribute("data-s", arr[i]);
      labelRow(idx, arr);
      done();
      return;
    }
    var mine = state;
    for (i = 0; i < COLS; i++) {
      (function (i) {
        var t = tiles[idx][i];
        setTimeout(function () {
          if (state !== mine) return;
          t.classList.remove("flip");
          void t.offsetWidth;
          t.classList.add("flip");
          setTimeout(function () {
            if (state !== mine) return;
            t.setAttribute("data-s", arr[i]);
          }, 170);
          if (i === COLS - 1) setTimeout(function () {
            if (state !== mine) return;
            labelRow(idx, arr);
            done();
          }, 360);
        }, i * 120);
      })(i);
    }
  }

  function labelRow(idx, arr) {
    var w = state.rows[idx].w, parts = [], i;
    for (i = 0; i < COLS; i++) parts.push(w.charAt(i).toUpperCase() + " " + NAMES[arr[i]]);
    rowEls[idx].setAttribute("aria-label", "Row " + (idx + 1) + ": " + parts.join(", "));
  }

  function announce(word, arr) {
    var parts = [], i;
    for (i = 0; i < COLS; i++) parts.push(word.charAt(i).toUpperCase() + " " + NAMES[arr[i]]);
    var tail = state.over
      ? (state.won ? " Solved in " + state.rows.length + "." : " The word was " + state.answer.toUpperCase() + ".")
      : " " + state.pool.length + " candidate" + (state.pool.length === 1 ? "" : "s") + " left.";
    say(word.toUpperCase() + ": " + parts.join(", ") + "." + tail);
  }

  function applyKeys(word, arr) {
    var i;
    for (i = 0; i < COLS; i++) {
      var ch = word.charAt(i), s = arr[i];
      var prev = state.keys[ch];
      if (prev === undefined || s > prev) {
        state.keys[ch] = s;
        var k = KEYS[ch];
        if (k) {
          k.setAttribute("data-s", String(s));
          k.setAttribute("aria-label", "Letter " + ch.toUpperCase() + ", " + NAMES[s]);
        }
      }
    }
  }

  function paintCur(popLast) {
    var idx = state.rows.length, i;
    if (idx >= ROWS) return;
    for (i = 0; i < COLS; i++) {
      var t = tiles[idx][i], ch = state.cur.charAt(i) || "";
      if (t.textContent !== ch) {
        t.textContent = ch;
        if (ch) t.classList.add("filled"); else t.classList.remove("filled");
        if (ch && popLast && i === state.cur.length - 1 && !reduced) {
          t.classList.remove("pop"); void t.offsetWidth; t.classList.add("pop");
        }
      }
    }
  }

  function shake() {
    var idx = state.rows.length;
    if (idx >= ROWS || reduced) return;
    var row = rowEls[idx];
    row.classList.remove("bad"); void row.offsetWidth; row.classList.add("bad");
  }

  function submit() {
    if (state.cur.length < COLS) { setToast("needs five letters", "warn"); shake(); say("Needs five letters."); return; }
    var w = state.cur;
    if (!ALLOWED[w]) { setToast('"' + w.toUpperCase() + '" is not in the word list', "warn"); shake(); say(w.toUpperCase() + " is not in the word list."); return; }
    setToast("");
    commit(w);
  }

  function press(code) {
    if (!state) return;
    if (state.over) {
      if (code === "enter") newGame();
      return;
    }
    if (code === "enter") { if (!state.busy) submit(); return; }
    if (code === "back") {
      if (state.cur.length) { state.cur = state.cur.slice(0, -1); paintCur(false); setToast(""); }
      return;
    }
    if (state.cur.length < COLS) { state.cur += code; paintCur(true); }
  }

  function finish(won) {
    if (state.cur) { state.cur = ""; paintCur(false); }   /* drop letters typed mid-reveal */
    state.over = true;
    state.won = won;
    state.status = won ? STATUS.won : STATUS.lost;
    session.played++;
    if (won) {
      session.solved++; session.streak++; session.sum += state.rows.length;
      var n = state.rows.length;
      setToast(n === 1 ? "solved on the opening guess" : "solved in " + n + " guesses", "win");
      if (!reduced) hopRow(state.rows.length - 1);
    } else {
      session.streak = 0;
      setToast("out of guesses — the word was " + state.answer.toUpperCase(), "warn");
    }
    renderResult();
  }

  function giveUp() {
    if (state.over || state.busy) return;
    if (state.cur) { state.cur = ""; paintCur(false); }
    state.over = true;
    state.won = false;
    state.status = STATUS.gave;
    session.played++;
    session.streak = 0;
    setToast("revealed — the word was " + state.answer.toUpperCase(), "warn");
    say("Revealed. The word was " + state.answer.toUpperCase() + ".");
    renderResult();
    updatePanel();
  }

  function hopRow(idx) {
    var mine = state, i;
    for (i = 0; i < COLS; i++) {
      (function (i) {
        setTimeout(function () {
          if (state !== mine) return;
          var t = tiles[idx][i];
          t.classList.remove("hop"); void t.offsetWidth; t.classList.add("hop");
        }, i * 70);
      })(i);
    }
  }

  function renderResult() {
    var i, j;
    gridEl.textContent = "";
    for (i = 0; i < state.rows.length; i++) {
      var gr = document.createElement("div");
      gr.className = "grow";
      for (j = 0; j < COLS; j++) {
        var cell = document.createElement("div");
        cell.className = "gcell";
        cell.setAttribute("data-s", String(state.rows[i].a[j]));
        gr.appendChild(cell);
      }
      gridEl.appendChild(gr);
    }
    if (state.won) {
      glineEl.className = "gline ok";
      glineEl.textContent = "word guess  " + state.rows.length + "/6";
      gnoteEl.innerHTML = "Nothing to copy, nothing to post — the grid just lives here. Press <b>Enter</b> or hit <b>New word</b> for another.";
    } else {
      glineEl.className = "gline miss";
      glineEl.textContent = "word guess  X/6  ·  " + state.answer.toUpperCase();
      gnoteEl.innerHTML = "The answer was <span class=\"reveal\">" + state.answer.toUpperCase() + "</span>. Press <b>Enter</b> or hit <b>New word</b> for another.";
    }
    resultBox.hidden = false;
  }

  function updatePanel() {
    var used = state.rows.length;
    el.guess.textContent = (state.over ? used : Math.min(used + 1, ROWS)) + " / " + ROWS;
    el.pool.textContent = String(state.pool.length);
    el.pool.className = "sv" + (state.pool.length === 1 && !state.over ? " amber" : "");
    var outc = 0, ch;
    for (ch in state.keys) if (state.keys[ch] === 0) outc++;
    el.out.textContent = outc + (outc === 1 ? " letter" : " letters");
    el.state.textContent = state.status;
    el.state.className = "sv small" + (state.status === STATUS.won ? " ok" : state.status === STATUS.play ? "" : " warn");

    trailEl.textContent = "";
    for (var i = 0; i < state.trail.length; i++) {
      if (i) {
        var a = document.createElement("span");
        a.className = "arw"; a.textContent = "→";
        trailEl.appendChild(a);
      }
      var n = document.createElement("span");
      n.className = i === state.trail.length - 1 && i > 0 ? "cur" : "n0";
      n.textContent = String(state.trail[i]);
      trailEl.appendChild(n);
    }

    giveBtn.disabled = state.over;
    hintBtn.disabled = state.over || state.pool.length === 0;

    el.played.textContent = String(session.played);
    el.solved.textContent = String(session.solved);
    el.solved.className = "sv" + (session.solved > 0 ? " ok" : "");
    el.streak.textContent = String(session.streak);
    el.avg.textContent = session.solved ? (session.sum / session.solved).toFixed(1) : "—";
  }

  /* ── controls ───────────────────────────────────────────────────────────── */
  newBtn.addEventListener("click", function () { newGame(); });
  giveBtn.addEventListener("click", function () { giveUp(); });
  hintBtn.addEventListener("click", function () {
    if (!state || state.over) return;
    var pool = state.pool;
    if (!pool.length) { hintOut.textContent = "no candidate matches those colours."; return; }
    hintOut.textContent = "thinking…";
    var mine = state;
    setTimeout(function () {
      if (state !== mine) return;
      var b = bestGuess(pool);
      if (!b) { hintOut.textContent = "no candidate matches those colours."; return; }
      if (pool.length === 1) {
        hintOut.innerHTML = "one candidate left: <b>" + b.word + "</b>";
      } else {
        hintOut.innerHTML = "try <b>" + b.word + "</b> · leaves ≈ " +
          (b.exp < 10 ? b.exp.toFixed(1) : Math.round(b.exp)) + " of " + pool.length;
      }
      say("Suggested guess: " + b.word.toUpperCase());
    }, reduced ? 0 : 30);
  });

  document.addEventListener("keydown", function (e) {
    if (e.ctrlKey || e.metaKey || e.altKey) return;
    var ae = document.activeElement;
    var onBtn = ae && ae.tagName === "BUTTON";
    var k = e.key;
    if (k === "Enter" || k === " " || k === "Spacebar") {
      if (onBtn) return;               /* let the focused button activate itself */
      if (k === "Enter") { e.preventDefault(); press("enter"); }
      return;
    }
    if (k === "Backspace") { e.preventDefault(); press("back"); return; }
    if (k && k.length === 1) {
      var c = k.toLowerCase();
      if (c >= "a" && c <= "z") { e.preventDefault(); press(c); }
    }
  });

  /* ── theme + motion plumbing ────────────────────────────────────────────── */
  window.addEventListener("message", function (e) {
    var d = e.data;
    if (d && d.type === "sloprun:theme" && (d.theme === "light" || d.theme === "dark")) {
      root.setAttribute("data-theme", d.theme);
    }
  });
  if (mqRM) {
    var onRM = function () { reduced = mqRM.matches; };
    if (mqRM.addEventListener) mqRM.addEventListener("change", onRM);
    else if (mqRM.addListener) mqRM.addListener(onRM);
  }

  newGame();
})();
</script>
</body>
</html>

source-visible by construction · nothing is published here without its code

Comments

0 total

No comments yet. If you ran it, say what happened.

Report this post

Goes straight to the moderation queue. Enough independent reports and the post is suspended automatically until a human looks.

what is wrong