I'm a beginner trying to make a Wordle clone in python. I already have most of it sorted out but am concerned about my code being difficult to read. The part I'm struggling with the most is the algorithm for how guesses are displayed.
An easily overlooked aspect of the original game is that it tries to make the player's life easier by hiding additional instances of a character in a guess whenever all instances of that letter have been found. That is, if the solution was "walls", and the player inputs "lulls", the last three characters would show as green as expected, but the first 'L' would be greyed out to indicate that all instances of that letter have been found (only for that line, subsequent lines/guesses reset this).
This may seem obvious if you've played the game a lot, but many clones don't do this, which has the side effect of making the game harder. This answer to another wordle related question touches on this.
I'm trying to implement this functionality in the function that compares player input with the solution in my version, the relevant section of which currently looks like this:
from collections import Counter, defaultdict green = 3 yellow = 2 grey = 1 def compare_word(string, solution): def clear_yellow_letters(): # use counter to count instaces # of a letter in each string str_c_count = Counter(string) sol_c_count = Counter(solution) for k, v in c_green_count.items(): if v == sol_c_count[k]: # if there are more instances of letter than # have been located in solution, grey-out # additional instances if str_c_count[k] > sol_c_count[k]: for i in range(len(color_dic)): char = color_dic[i] if char == k and color_dic[i] == yellow: color_dic[i] = grey return color_dic # color_dic is actually a list >_>. since the same letter can appear # multiple times in a word, we prefer to use the index as a key # instead of a real dictionary, where repeated letters would all # point to the same color regardless of location. color_dic = string, [0 for c in string] c_green_count = defaultdict(int) # creates keys if they don't exist # this loop compares the chars in string and solution based on index, # and assigns a color to the respective position in the array. for i in range(len(color_dic)): char = color_dic[i] if char == solution[i]: color = green c_green_count[char] += 1 elif char in solution: color = yellow else: color = grey color_dic[i] = color if c_green_count.items(): color_dic = clear_yellow_letters() return color_dic print(compare_word('lulls', 'walls'))
This prints a tuple containing a string, and a list of ints referencing each color used for displaying guesses. Note that this use of print is just for demonstration, the actual output is handled in curses (that's what the numbers are for).
clear_yellow_letters() does what I just described. Without it
compare_word() would return the int that maps to
l in our string as 2 (yellow). While this works as it is, I feel there must be a simpler way to do it, as that section is a bit difficult to follow, even with all the comments.
Another thing I'm confused about is code style/formatting. This is only an excerpt of my full project, which I've split into several modules due to its length, but one issue I keep coming across is how to know when to break-down functions into smaller functions and when to not. With
compare_word() for example,
clear_yellow_letters() is only called inside of it. Should I give the latter any parameters if all the vars it uses exist in the same scope, or is it okay to use the same names in this case? Would it be best to define it as a separate function for legibility?
I hope this excerpt is sufficient for understanding the logic for how I'm trying to get the words displayed, I am not including the whole thing because as I mentioned, it's rather long, but if more context is needed I'll oblige. I'd appreciate any suggestions on what could be improved.