Wordle Solver

Games

Gather input about an in-progress Wordle game and present a live-updating list of valid candidates.

This example isn't too useful as a form, but shows the power of programmability in this context. With a relatively modest line count, the code is only focused on the core solving loop, pretty much the way you'd write it if you were building a command-line solver: download a word list, and filter it down incrementally based on user input until a single word remains.

Formulate wraps an interactive web UI over this core loop, and gives you undo for free.

Build
Build on this example by creating an editable copy of this form.
let alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

let getDescription = (words) => {
  if (words.length > 5) {
    return `${words.slice(0, 5).join(", ")}, and ${words.length - 5} more`;
  } else {
    return words.join(", ");
  }
};

export default async function () {
  let url = "https://prod.static.formulate.dev/gallery/wordle.txt";
  let response = await form.fetch(url);
  let words = response.text.split("\n");

  await form.statement("Hello, welcome to the Wordle solver!", {
    description: `
- Enter a starting word on [the Wordle website](https://www.nytimes.com/games/wordle), and then hit Next.
- **Candidates**: ${getDescription(words)}
    `,
  });

  while (true) {
    let { value: type } = await form.multi(
      "Do you want to tell me about a green, yellow, or gray letter?",
      ["Green", "Yellow", "Gray"],
      { single: true }
    );

    let { value: letter } = await form.multi("Ok, and what letter?", alphabet, {
      hideNumbers: true,
      single: true,
    });
    letter = letter.toLowerCase();

    if (type === "Green") {
      let { value: position } = await form.multi(
        "Great, and what position?",
        [1, 2, 3, 4, 5],
        { hideNumbers: true, single: true }
      );
      words = words.filter((word) => word[position - 1] === letter);
    }

    if (type === "Yellow") {
      let { value: position } = await form.multi(
        "Great, and what position?",
        [1, 2, 3, 4, 5],
        { hideNumbers: true, single: true }
      );
      words = words.filter(
        (word) => word[position - 1] !== letter && word.includes(letter)
      );
    }

    if (type === "Gray") {
      words = words.filter((word) => !word.includes(letter));
    }

    await form.statement("Ok, I think I've got that!", {
      description: `**Candidates remaining**: ${getDescription(words)}`,
    });

    if (words.length === 1) {
      break;
    }
  }
}