1

I'm recreating Wordle in Python, but I'm running in to a problem. It highlights letters yellow even if there are too many of them. For example, if the word is gas and you enter a word such as gss, it highlights both letters s even though there is only 1 in the word. Here is my code:

import random
import time
import sys
import os

if os.name == 'nt':
    from ctypes import windll
    k = windll.kernel32
    k.SetConsoleMode(k.GetStdHandle(-11), 7)

keys = {'a': 'NSr', 'b': 'rlK', 'c': 'yDD', 'd': 'YBr', 'e': 'XBB', 'f': 'LLo', 'g': 'gZn', 'h': 'LTd', 'i': 'hKn', 'j': 'fWj', 'k': 'dgu', 'l': 'nFN', 'm': 'nNy',
        'n': 'QKD', 'o': 'cJJ', 'p': 'MEA', 'q': 'WTJ', 'r': 'nnM', 's': 'Tru', 't': 'xcE', 'u': 'Msx', 'v': 'Cef', 'w': 'Hkf', 'x': 'obn', 'y': 'myp', 'z': 'PUE'}

keyr = {v: k for k, v in keys.items()}

def encrypt(text):
  if len(text) > 1:
    string = ""
    for char in text:
      if char in keys:
        string += keys[char] + ","
      else:
        return "Only letters are allowed"
        break
    return string
  else:
    return "Text must have something in it"

def decrypt(text):
  text = text[:-1].split(",")
  if len(text) > 1:
    string = ""
    for char in text:
      if char in keyr:
        string += keyr[char]
      else:
        return "Only letters are allowed"
        break
    return string
  else:
    return "Text must have something in it"

print("Welcome to Wordle!")
print("Random or Custom Word?")
ch = input("Type 'r' or 'c' ")

if ch not in ("r", "c"):
  while ch not in ("r", "c"):
    ch = input("Type 'r' or 'c' ")

green = "\u001b[32m"
yellow = "\u001b[33m"
reset = "\u001b[0m"

if ch == "r":
  letters = "abcdefghijklmnopqrstuvwxyz"
  ln = {}
  for char in letters:
    ln[char] = 0
  words = open("words.txt", "r")
  wordl = []
  for item in words.readlines():
    wordl.append(item.strip())
  word = wordl[random.randint(0, 5756)]
  print(f'Your word is 5 letters. Start guessing!')
  num = 1
  correct = False
  while num < 6:
    guess = input(f'Guess {str(num)}: ').lower()
    sys.stdout.write("\033[F")
    invalid = False
    for char in guess:
      if char not in keys:
        print(" " * 250)
        sys.stdout.write("\033[F")
        print("Must be only letters!")
        invalid = True
    if len(guess) > 5:
      print(" " * 250)
      sys.stdout.write("\033[F")
      print("Word is too long.")
    elif len(guess) < 5:
      print(" " * 250)
      sys.stdout.write("\033[F")
      print("Word is too short.")
    elif guess not in wordl:
      print(" " * 250)
      sys.stdout.write("\033[F")
      print("Invalid word.")
    elif invalid:
      pass
    else:
      if guess == word:
        print("Your word is correct!")
        correct = True
        break
      chn = 0
      colored = ""
      for char in guess:
        if char in word:
          if char == word[chn]:
            colored += f'{green}{char}{reset}'
          else:
            colored += f'{yellow}{char}{reset}'
        else:
          colored += char
        chn += 1
      print(f'Guess {str(num)}: ' + colored)
      num += 1
  if correct == False:
    print(f'You lose! The word was {word}. Better luck next time!')
  else:
    print("Congratulations! You win!")
  time.sleep(999)

The solution I tried was creating a dictionary of every letter and the number of times it appears that resets every word you enter, like this:

letters_n = {}
letters = "abcdefghijklmnopqrstuvwxyz"
for char in letters:
  letters_n[char] = 0

And then when it went over a letter, I added the number and checked it against the count of that character in the word:

for char in guess:
  if char in word:
    if char == word[chn]:
      colored += f'{green}{char}{reset}'
    else:
      if letters_n[char] >= word.count(char):
        colored += char
      else:
        colored += f'{yellow}{char}{reset}'
      letters_n[char] += 1
  else:
    colored += char

It still highlighted letters yellow that were not in the word. How can I fix this? (Sorry for long code sample)

Donoru
  • 115
  • 1
  • 15

1 Answers1

2

You need to eliminate the letters once you check them.

This uses 2 loops so that all the green letters will take precedent, and then the yellow and white letters will be considered.

else:
    if guess == word:
        print("Your word is correct!")
        correct = True
        break

    arr = list(word) # this is a copy of your actual word
    ans = [None for _ in range(len(arr))] # this is your colored string output

    for i, char in enumerate(guess): # check only for green letters first
        if char == arr[i]:
            ans[i] = f"{green}{char}{reset}" # print green
            arr[i] = None # remove the letter so it can't be checked again

    for i, char in enumerate(guess): # check for yellow and white letters
        if char in arr and ans[i] is None:
            ans[i] = f"{yellow}{char}{reset}" # print yellow
        elif ans[i] is None:
            ans[i] = char # print white
        arr[i] = None # remove the letter so it can't be checked again
        
    print(f'Guess {str(num)}: ' + "".join(ans)) # print the guess with the correct colouring
    num += 1 # increment number of guesses
QuantumMecha
  • 1,514
  • 3
  • 22
  • Would I implement this by changing the variable `ans` to `guess`? – Donoru Mar 10 '22 at 16:03
  • No, this is a drop in replacement. I've edited my answer so it should be more obvious where to put it. `ans` does not need to change as that is the output. `guess` is already used when enumerating through to check for letters – QuantumMecha Mar 10 '22 at 23:23