# Unwordle Solver Algorithm

rules

Unworld is a word guessing game in which it shows you a n*n color grid and a base word and the goal of the player is to fill words into the grid such that it follows these rules:

• a green brick must contain a letter from the base word with correct positioning.
• a yellow brick must contain a letter from the base word but in an incorrect position
• a gray brick must NOT contain ANY letter from the base word
• a level beneath another level must use all the information from the level above it:
• so: if a yellow or green letter is used on an higher level they must be used in a lower level
• if a gray letter is used on an higher level they must NOT be used on the lower level
• a yellow letter can not be used on the same index multiple times
• if it is known that there's only M amount of letter k, you can not use more than that amount in you building

example:  image on the left is the starting position.
image on the right is the winning position.
they follow all the rules mentioned above.

problem I wrote a code to solve the game and it can solve 80% of the puzzle with no sweat, but it get really slow as the question become more difficult. I am not sure if it was due to the algorithm or the flow of the program. The code was provided below.

link to the dictionary file I use

unwordle.py

def help_() -> None:
"""message for help/-help flags."""

s = """unwordle is a popular word game!
this program is a game solver.
first check out the unwordle game board.
then in command line type in python unwordle.py
if the first row is *green* *yellow* *gray* *gray* *gray*,
you would add GYXXX at the end of that command
you repeat this for the next two row.(all the hints)
and lastly typed in the answer word (letter only)
a sample output would look something like this:
python unwordle.py YXXXX XYXYX XGYXG ralph\n"""

print(s)
exit()
return

def check_sys_arg(sys_argv: list) -> list:
"""
validating the input of the user.
<br>including checking if word is the right len
<br>and if contains disallowed characters.
"""

ERROR_MSG_2 = ("include disallowed character in hint color:"+
"G for green, Y for yellow, and X for gray")
ERROR_MSG_3 = "include disallowed character in answer word"
ERROR_MSG_4 = "inconsistent word length in input"

ALLOWED_COLOR_S: set = set("GYX")
ALLOWED_CHR_S: set = set("abcdefghijklmnopqrstuvwxyz")

output = []

wrd_ln = len(sys_argv)

for x in range(1, len(sys_argv) - 1):
x = sys_argv[x].upper()
if set(x) - ALLOWED_COLOR_S:
print("use unwordle.py -help to get help")
raise Exception(ERROR_MSG_2)
if len(x) != wrd_ln:
print("use unwordle.py -help to get help")
raise Exception(ERROR_MSG_4)
output.append(x)

x = sys_argv[-1].lower()
if set(x) - ALLOWED_CHR_S:
print("use unwordle.py -help to get help")
raise Exception(ERROR_MSG_3)
if len(x) != wrd_ln:
print("use unwordle.py -help to get help")
raise Exception(ERROR_MSG_4)
output.append(x)

return output

def import_dictionary(file: str = "dictionary.txt",
target_len_int: int = 5) -> list:
"""
reading and filtering words from txt files.
<br>file: the directory of which txt file is located
<br>target_len_int : target word length
"""
output = []
with open(file, "r+") as f:  #reading list of words
for word in temp:
word = word.strip()
if len(word) == target_len_int:
output.append(word)
return output

def color_word(answer_word: str, guess_word: str) -> str:
"""
take two words and color accordingly.
an example output would be "XXYYG"
"""
color_l = ["X"] * len(guess_word)
for counter, (chr_1, chr_2) in enumerate(zip(answer_word, guess_word)):
if chr_1 == chr_2:
color_l[counter] = "G"
ans_wrd_l.remove(chr_1)
for counter, chr_1 in enumerate(guess_word):
if color_l[counter] == "G":
continue
if chr_1 in ans_wrd_l:
color_l[counter] = "Y"
ans_wrd_l.remove(chr_1)
return "".join(color_l)

def find_candidate(wrd_l: list, final_ans: str, search: str) -> dict:
"""
loop through a word list and search for words that fit the criteria.
<br>the result to the function is a dict with:
<br>key being the word, val being a tuple of two set.:
<br>explain below:
<br>the first set contain sucess guesses(Y/G)
<br>the second set contain failed guesses:
<br>X or Y that is out of position
"""
def multi_apperance(chr: str,
succes: set,
append_to: set,
break_: bool = True):
for x in range(1, len(o) + 1):
x = str(x) + chr
if x not in success:
if break_:
break

output = {}
for o in all_wrd_l:
if color_word(final_ans, o) != search:
continue

fail = set()
success = set()

for counter, (chr, color) in enumerate(zip(o, search)):
if color == "X":
continue

if chr in success:
multi_apperance(chr, success, success)
else:

if color == "Y":

for counter, (chr, color) in enumerate(zip(o, search)):
if color != "X":
continue
if chr not in success:
else:
multi_apperance(chr, success, fail, False)

output[o] = (success, fail)
return output

"""
collect a list of possible candidates and render result. always return 0.
<br>required args:
<br>cand_list -> the candidate list. for reference only.
<br>include a list of all possible candidate dict here.
<br>starting from clue 1 ...clue 3
"""

INSTRUCTION_MSG = """want a different answer?
enter 1 for a different answer or enter 0 to exit the program.
tip: you can enter any number and the word at that index will be changed
the left most word has a index of 1.
"""
print(INSTRUCTION_MSG)
while True:
print()
print("invalid input, let's try again.")
else:
def inner_main(depth: int,
cand_list: list,
display: list = [],
success_j: set = {},
fail_j: set = {}) -> 0:
"""The worker function for main."""

i_cands = cand_list[depth]

for cand in i_cands:
success_i, fail_i = i_cands[cand]
if display:
if success_i - success_j:
continue
if fail_i.intersection(fail_j):
continue
display.insert(0, cand)

if depth:
_ = inner_main(depth - 1, cand_list, answer, display,
success_i, fail_i.union(fail_j))
else:
print(display)

_ = int(_) - 1
del display[-1]
del display
if _:
return _ - 1

return 0

return 0

if __name__ == "__main__":
import sys
print()  # print an extra line to avoid any confusion
if len(sys.argv) == 1:
print("use unwordle.py -help to get help")
print()
exit()
help_flags = ["h", "help", "-help", "-h", "--help", "--h"]
if sys.argv.lower() in help_flags:
help_()
print()
if len(sys.argv) == 2:
print("use unwordle.py -help to get help")
print()
exit()
user_input_l: list = check_sys_arg(sys.argv)

WRD_LN = len(user_input_l)
`