How to resolve the algorithm Wordle comparison step by step in the Haskell programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Wordle comparison step by step in the Haskell programming language

Table of Contents

Problem Statement

While similar to both Bulls and cows and Mastermind, Wordle is a notable variation, having experienced a viral surge in popularity, and reverse engineering the game or creating variants has become a popular programming exercise. However, a sampling of the "code a Wordle clone" videos on YouTube shows that seven of the eight reviewed had a serious flaw in the way that they assigned colours to the letters of a guessed word. This aspect of the game is described here: en.wikipedia.org/wiki/Wordle#Gameplay Create a function or procedure that takes two strings; the answer string, and the guess string, and returns a string, list, dynamic array or other ordered sequence indicating how each letter should be marked as per the description above. (e.g. "green", "yellow", or "grey", or, equivalently, the integers 2, 1, or 0 or suchlike.) You can assume that both the answer string and the guess string are the same length, and contain only printable characters/code points in the ASCII/UniCode Range ! to ~ (hex 20 to 7F) and that case is significant. (The original game only uses strings of 5 characters, all alphabetic letters, all in the same case, but this allows for most existing variants of the game.) Provide test data and show the output here. The test data should include the answer string ALLOW and the guess string LOLLY, and the result should be (yellow, yellow, green, grey, grey) or equivalent.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Wordle comparison step by step in the Haskell programming language

Importing Libraries:

  • Data.Bifunctor for uncurrying functions (first)
  • Data.List for list operations (intercalate, mapAccumL)
  • Data.Map.Strict for managing maps (M.Map)
  • Data.Maybe for retrieving values from Maybe (fromMaybe)

Wordle Comparison Functions:

  • wordleScore compares two strings (target and guess) and returns a list of scores indicating the correctness of each character position. It leverages charCounts to determine the character frequencies in the guess.
  • green handles "green" matches (correct letter in correct position).
  • amber handles "amber" matches (correct letter, but incorrect position).

Score Calculation:

  • charCounts builds a map of character frequencies in a string.
  • The mapAccumL function processes a list of tuples (zip of target and guess characters) using green and amber.
  • The result is a tuple containing the remaining characters and a list of scores.

Test Driver:

  • main function provides test cases and prints the results.
  • wordleReport generates a report for each test case, showing the target, guess, scores, and color-coded results.
  • color maps scores to color representations ("green", "amber", "gray").

Source code in the haskell programming language

import Data.Bifunctor (first)
import Data.List (intercalate, mapAccumL)
import qualified Data.Map.Strict as M
import Data.Maybe (fromMaybe)

type Tally = M.Map Char Int

-------------------- WORDLE COMPARISON -------------------

wordleScore :: String -> String -> [Int]
wordleScore target guess =
  snd $
    uncurry (mapAccumL amber) $
      first charCounts $
        mapAccumL green [] (zip target guess)

green :: String -> (Char, Char) -> (String, (Char, Int))
green residue (t, g)
  | t == g = (residue, (g, 2))
  | otherwise = (t : residue, (g, 0))

amber :: Tally -> (Char, Int) -> (Tally, Int)
amber tally (_, 2) = (tally, 2)
amber tally (c, _)
  | 0 < fromMaybe 0 (M.lookup c tally) =
      (M.adjust pred c tally, 1)
  | otherwise = (tally, 0)

charCounts :: String -> Tally
charCounts =
  foldr
    (flip (M.insertWith (+)) 1)
    M.empty

--------------------------- TEST -------------------------
main :: IO ()
main = do
  putStrLn $ intercalate " -> " ["Target", "Guess", "Scores"]
  putStrLn []
  mapM_ (either putStrLn putStrLn) $
    uncurry wordleReport
      <$> [ ("ALLOW", "LOLLY"),
            ("CHANT", "LATTE"),
            ("ROBIN", "ALERT"),
            ("ROBIN", "SONIC"),
            ("ROBIN", "ROBIN"),
            ("BULLY", "LOLLY"),
            ("ADAPT", "SÅLÅD"),
            ("Ukraine", "Ukraíne"),
            ("BBAAB", "BBBBBAA"),
            ("BBAABBB", "AABBBAA")
          ]

wordleReport :: String -> String -> Either String String
wordleReport target guess
  | 5 /= length target =
      Left (target <> ": Expected 5 character target.")
  | 5 /= length guess =
      Left (guess <> ": Expected 5 character guess.")
  | otherwise =
      let scores = wordleScore target guess
       in Right
            ( intercalate
                " -> "
                [ target,
                  guess,
                  show scores,
                  unwords (color <$> scores)
                ]
            )

color 2 = "green"
color 1 = "amber"
color _ = "gray"


  

You may also check:How to resolve the algorithm Leap year step by step in the X86 Assembly programming language
You may also check:How to resolve the algorithm Inverted index step by step in the Common Lisp programming language
You may also check:How to resolve the algorithm Strip control codes and extended characters from a string step by step in the D programming language
You may also check:How to resolve the algorithm Totient function step by step in the FreeBASIC programming language
You may also check:How to resolve the algorithm N-queens problem step by step in the Racket programming language