Spaces:
Runtime error
Runtime error
Reshinth Adithyan
commited on
Commit
·
c5f913a
1
Parent(s):
314fe3a
Initial Commit
Browse files- app.py +17 -0
- requirements.txt +3 -0
- src/__init__.py +0 -0
- src/agent.py +34 -0
- src/game.py +99 -0
- src/metrics.py +45 -0
- src/utils.py +43 -0
app.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import pandas as pd
|
3 |
+
from src.game import Wordle
|
4 |
+
|
5 |
+
|
6 |
+
st.title("WORDLE")
|
7 |
+
|
8 |
+
|
9 |
+
with st.form("Wordle"):
|
10 |
+
button = st.form_submit_button("Play")
|
11 |
+
box = st.selectbox("Select the trial level :",["6","100"])
|
12 |
+
if button:
|
13 |
+
wordle = Wordle(int(box))
|
14 |
+
chosen_word,game_diction = wordle.play()
|
15 |
+
st.dataframe(pd.DataFrame.from_dict(game_diction))
|
16 |
+
st.write(f"The actual word is : {wordle.wordle}")
|
17 |
+
st.write(f"It took {len(game_diction['step_no'])} random search steps to find it")
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
nltk==3.6.2
|
2 |
+
pandas==1.3.0
|
3 |
+
streamlit==0.84.0
|
src/__init__.py
ADDED
File without changes
|
src/agent.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
from src.metrics import get_word_list
|
3 |
+
|
4 |
+
|
5 |
+
class Cerebrum:
|
6 |
+
def __init__(self,vowel_knowledge:int=2) -> None:
|
7 |
+
self.word_list = get_word_list()
|
8 |
+
self.init_word_list = self.get_vowelled_word_list(vowel_knowledge)
|
9 |
+
|
10 |
+
def get_vowelled_word_list(self,nos_vowels:int)->list:
|
11 |
+
"""
|
12 |
+
Returns a list of words with the given number of vowels.
|
13 |
+
"""
|
14 |
+
vowels = set(["a","e","i","o","u"])
|
15 |
+
tmp_list = []
|
16 |
+
for word in self.word_list:
|
17 |
+
ind_word_set = set(list(word))
|
18 |
+
if len(list(vowels.intersection(ind_word_set))) > nos_vowels:
|
19 |
+
tmp_list.append(word)
|
20 |
+
return tmp_list
|
21 |
+
|
22 |
+
def random_first_choice(self)->str:
|
23 |
+
return random.choice(self.init_word_list)
|
24 |
+
|
25 |
+
def random_n_choice(self,hash_output:list[list])->str:
|
26 |
+
if len(hash_output) == 1:
|
27 |
+
return random.choice(hash_output[0])
|
28 |
+
else:
|
29 |
+
sub_hash = random.choice(hash_output)
|
30 |
+
return random.choice(sub_hash)
|
31 |
+
|
32 |
+
if __name__ == "__main__":
|
33 |
+
cerebrum = Cerebrum()
|
34 |
+
print(len(cerebrum.init_word_list))
|
src/game.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from itertools import count
|
2 |
+
from src.metrics import get_word_list,Metrics
|
3 |
+
import logging
|
4 |
+
import random
|
5 |
+
from src.utils import WordHash
|
6 |
+
from src.agent import Cerebrum
|
7 |
+
|
8 |
+
|
9 |
+
logging.basicConfig(level=logging.INFO)
|
10 |
+
logger = logging.getLogger(__name__)
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
class Wordle:
|
17 |
+
def __init__(self,steps_to_be_tried=6) -> None:
|
18 |
+
self.steps = steps_to_be_tried
|
19 |
+
self.word_list = get_word_list()
|
20 |
+
self.letter_list = list("abcdefghijklmnopqrstuvwxyz")
|
21 |
+
self.wordle = random.choice(self.word_list)
|
22 |
+
self.sixth_sense = Cerebrum()
|
23 |
+
self.hash = WordHash()
|
24 |
+
logger.info(f"The Word to be found is {self.wordle}")
|
25 |
+
self.evaluator = Metrics()
|
26 |
+
|
27 |
+
def deduct_vocab(self,score_dict:dict):
|
28 |
+
"""
|
29 |
+
Returns True if the word is present in the vocab.
|
30 |
+
"""
|
31 |
+
for letter in score_dict:
|
32 |
+
if score_dict[letter] == 0:
|
33 |
+
if letter in self.letter_list:
|
34 |
+
del self.letter_list[self.letter_list.index(letter)]
|
35 |
+
|
36 |
+
def preprocess_pos_word(self,pos_score_dict:dict):
|
37 |
+
"""
|
38 |
+
Flag : G -> Sure, Y -> Probable
|
39 |
+
"""
|
40 |
+
pos_slice_list_g = []
|
41 |
+
pos_slice_list_y = []
|
42 |
+
for ind in range(len(pos_score_dict)):
|
43 |
+
letter = list(pos_score_dict.keys())[ind]
|
44 |
+
score = pos_score_dict[letter]
|
45 |
+
if score == 2:
|
46 |
+
pos_slice_list_g.append([ind,letter,"G"])
|
47 |
+
if score == 1:
|
48 |
+
for possible_index in range(5):
|
49 |
+
if possible_index != ind:
|
50 |
+
pos_slice_list_y.append([possible_index,letter,"Y"])
|
51 |
+
|
52 |
+
return pos_slice_list_g + pos_slice_list_y
|
53 |
+
|
54 |
+
def single_step(self,pred_word:str):
|
55 |
+
pos_score_dict = self.evaluator(self.wordle,pred_word)
|
56 |
+
self.deduct_vocab(pos_score_dict)
|
57 |
+
|
58 |
+
return pos_score_dict
|
59 |
+
|
60 |
+
def play(self)->str:
|
61 |
+
game_diction = {"step_no":[],"chosen_word":[],"status":[]}
|
62 |
+
for step in range(self.steps):
|
63 |
+
logger.info(f"Step {step}")
|
64 |
+
if step == 0:
|
65 |
+
chosen = self.sixth_sense.random_first_choice()
|
66 |
+
logger.info(f"Chosen word is {chosen}")
|
67 |
+
pos_score_dict = self.single_step(chosen)
|
68 |
+
slice_pos_list = self.hash.slice_pos(self.preprocess_pos_word(pos_score_dict))
|
69 |
+
game_diction["chosen_word"].append(chosen)
|
70 |
+
game_diction["step_no"].append(step)
|
71 |
+
game_diction["status"].append("CONTINUE")
|
72 |
+
else:
|
73 |
+
|
74 |
+
chosen = self.sixth_sense.random_n_choice(slice_pos_list)
|
75 |
+
logger.info(f"Chosen word is {chosen}")
|
76 |
+
pos_score_dict = self.single_step(chosen)
|
77 |
+
slice_pos_list = self.hash.slice_pos(self.preprocess_pos_word(pos_score_dict))
|
78 |
+
game_diction["chosen_word"].append(chosen)
|
79 |
+
game_diction["step_no"].append(step)
|
80 |
+
if chosen != self.wordle:
|
81 |
+
game_diction["status"].append("CONTINUE")
|
82 |
+
elif chosen == self.wordle:
|
83 |
+
game_diction["status"].append("IMPRESSIVE")
|
84 |
+
logger.info(f"The word is {chosen}")
|
85 |
+
break
|
86 |
+
return chosen,game_diction
|
87 |
+
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
|
92 |
+
if __name__ == "__main__":
|
93 |
+
pass
|
94 |
+
# pos_score_dict = wordle_module.single_step("cants")
|
95 |
+
# print(pos_score_dict)
|
96 |
+
# slice_pos_list = wordle_module.preprocess_pos_word(pos_score_dict)
|
97 |
+
# print(slice_pos_list)
|
98 |
+
# hash = WordHash()
|
99 |
+
# print(hash.slice_pos(slice_pos_list))
|
src/metrics.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from nltk import corpus
|
2 |
+
|
3 |
+
|
4 |
+
def get_word_list()->list:
|
5 |
+
|
6 |
+
return [ i for i in corpus.words.words() if len(i) == 5]
|
7 |
+
|
8 |
+
|
9 |
+
|
10 |
+
class Metrics:
|
11 |
+
def __init__(self):
|
12 |
+
self.score_dict = {
|
13 |
+
"not_present" : 0,
|
14 |
+
"wrong_pos" : 1,
|
15 |
+
"right" : 2
|
16 |
+
}
|
17 |
+
self.word_list = get_word_list()
|
18 |
+
|
19 |
+
def check_word(self,ref_word:str)->bool:
|
20 |
+
"""
|
21 |
+
Returns True/False based on it's presence.
|
22 |
+
"""
|
23 |
+
return ref_word in self.word_list
|
24 |
+
|
25 |
+
def __call__(self,ref_word:str,pred_word:str)->dict:
|
26 |
+
"""
|
27 |
+
Returns the position level score based on the comparison
|
28 |
+
"""
|
29 |
+
score_dict = {}
|
30 |
+
|
31 |
+
for letter_idx in range(5):
|
32 |
+
pred_letter = pred_word[letter_idx]
|
33 |
+
if pred_letter == ref_word[letter_idx]:
|
34 |
+
score_dict[pred_letter] = 2
|
35 |
+
elif pred_letter in ref_word:
|
36 |
+
score_dict[pred_letter] = 1
|
37 |
+
else:
|
38 |
+
score_dict[pred_letter] = 0
|
39 |
+
|
40 |
+
return score_dict
|
41 |
+
|
42 |
+
if __name__ == "__main__":
|
43 |
+
print(len(get_word_list()))
|
44 |
+
metric = Metrics()
|
45 |
+
print(metric("apple","aplep"))
|
src/utils.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from itertools import count
|
2 |
+
from src.metrics import get_word_list,Metrics
|
3 |
+
|
4 |
+
import logging
|
5 |
+
import random
|
6 |
+
logging.basicConfig(level=logging.INFO)
|
7 |
+
logger = logging.getLogger(__name__)
|
8 |
+
|
9 |
+
|
10 |
+
|
11 |
+
class WordHash:
|
12 |
+
def __init__(self) -> None:
|
13 |
+
self.word_list = get_word_list()
|
14 |
+
|
15 |
+
def slice_pos(self,pos_letter_pair_list:list)->list:
|
16 |
+
counter = 0
|
17 |
+
tmp = []
|
18 |
+
tmp_super_list = []
|
19 |
+
for pos_letter_pair in pos_letter_pair_list:
|
20 |
+
pos,letter,flag = pos_letter_pair[0],pos_letter_pair[1],pos_letter_pair[2]
|
21 |
+
if flag == "G":
|
22 |
+
if counter == 0:
|
23 |
+
for word in self.word_list:
|
24 |
+
if word[pos] == letter:
|
25 |
+
tmp.append(word)
|
26 |
+
else:
|
27 |
+
tmp = [word for word in tmp if word[pos] == letter]
|
28 |
+
counter = counter + 1
|
29 |
+
else:
|
30 |
+
tmp_super_list.append(tmp)
|
31 |
+
if counter == 0:
|
32 |
+
for word in self.word_list:
|
33 |
+
if word[pos] == letter:
|
34 |
+
tmp_super_list[-1].append(word)
|
35 |
+
else:
|
36 |
+
tmp_super_list[-1] = [word for word in tmp_super_list[-1] if word[pos] == letter]
|
37 |
+
counter = counter + 1
|
38 |
+
if len(tmp_super_list) != 0:
|
39 |
+
return [ i for i in tmp_super_list if len(i) > 0]
|
40 |
+
elif len(tmp) != 0 and len(tmp_super_list) == 0:
|
41 |
+
return [tmp]
|
42 |
+
else:
|
43 |
+
return [self.word_list]
|