How to resolve the algorithm Wordle comparison step by step in the Python programming language
How to resolve the algorithm Wordle comparison step by step in the Python 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 Python programming language
This Python code defines functions for comparing words based on the popular game Wordle. The core functions are aimed at scoring guesses.
Function Overview:
- wordleScore(target, guess): Calculates the Wordle score by comparing the characters in the guess to the target word.
- green(residue, tg): Scores characters in the guess that are in the correct position as the target.
- amber(tally, cn): Scores characters in the guess that are present in the target but in different positions.
Implementation Details:
wordleScore:
- Uses
mapAccumL
to combinegreen
andamber
to calculate the score for each character. - The score is represented as a sequence of integers: 2 for correct position, 1 for incorrect position, and 0 for absent.
green:
- Checks if the characters in the guess and target match.
- If they match, returns a score of 2 and adds the character to the list of residues.
- Otherwise, returns a score of 0 and adds the character to the residue list.
amber:
- Adjusts the tally of unmatched characters.
- If the character is found in the tally, decrements the count and returns a score of 1.
- If the character is not found or the count is 0, returns a score of 0.
Generic Helper Functions:
adjust
: Updates a dictionary with a new value for a given key.charCounts
: Counts the occurrences of characters in a string.first
: Applies a function to the first element of a tuple.insertWith
: Inserts a key-value pair into a dictionary, using a specified function to update the value if it exists.mapAccumL
: Computes a sequence of values while accumulating a second sequence.second
: Applies a function to the second element of a tuple.
Testing:
The script includes a main
function that tests the Wordle comparison functions on various pairs of target and guess words, displaying the colored scores for each character in the guess.
Source code in the python programming language
'''Wordle comparison'''
from functools import reduce
from operator import add
# wordleScore :: String -> String -> [Int]
def wordleScore(target, guess):
'''A sequence of integers scoring characters
in the guess:
2 for correct character and position
1 for a character which is elsewhere in the target
0 for for character not seen in the target.
'''
return mapAccumL(amber)(
*first(charCounts)(
mapAccumL(green)(
[], zip(target, guess)
)
)
)[1]
# green :: String -> (Char, Char) -> (String, (Char, Int))
def green(residue, tg):
'''The existing residue of unmatched characters, tupled
with a character score of 2 if the target character
and guess character match.
Otherwise, a residue (extended by the unmatched
character) tupled with a character score of 0.
'''
t, g = tg
return (residue, (g, 2)) if t == g else (
[t] + residue, (g, 0)
)
# amber :: Dict -> (Char, Int) -> (Dict, Int)
def amber(tally, cn):
'''An adjusted tally of the counts of unmatched
of remaining unmatched characters, tupled with
a 1 if the character was in the remaining tally
(now decremented) and otherwise a 0.
'''
c, n = cn
return (tally, 2) if 2 == n else (
adjust(
lambda x: x - 1,
c, tally
),
1
) if 0 < tally.get(c, 0) else (tally, 0)
# ------------------------- TEST -------------------------
# main :: IO ()
def main():
'''Scores for a set of (Target, Guess) pairs.
'''
print(' -> '.join(['Target', 'Guess', 'Scores']))
print()
print(
'\n'.join([
wordleReport(*tg) for tg in [
("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 -> String
def wordleReport(target, guess):
'''Either a message, if target or guess are other than
five characters long, or a color-coded wordle score
for each character in the guess.
'''
scoreName = {2: 'green', 1: 'amber', 0: 'gray'}
if 5 != len(target):
return f'{target}: Expected 5 character target.'
elif 5 != len(guess):
return f'{guess}: Expected 5 character guess.'
else:
scores = wordleScore(target, guess)
return ' -> '.join([
target, guess, repr(scores),
' '.join([
scoreName[n] for n in scores
])
])
# ----------------------- GENERIC ------------------------
# adjust :: (a -> a) -> Key -> Dict -> Dict
def adjust(f, k, dct):
'''A new copy of the Dict, in which any value for
the given key has been updated by application of
f to the existing value.
'''
return dict(
dct,
**{k: f(dct[k]) if k in dct else None}
)
# charCounts :: String -> Dict Char Int
def charCounts(s):
'''A dictionary of the individual characters in s,
with the frequency of their occurrence.
'''
return reduce(
lambda a, c: insertWith(add)(c)(1)(a),
list(s),
{}
)
# first :: (a -> b) -> ((a, c) -> (b, c))
def first(f):
'''A simple function lifted to a function over a tuple,
with f applied only the first of two values.
'''
return lambda xy: (f(xy[0]), xy[1])
# insertWith :: Ord k => (a -> a -> a) ->
# k -> a -> Map k a -> Map k a
def insertWith(f):
'''A new dictionary updated with a (k, f(v)(x)) pair.
Where there is no existing v for k, the supplied
x is used directly.
'''
return lambda k: lambda x: lambda dct: dict(
dct,
**{k: f(dct[k], x) if k in dct else x}
)
# mapAccumL :: (acc -> x -> (acc, y)) -> acc ->
# [x] -> (acc, [y])
def mapAccumL(f):
'''A tuple of an accumulation and a map
with accumulation from left to right.
'''
def nxt(a, x):
return second(lambda v: a[1] + [v])(
f(a[0], x)
)
return lambda acc, xs: reduce(
nxt, xs, (acc, [])
)
# second :: (a -> b) -> ((c, a) -> (c, b))
def second(f):
'''A simple function lifted to a function over a tuple,
with f applied only to the second of two values.
'''
return lambda xy: (xy[0], f(xy[1]))
# MAIN ---
if __name__ == '__main__':
main()
You may also check:How to resolve the algorithm Levenshtein distance/Alignment step by step in the D programming language
You may also check:How to resolve the algorithm Forest fire step by step in the Rust programming language
You may also check:How to resolve the algorithm FizzBuzz step by step in the Picat programming language
You may also check:How to resolve the algorithm Check that file exists step by step in the Elena programming language
You may also check:How to resolve the algorithm Array concatenation step by step in the Oberon-2 programming language