initial commit
This commit is contained in:
commit
fcdfd667bd
17
.drone.yml
Normal file
17
.drone.yml
Normal file
@ -0,0 +1,17 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: solve
|
||||
trigger:
|
||||
event: [cron]
|
||||
cron: [daily-solve]
|
||||
|
||||
|
||||
steps:
|
||||
- name: run
|
||||
image: joyzoursky/python-chromedriver:3.9-selenium
|
||||
environment:
|
||||
SLACK_HOOK_URL:
|
||||
from_secret: slack_hook_url
|
||||
commands:
|
||||
- pip install requests
|
||||
- python bot.py
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
**/__pycache__*
|
155
bot.py
Normal file
155
bot.py
Normal file
@ -0,0 +1,155 @@
|
||||
import collections
|
||||
import datetime
|
||||
import os
|
||||
import pathlib
|
||||
import time
|
||||
|
||||
import requests
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
|
||||
EMOJI = {
|
||||
'absent': ':black_large_square:',
|
||||
'present': ':large_yellow_square:',
|
||||
'correct': ':large_green_square:',
|
||||
}
|
||||
|
||||
|
||||
def filter_word(word, conditions):
|
||||
# first, filter on correct
|
||||
for char, idx in conditions['correct']:
|
||||
if word[idx] != char:
|
||||
return False
|
||||
|
||||
# we only want to consider characters in positions that haven't been spoken for already
|
||||
positions = [0, 1, 2, 3, 4]
|
||||
for _, i in conditions['correct']:
|
||||
positions.remove(i)
|
||||
|
||||
# now filter on present-but-not-correct
|
||||
if conditions['present']:
|
||||
required_chars = set(c[0] for c in conditions['present'])
|
||||
actual_chars = set(word[p] for p in positions)
|
||||
overlap = required_chars & actual_chars
|
||||
if len(overlap) == 0:
|
||||
return False
|
||||
|
||||
to_remove = []
|
||||
for cond in conditions['present']:
|
||||
for p in positions:
|
||||
char = word[p]
|
||||
if cond[0] == char:
|
||||
if cond[1] == p:
|
||||
return False # this might break everything?
|
||||
else:
|
||||
to_remove.append(p)
|
||||
|
||||
# remove the characters that met our criteria above
|
||||
for p in to_remove:
|
||||
positions.remove(p)
|
||||
|
||||
# filter on absence
|
||||
for p in positions:
|
||||
char = word[p]
|
||||
if char in conditions['absent']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class Solver:
|
||||
def __init__(self):
|
||||
print('Launching web browser')
|
||||
self.driver = self.setup_driver()
|
||||
print('Navigating to page')
|
||||
self.driver.get('https://www.powerlanguage.co.uk/wordle/')
|
||||
time.sleep(2)
|
||||
self.body = self.driver.find_element(By.TAG_NAME, 'body')
|
||||
self.body.click()
|
||||
self.words = pathlib.Path('dictionary.txt').read_text().splitlines()
|
||||
|
||||
def setup_driver(self):
|
||||
options = ChromeOptions()
|
||||
options.headless = True
|
||||
options.add_argument('--no-sandbox')
|
||||
options.add_argument('--remote-debugging-port=9222')
|
||||
return webdriver.Chrome(options=options)
|
||||
|
||||
def input_word(self, word):
|
||||
for char in word:
|
||||
self.body.send_keys(char)
|
||||
self.body.send_keys(Keys.ENTER)
|
||||
|
||||
def get_rows(self):
|
||||
return self.driver.execute_script(
|
||||
"""return Array.from(
|
||||
document
|
||||
.querySelector('game-app')
|
||||
.shadowRoot
|
||||
.querySelectorAll('game-row')
|
||||
).map(e => e.shadowRoot.querySelectorAll('game-tile'))"""
|
||||
)
|
||||
|
||||
def read_row(self, n):
|
||||
result = {
|
||||
'present': [],
|
||||
'correct': [],
|
||||
'absent': [],
|
||||
}
|
||||
rows = self.get_rows()
|
||||
for i, tile in enumerate(rows[n]):
|
||||
char = tile.get_attribute('letter')
|
||||
status = tile.get_attribute('evaluation')
|
||||
result[status].append((char, i))
|
||||
|
||||
result['absent'] = set(c[0] for c in result['absent'])
|
||||
return result
|
||||
|
||||
def get_history(self, row_count):
|
||||
rows = self.get_rows()
|
||||
history = []
|
||||
for i in range(row_count):
|
||||
row_hist = []
|
||||
for tile in rows[i]:
|
||||
status = tile.get_attribute('evaluation')
|
||||
row_hist.append(EMOJI[status])
|
||||
history.append(row_hist)
|
||||
return history
|
||||
|
||||
def solve(self):
|
||||
print('Attempting to solve')
|
||||
for i in range(6):
|
||||
print('Trying word:', self.words[0])
|
||||
self.input_word(self.words[0])
|
||||
time.sleep(2)
|
||||
|
||||
conditions = self.read_row(i)
|
||||
if len(conditions['correct']) == 5:
|
||||
return {
|
||||
'word': self.words[0],
|
||||
'history': self.get_history(i + 1),
|
||||
'iterations': i + 1
|
||||
}
|
||||
|
||||
self.words = [w for w in self.words if filter_word(w, conditions)]
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
solver = Solver()
|
||||
try:
|
||||
result = solver.solve()
|
||||
finally:
|
||||
solver.driver.close()
|
||||
|
||||
if result:
|
||||
print(f'Success!')
|
||||
wordle_num = (datetime.date.today() - datetime.date(2022, 1, 17)).days + 212
|
||||
lines = [f"Wordle {wordle_num}: {result['iterations']}/6"]
|
||||
lines = lines + [''.join(row) for row in result['history']]
|
||||
requests.post(os.environ['SLACK_HOOK_URL'], json={'text': '\n'.join(lines)})
|
||||
else:
|
||||
print('Failed to find the word.')
|
12972
dictionary.txt
Normal file
12972
dictionary.txt
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user