-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshortlist.py
189 lines (168 loc) · 8.52 KB
/
shortlist.py
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
'''shortlist class'''
import numpy as np
import tools as tl
class Shortlist:
"""Class representing an updatable shortlist of guesses."""
def __init__(self):
# Initial untouched values
self.words = []
self.words_splitted = []
self.scores = []
# Temporary variables, updatable
self.temp_words = []
self.temp_words_splitted = []
self.temp_scores = []
# Knowledge from Wordle hints, dictionaries (letter, list of places).
self.temp_grey_letters = {}
self.temp_green_letters = {}
self.temp_yellow_letters = {}
def reset_all_temp(self):
'''None ---> None.
Resets all temp_ self.variables to their value before starting guesses.'''
self.temp_grey_letters = {}
self.temp_green_letters = {}
self.temp_yellow_letters = {}
self.temp_words = self.words
self.temp_words_splitted = self.words_splitted
self.temp_scores = self.scores
def best_guess(self, print_ = False):
''' None ---> None.
Returns the word with the best score in the temp_words shortlist.
Prints the result if print_ = True.'''
if len(self.temp_words)>0:
temp = self.temp_words[0]
if print_:
print('Best guess :',temp)
return temp
def print_top(self):
''' None ---> None.
Prints the 9 words with the best scores in the temp_words shortlist.'''
print('----------------------------------')
print('| Suggestions | Score | Rank |')
print('----------------------------------')
for i in range(min(9,len(self.temp_words))):
print('| '+self.temp_words[i]+ ' | '+'{:.4f}'.format(self.temp_scores[i])+' | '+str(i+1)+' |' )
def read_1st_guess(self):
'''None ---> None.
Reads words_ranked.txt's initial scoring and assigns it to initial variables.'''
tab= np.loadtxt('words_ranked.txt',dtype='str')
self.words = tab[:,0]
self.temp_words = self.words
self.scores = tab[:,1].astype(float)
self.temp_scores = self.scores
self.words_splitted = tl.split_in_array(self.words)
self.temp_words_splitted = self.words_splitted
def intersection_grey(self):
'''None ---> None.
Updates the shortlist in temp_words from temp_grey_letters.
Words with the grey letters are removed from the shortlist.'''
# Initialize selection boolean array
Truth = 0
for letter in self.temp_grey_letters:
temp = (self.temp_words_splitted == letter)
# If the letter is also a green or yellow letter
if letter in self.temp_green_letters:
# We don't study columns where there is a detected green.
temp[:,self.temp_green_letters[letter]] *= False
if letter in self.temp_yellow_letters:
# We study columns where there is a detected yellow but in intersection_yellow.
return()
Truth += temp
Or = np.sum(Truth,axis = 1) # number of found grey letters per word
Truth = (Or == 0) # keep only those without any
# Update temp arrays by using numpy selection
self.temp_words = self.temp_words[Truth]
self.temp_words_splitted = self.temp_words_splitted[Truth]
self.temp_scores = self.temp_scores[Truth]
def intersection_green(self):
'''None ---> None.
Updates the shortlist in temp_words from temp_green_letters.
Only words with the green letters at the right spots are kept in the shortlist.'''
# Initialize selection boolean array
Truth = 1
# Each word of the shortlist has to have the green letters at the right places
# No need for extra considerations if doublons
for letter, positions in self.temp_green_letters.items():
for pos in positions:
Truth = np.logical_and(Truth, self.temp_words_splitted[:,pos] == letter)
# Update temp arrays by using numpy selection
self.temp_words = self.temp_words[Truth]
self.temp_words_splitted = self.temp_words_splitted[Truth]
self.temp_scores = self.temp_scores[Truth]
def intersection_yellow(self):
'''None ---> None.
Updates the shortlist in temp_words from temp_yellow_letters.
Only words with the yellow letters at the right spots are kept in the shortlist.'''
# Initialize selection boolean array
Truth = 1
for letter in self.temp_yellow_letters:
# If the letter is yellow and has a doublon, the selection array must not use those columns for selection
# cols = indices excluding columns with this letter
# cols2 = indices excluding columns with this letter as green or grey only
if letter in self.temp_green_letters:
cols = list(set(range(0,5))-set(self.temp_yellow_letters[letter])-set(self.temp_green_letters[letter]))
cols2 = list(set(self.temp_yellow_letters[letter])-set(self.temp_green_letters[letter]))
elif letter in self.temp_grey_letters:
cols = list(set(range(0,5))-set(self.temp_yellow_letters[letter])-set(self.temp_grey_letters[letter]))
cols2 = list(set(self.temp_yellow_letters[letter])-set(self.temp_grey_letters[letter]))
else:
cols = list(set(range(0,5))-set(self.temp_yellow_letters[letter]))
cols2 = self.temp_yellow_letters[letter]
# We select words where columns without the identified doublon and yellow column have the yellow letter
auxTruth = (self.temp_words_splitted[:,cols] == letter)
Or = np.sum(auxTruth, axis = 1)
auxTruth = (Or > 0 )
# We select words where the yellow letter is not at the input spot
auxTruth2 = (self.temp_words_splitted[:,cols2]==letter)
Or2 = np.sum(auxTruth2, axis = 1)
auxTruth2 = (Or2 == 0)
# We intersect the two boolean array
Truth = np.logical_and(Truth, auxTruth)
Truth = np.logical_and(Truth, auxTruth2)
# Update temp arrays by using numpy selection
self.temp_words = self.temp_words[Truth]
self.temp_words_splitted = self.temp_words_splitted[Truth]
self.temp_scores = self.temp_scores[Truth]
def clear_temp_letters(self):
'''None ---> None.
Clears temporary letter variables.'''
self.temp_grey_letters = {}
self.temp_green_letters = {}
self.temp_yellow_letters = {}
def new_temp(self, word, output):
'''(str,str)--->None.
From a given word and its Wordle output, assigns letters to their dictionnary (g,y or -).'''
self.clear_temp_letters()
for i in range(5):
if output[i]=='-':
if word[i] in self.temp_grey_letters:
self.temp_grey_letters[word[i]].append(i)
else:
self.temp_grey_letters[word[i]]= [i]
elif output[i]=='g':
if word[i] in self.temp_green_letters:
self.temp_green_letters[word[i]].append(i)
else:
self.temp_green_letters[word[i]]= [i]
else:
if word[i] in self.temp_yellow_letters:
self.temp_yellow_letters[word[i]].append(i)
else:
self.temp_yellow_letters[word[i]]= [i]
def shorting_from_output(self,word,output):
'''(str,str)--->None.
From a given word and its Wordle output, completes the update of the shortlist.'''
self.new_temp(word,output)
# Green, grey, yellow order is important as explained in interesection_ functions
if self.temp_green_letters != {}:
self.intersection_green()
if self.temp_grey_letters != {}:
self.intersection_grey()
if self.temp_yellow_letters != {}:
self.intersection_yellow()
def update_scoring(self):
'''None ---> None.
Updates the scores with a scoring on the shortlist rather than on the full dictionnary.
See tools.rank_words.'''
self.temp_words, self.temp_words_splitted, self.temp_scores = tl.rank_words(self.temp_words,self.temp_words_splitted)
'''Yoann Launay, University of Cambridge, 12/22.'''