I created a Python script that solves Wordle (more specifically this version: https://mywordle.org), it uses a wordlist of all possible answers, it is working perfectly and it rarely loses, you can see it in action here (Google Drive).
You will need this file, I obtained it by editing this file: https://mywordle.org/f5.txt?v=0.2.0.
The Script:
import random
import re
import time
from copy import deepcopy
from pathlib import Path
from selenium import webdriver
from selenium.webdriver import FirefoxProfile
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.firefox.options import Options
from string import ascii_lowercase
options = Options()
options.add_argument("--log-level=3")
options.add_argument("--mute-audio")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
capabibilties = DesiredCapabilities().FIREFOX
capabibilties['pageLoadStrategy'] = 'eager'
profile = FirefoxProfile()
profile.set_preference("http.response.timeout", 1)
Firefox = webdriver.Firefox(capabilities=capabibilties, options=options, firefox_profile=profile)
wait = WebDriverWait(Firefox, 3)
grid = "//div/div[contains(@class, 'game-grid')]"
cell = grid + "/div[contains(@class, 'game-item')]"
states = {
'bg-gray-400': 'absent',
'bg-orange-400': 'present',
'bg-green-500': 'correct'
}
wordlelist = Path('D:/corpus/wordle-5.txt').read_text().splitlines()
class Agent:
def __init__(self):
self.pool = deepcopy(wordlelist)
self.letters = ascii_lowercase
self.pattern = ''
self.present = set()
def guess(self):
return random.choice(self.pool)
def update(self, conditions):
pool = list()
self.process(conditions)
for word in self.pool:
if re.match(self.pattern, word):
if not self.present or all(l in word for l in self.present):
pool.append(word)
self.pool = pool
def process(self, conditions):
for letter, state in conditions:
if state == 'absent':
self.letters = self.letters.replace(letter, '')
pattern = []
self.present.clear()
for letter, state in conditions:
if state == 'absent':
pattern.append('[' + self.letters + ']')
elif state == 'present':
pattern.append('[' + self.letters.replace(letter, '') + ']')
self.present.add(letter)
elif state == 'correct':
pattern.append(letter)
self.pattern = '^' + ''.join(pattern) + '$'
def solve():
agent = Agent()
correct_status = ['bg-green-500'] * 5
wait.until(EC.visibility_of_element_located((By.XPATH, grid)))
for i in range(6):
guess = agent.guess()
Firefox.find_element('xpath', '//body').send_keys(guess)
Firefox.find_element('xpath', '//body').send_keys(Keys.ENTER)
cells = Firefox.find_elements('xpath', cell)
time.sleep(2)
status = [c.find_element('xpath', './div[2]').get_attribute('class').split()[2] for c in cells[i*5:i*5+5]]
if status == correct_status:
break
status = [states[s] for s in status]
agent.update(list(zip(guess, status)))
time.sleep(3)
wait.until(EC.visibility_of_element_located((By.XPATH, '//div[1]/div[1]/button[3]')))
Firefox.find_element('xpath', '//div[1]/div[1]/button[3]').click()
if __name__ == '__main__':
Firefox.get('https://mywordle.org')
time.sleep(3)
while True:
solve()
I wrote this script in under 3 hours all by myself, the part of the script that I want to get reviewed is the class Agent
. It can work with other front-end as well, I am perfectly capable of writing a full-fledged working GUI Wordle game using PyQt6, but nah I am lazy.
I want to know how I can improve the logic, algorithm, efficiency et cetera of that particular class.