Home Posts Post Search Tag Search

Game Site Journal - 12 Wordle Feedback
Published on: 2025-04-28 Tags: elixir, Side Project, LiveView, Game Site, Keyboard

This is a little piece of work I did on the Wordle. I was having an issue with the feedback on the words not being correct. I wanted to make sure that a letter only gets a yellow if it’s in the word, not already in the right position, and not already counted for.

Initial setup:

letter_count =
  letter_count(word)
  |> IO.inspect(label: "Letter Count")

Enum.map(index_guess, fn {letter, index} ->
  cond do
    {letter, index} in index_word ->
      letter_count = Map.update!(letter_count, letter, fn count -> count - 1 end)
      |> IO.inspect(label: "green")
      [letter, "bg-green-400"]

    letter in String.split(word, "", trim: true) and letter_count[letter] > 0 ->
      letter_count = Map.update!(letter_count, letter, fn count -> count - 1 end)
      |> IO.inspect(label: "yellow")
      [letter, "bg-yellow-300"]

    true ->
      [letter, "bg-gray-300"]
  end
end)

This approach didn’t work for words like "Tolls" when entering "Torts" — it would output 1 green t and 1 yellow t.


Solution: Two Passes

First pass – set greens:

{green_results, letter_count_after_greens} =
  Enum.map_reduce(index_guess, letter_count, fn {letter, index}, letter_count ->
    if {letter, index} in index_word do
      letter_count = Map.update!(letter_count, letter, fn count -> count - 1 end)
      IO.inspect(letter_count, label: "green update")
      {[letter, "bg-green-400"], letter_count}
    else
      {[{letter, index}], letter_count}
    end
  end)

Second pass – set yellows and grays:

{final_results, _final_letter_count} =
  Enum.map_reduce(green_results, letter_count_after_greens, fn
    [{letter, index}], letter_count ->
      if letter in String.split(word, "", trim: true) and letter_count[letter] > 0 do
        letter_count = Map.update!(letter_count, letter, fn count -> count - 1 end)
        IO.inspect(letter_count, label: "yellow update")
        {[letter, "bg-yellow-300"], letter_count}
      else
        {[letter, "bg-gray-300"], letter_count}
      end

    # Already green
    [letter, color], letter_count ->
      {[letter, color], letter_count}
  end)

Explanation

  • First pass: We use Enum.map_reduce instead of Enum.map so letter_count can be updated. Any letter in the correct position (green) is handled here. Non-green letters are kept as {letter, index} for the next pass.

  • Second pass: green_results contains two types:

    • [letter, color] → already green
    • {letter, index} → not yet colored

    We use pattern matching on the function inputs to handle each case.

    • [letter, color] → keep the same output, maintain letter_count
    • {letter, index} → check if it should be yellow or gray

The tricky part was keeping letter_count updated while still passing the correct information to the next Enum. This two-pass approach solves that elegantly while reusing most of the original code.