-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathguesserentropy_old.py
156 lines (119 loc) · 6.39 KB
/
guesserentropy_old.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
# Author: Iason Chaimalas
# Date: 2 June 2022
from HashTableWordle import HashTableWordle # import class for hash table
from word_colour_pattern import int_to_ternary, read_list
from numpy import log2, random # log2 for entropy, random.randint for random nums
import json # for hash table read/write
import os
from tqdm import tqdm as ProgressBarLookup # to see the progress of the lookup creation
class Guesser(HashTableWordle):
""" Process to guess the optimal word to find the Wordle solution word """
def __init__(self, solution_words):
""" Constructor """
super().__init__() # inherit constructor of HashTableWordle
self.read_json('hashfile') # read hashfile.json into the hash_table attr of Guesser
# set up extra attr
self.guess_counter = 0 # how many guesses the bot has already made
self.current_guess = "" # current guess (initially empty) at guess_counter + 1 step
self.poss = solution_words
# the existing list of possible Wordle words generated by a
# previous call of this func for a different guessword
# --> initially all solution_words are possible true solutions
# entropy of a possible guess
def entropy(guessword):
"""
At any point in Wordle, there are poss possible solution words given a new guess
with its associated guessmap (base-10 int), where E is a subset of poss.
For any guessword, there are 3^5 possible guessmaps (0-242) as the solution word
is unknown. Each guessmap has a probability p of occuring given the guessword.
This p is found as the number of possibilities poss that fit the guessword over
all possibilities 12792.
Then, entropy I is the sum of -p*log(p) for all 243 possible guessmaps
"""
I = 0 # entropy - initial sum
for gm in range(3**5): # all guessmaps gm
for s in self.poss: # for solution words in list of possible solutions
poss_poss = 0 # possible solutions in list poss
#print(f"s = {s}")
key = (guessword, s)
#print(f"key = {key}, hashkey = {hash(key)}")
if self.search_words(key) == gm:
poss_poss += 1
# increment occurence of this gm for this given guessword
p = poss_poss / len(self.poss)
if p != 0: I += -p*log2(p) # entropy formula
return I # entropy of a given guessword over the list of possible solutions at
# that point in Wordle
# finds guess with max entropy and guesses it
def make_guess(self, allowed_words):
"""
Calculate the entropy I of all possible guesswords at each stage of Wordle
and thus select the guessword with the maximum entropy (gives most amount
of information to narrow down the possible solutions)
"""
Ig = [] # list of entropy I for all guesswords g
for g in allowed_words: # for all possible guesswords
Ig.append(self.entropy(g))
Ig_imax = Ig.index(max(Ig)) # the index of maximum entropy, imax, in Ig
self.current_guess = allowed_words[Ig_imax]
# thus the current guess is the word corresponding to max entropy
# i.e. the word that will give the most info on average
self.current_guess += 1 # increment as we have now made a guess
# narrows down possibilities for solution word given the resulting colourmap of
# the guessed word from func make_guess above
def possibilities(self, guessword, guessmap, solution_words):
"""
Inputs:
- guessword: current str guess
- guessmap: base-10 int representing the ternary list with
5 elements, each 2 (grey), 1 (yellow) or 0 (green) in value, which
is the colourpattern for the given guess
- solution_words: list of all str possible solution words
This func determines the possible correct Wordle words that fit the colour
pattern for the given guessword.
"""
if self.guess_counter == 0: # 1st guess -- 0 guesses already made
poss = solution_words # 1st guess so solution word has not been narrowed down
else:
guesstrue = self.search_value(guessmap) # list of tuples that fit this guessmap
poss_updated = []
for i in range(len(guesstrue)):
if guesstrue[i][0] == guessword:
poss_updated.append(guesstrue[i][1])
poss = poss_updated
#for i in poss:
# if self.search_words((guessword, i)) != guessmap:
# # look-up all possible pairs of the current guess and all possible solutions
# # in the hash table. If the colourmap for that pair does not fit the
# # guessmap of this word, then the ith solution word tested is not a possibility
# self.poss.remove(i) # remove this as a possible solution word
def main():
# initialise paths for allowed and solution words
txtpath = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "Words"
)
ALLOWED_WORDS_FILE = os.path.join(txtpath, "AllowedWords.txt")
SOLUTION_WORDS_FILE = os.path.join(txtpath, "SolutionWord.txt")
allowed_words = read_list(0)
solution_words = read_list(1)
# initialise Wordle Solver using Entropy
guesswordle = Guesser(solution_words)
# Choose a random solution word
randindex = random.randint(0, len(solution_words))
print(f"randindex = {randindex}")
randsol = solution_words[randindex]
print(f"randsol = {randsol}")
# solution word at randomly-chosen index in solution-words list
guessmap = 242 # initially 0 - all grey as we have no info
while guessmap != 0:
# while bot has not solved this Wordle yet
# i.e. the result of the bot's guess is not fully correct/green
guesswordle.make_guess(allowed_words)
guessx = guesswordle.current_guess
guessmap = guesswordle.search_words((guessx, randsol))
guesswordle.possibilities(guessx, guessmap, solution_words)
print(f"Current Guess: {guessx}")
print(f"Guessmap for this guess: {int_to_ternary(guessmap)}")
print(f"Wordle won in {guesswordle.current_guess} guesses!")
if __name__ == "__main__":
main()