"""
- wordle solver
"""
import random
import time
import json
def read_words_alpha(word_len: int = 5, excluded_words: list = []) -> list:
"""
- word_len 길이에 속하고, excluded_words에 속하지 않는 단어만 리턴
"""
return_lst = list()
with open("words_alpha.txt", "r") as f:
for i, each_line in enumerate(f.readlines()):
word = each_line.strip()
if (len(word) == word_len) and (word not in excluded_words):
return_lst.append(word)
return return_lst
def find_words_excluding_char(
total_words: list, ex_char: str = "", limit_n: int = 5):
"""
- ex_char를 보유하지 않은 단어들만 출력
"""
word_print_count = 0
return_w_lst = list()
for each_word in total_words:
if len(set(each_word).intersection(set(ex_char))) == 0:
if len(set(each_word)) == 5:
print(each_word)
return_w_lst.append(each_word)
word_print_count += 1
if word_print_count == limit_n:
break
return return_w_lst
def current_state_of_word(target_word: str, guess_word: str) -> list:
"""
target_word와 guess_word를 비교하여 정보를 리턴
- 2: char, index equal
- 1: char equal
- 0: None
"""
return_lst = list()
for ca, cb in zip(target_word, guess_word):
if ca == cb:
return_lst.append(2)
else:
if cb in set(target_word):
return_lst.append(1)
else:
return_lst.append(0)
return return_lst
class WordleSolver:
def __init__(self):
self.total_words = read_words_alpha(5, [])
self.exclude_char = set()
self.candidate_char = set()
self.index_exclude_dict = {
i: set() for i in range(0, 5)
}
self.target_word = ["_" for i in range(0, 5)]
self.excluded_words = []
def refresh(self):
self.exclude_char = set()
self.candidate_char = set()
self.index_exclude_dict = {
i: set() for i in range(0, 5)
}
self.target_word = ["_" for i in range(0, 5)]
self.excluded_words = []
def set_constant(self, exclude_c=1.0, index_c=0.2, correct_c=5.0):
"""
- word를 검색할 때 획득할 수 있는 정보들에 대한 weight
"""
self.EXCLUDE_C = exclude_c
self.INDEX_C = index_c
self.CORRECT_C = correct_c
def print_self(self):
print(f"exclude_char: {self.exclude_char}")
print(f"candidate_char: {self.candidate_char}")
print(f"index_exclude_dict: {self.index_exclude_dict}")
def scoring_word(self, word: str) -> int:
"""
- 각 정보에 대한 weight를 사용하여 단어의 정보획득량을 계산
"""
return_score = 0.0
# EXCLUDE_C
before_exclude = len(self.exclude_char)
after__exclude = len(self.exclude_char.union(set(word)))
exclude_score = (after__exclude - before_exclude) * self.EXCLUDE_C
exclude_score = exclude_score / ((27 - before_exclude) / 27)
return_score += exclude_score
# INDEX_C
index_count = 0
for i, c in enumerate(word):
if c != self.target_word[i]:
if c in self.candidate_char:
if c not in self.index_exclude_dict[i]:
index_count += 1
index_score = index_count * self.INDEX_C
index_score *= len(self.candidate_char)
return_score += index_score
# CORRECT_C
correct_count = 0
for i, c in enumerate(self.target_word):
if word[i] == c:
correct_count += 1
return_score += correct_count * self.CORRECT_C
return return_score
def updating_info(self, guess_word: str, feedback: list):
"""
- feedback: guess list
"""
self.excluded_words.append(guess_word)
for i, (c, f) in enumerate(zip(guess_word, feedback)):
if f == 2:
self.candidate_char.update(c)
self.target_word[i] = c
elif f == 1:
self.candidate_char.update(c)
self.index_exclude_dict[i].update(c)
elif f == 0:
self.exclude_char.update(c)
for i in range(0, 5):
self.index_exclude_dict[i].update(c)
else:
print("ERROR")
def guessing_word(self) -> str:
"""
- 전체 단어 pool중에서 가장 정보 획득량(score)이 높은 단어를 리턴
"""
random_index = random.randint(0, len(self.total_words))
guess_word = self.total_words[random_index]
guess_score = self.scoring_word(guess_word)
for curr_word in self.total_words:
curr_score = self.scoring_word(curr_word)
if curr_word not in self.excluded_words:
if guess_score < curr_score:
guess_word = curr_word
guess_score = curr_score
else:
continue
if False:
print(f"{guess_word}, {guess_score:7.3f}")
return guess_word
if __name__ == "__main__":
wordle_solver = WordleSolver()
total_words = read_words_alpha()
file_name = f"log/result.json"
wf = open(file_name, "w")
result_list = list()
"""
- exc_c, idx_c, cor_c 에 대한 Grid Search 를 진행하여
평균적인 trial 수를 json파일에 저장한다.
"""
problem_n = 50
param_range = [i * 0.1 for i in range(1, 11)]
for exc_c in param_range:
for idx_c in param_range:
for cor_c in param_range:
start_time = time.time()
param_and_result_dict = dict()
param_and_result_dict['param'] = {
'exc_c': exc_c, 'idx_c': idx_c, 'cor_c': cor_c
}
wordle_solver.set_constant(exc_c, idx_c, cor_c)
log = f"== EXC_C: {exc_c:6.2f}, IDX_C: {idx_c:6.2f}, COR_C: {cor_c: 6.2f} :::: "
print(log, end="")
trial_lst = list()
for each_problem in range(0, problem_n):
random.seed(each_problem)
wordle_solver.refresh()
target_index = random.randint(0, len(total_words))
target_word = total_words[target_index]
# print(target_word)
trial_to_success = 0
# auto input
for each_trial in range(0, 100):
trial_to_success += 1
# print(f"== Trial {each_trial: 2d} :: ", end="")
predicted_word = wordle_solver.guessing_word()
feedback = current_state_of_word(target_word, predicted_word)
wordle_solver.updating_info(predicted_word, feedback)
if predicted_word == target_word:
break
if False:
print(f"== Problem: {each_problem:2d} :: {target_word} :: ", end="")
print(f"Trial to success: {trial_to_success:3d}")
trial_lst.append(trial_to_success)
avg_trial = sum(trial_lst) / problem_n
param_and_result_dict['result'] = avg_trial
result_list.append(param_and_result_dict)
log = f"Avg. Trial: {avg_trial: 6.2f} "
print(log, end="")
print(f"== {time.time() - start_time:.2f} seconds")
json.dump(result_list, wf, indent=4)
# find_words_excluding_char(total_words, "fghtoceansurlypowerkemps", limit_n=10)
댓글남기기