forked from meicholtz/wordle
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
203 lines (166 loc) · 6.18 KB
/
utils.py
File metadata and controls
203 lines (166 loc) · 6.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# utils.py
# Python library of functions related to Wordle game.
#
# Author: Matthew Eicholtz
# Inspired by: https://www.powerlanguage.co.uk/wordle/
from colorama import Fore
import os
import pdb
from pynput import keyboard
import subprocess
def getfeedback(guess, secret):
"""Check whether the guess matches the secret word, providing feedback about each letter.
Parameters
----------
guess : str
Word that the player guesses.
secret : str
Word that the player is trying to guess.
Returns
-------
feedback: list
A list of integers, one per letter in the guess, to indicate if the letter is correct (2),
almost correct (1), or incorrect (0).
"""
# Check for valid inputs
if not isinstance(guess, str) or not isinstance(secret, str):
raise TypeError("inputs must be strings")
elif len(guess) != len(secret):
raise ValueError("length of inputs must be equal")
# Initialize feedback
n = len(guess)
feedback = [0] * n # assume no letters match at first
# Find correct letters
for i in range(n):
if guess[i] == secret[i]:
feedback[i] = 2
# Find almost correct letters (exists in the secret, but in a different position)
letters = ''.join([letter for letter, match in zip(secret, feedback) if not match])
for i in range(n):
if feedback[i] != 2 and guess[i] in letters:
feedback[i] = 1
j = letters.index(guess[i])
letters = letters[:j] + letters[j+1:]
return feedback
def getkey(debug=False):
"""Wait for the user to press a key. Valid options include a letter, Backspace, Enter, or Escape key.
Parameters
----------
debug : bool, optional
Show internal information about the key that was pressed. Default is False.
Returns
-------
key: str
A string indicating what was pressed.
"""
with keyboard.Events() as events:
for event in events:
if isinstance(event, keyboard.Events.Release):
if hasattr(event.key, 'char') and event.key.char in 'abcdefghijklmnopqrstuvwxyz':
return event.key.char.upper()
elif event.key == keyboard.Key.backspace:
return 'backspace'
elif event.key == keyboard.Key.enter:
return 'enter'
elif event.key == keyboard.Key.esc:
return 'esc'
if debug:
print(event.key)
def getversion():
"""Retrieve the current git hash to use as a 'version' number."""
return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip()
def readwords(file, header=True, sep='\n'):
"""Return a list of uppercase words from file.
Parameters
----------
file : str
The file to read from.
header : bool, optional
Does the file contain a single-line header? Default is True.
sep : str, optional
Separator between words in the file. Default is '\\n'.
Returns
-------
words: list
A list of uppercase words.
"""
f = open(file, 'r')
if header: # does the file contain a header (e.g. number of words listed)
n = int(f.readline())
words = f.read().upper().split(sep) # make list of words
f.close()
return words
def removeletters(alphabet, guess, feedback):
"""Remove letters from the known alphabet using feedback about a guessed word.
Parameters
----------
alphabet : str
String of letters that are currently valid.
guess : str
Word that was guessed.
feedback: list
A list of integers, one per letter in the guessed word, to indicate if the letter
is correct (2), almost correct (1), or incorrect (0).
Returns
-------
leftovers: str
String of remaining letters after discarding those guessed with feedback=0.
"""
used = set([letter for letter, exists in zip(guess, feedback) if exists == 0])
leftovers = "".join([letter for letter in alphabet if letter not in used])
return leftovers
def test():
"""Test utility functions for errors."""
print('\nREADWORDS')
print('---------')
words = readwords('secretwords5.txt')
print(*words, sep=' ')
print(f'Number of words: {len(words)}')
print('\nGETFEEDBACK')
print('-----------')
print(f'ABC --> XYZ = {getfeedback("ABC", "XYZ")}')
print(f'TEST --> TEST = {getfeedback("TEST", "TEST")}')
print(f'ADIEU --> DIALS = {getfeedback("ADIEU", "DIALS")}')
print(f'ROBOT --> BOUND = {getfeedback("ROBOT", "BOUND")}')
print('\nGETKEY')
print('Press any key...')
key = getkey()
print(key)
def updatestats(outcome, filename="stats.txt"):
"""Update statistics file based on the outcome of a game."""
# Try to read data from file
try:
with open(filename, "r") as f:
data = f.read().split('\n') # make list of strings, one per stat line
except IOError:
print(Fore.YELLOW + f'WARNING: Unable to track stats because {filename} does not exist.')
return 0
# Load stats into dictionary
stats = {}
for line in data:
if len(line) == 0:
continue
stat, value = line.split('=')
try:
stats[stat] = int(value)
except: # need something special for lists
stats[stat] = [int(i) for i in value.split(',')]
# Modify stats based on outcome
stats['played'] += 1
if outcome != 0:
stats['current streak'] += 1
if stats['current streak'] > stats['max streak']:
stats['max streak'] = stats['current streak']
stats['guess distribution'][outcome - 1] += 1
else:
stats['current streak'] = 0
stats['win percentage'] = int(sum(stats['guess distribution']) / stats['played'] * 100)
# Write new stats to file
with open(filename, "w") as f:
for key, value in stats.items():
if isinstance(value, list):
f.write(f'{key}={",".join([str(i) for i in value])}\n')
else:
f.write(f'{key}={value}\n')
if __name__ == "__main__":
test()