-
Notifications
You must be signed in to change notification settings - Fork 0
/
scrabble.py
133 lines (114 loc) · 5.06 KB
/
scrabble.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
import itertools
from collections import defaultdict
import math
# Dictionary of the number of each tile in a bag of Scrabble tiles. Blanks = ?
frequencies = {"E": 12,
"A": 9, "I": 9,
"O": 8,
"N": 6, "R": 6, "T": 6,
"L": 4, "S": 4, "U": 4, "D": 4,
"G": 3,
"?": 2, "B": 2, "C": 2, "M": 2, "P": 2, "F": 2, "H": 2, "V": 2, "W": 2, "Y": 2,
"K": 1, "J": 1, "X": 1, "Q": 1, "Z": 1}
def is_valid(word):
with open('NSWL2020.txt') as f:
found = False
for line in f:
words = line.split()
if words[0] == word:
found = True
return True, line
if not found:
return False
# Replaces a letter at a specific index of the word with "?" (representing a blank tile)
def replace_with_blank(word, index, replacement):
return word[:index] + replacement + word[index+1:]
# Returns a list of each variation of the word using a single blank tile
def single_blanks(word):
single_cases = [replace_with_blank(word, idx, "?") for idx in range(len(word))]
# It is necessary to sort each variation of the word to account for words with duplicate letters and create a set
sorted_single = [''.join(sorted(ele)) for ele in single_cases]
return list(set(sorted_single))
# Returns a list of each variation of the word using two blank tiles
def double_blanks(word):
double_cases = []
for idx1, idx2 in itertools.combinations(range(len(word)), 2):
first_blank = replace_with_blank(word, idx1, "?")
second_blank = replace_with_blank(first_blank, idx2, "?")
double_cases.append(second_blank)
sorted_double = [''.join(sorted(ele)) for ele in double_cases]
return list(set(sorted_double))
# Returns the combination of both the single_blanks and double_blanks lists + the word itself
def all_blanks(word):
return list(set([word] + single_blanks(word) + double_blanks(word)))
# Cases will be the result of all_blanks, which is a list of all possible variations of the word, including blanks
# Only works for 7-letter words currently
def probability(cases):
numerators = []
for case in cases:
numerator = 1
# The denominator will always be C(100, 7)
denominator = 16007560800
# Count of the characters in each case
char_count = defaultdict(int)
char_combinations = []
for character in case:
char_count[character] += 1
# Calculate the total combinations of each character count using n! / r! * (n - r)!
for key in char_count:
# n = the count of the character in the bag of tiles, r = the count of the character in the case
n = frequencies[key]
r = char_count[key]
num = math.factorial(n) / (math.factorial(r) * math.factorial(n - r))
char_combinations += [num]
# Add the result to the numerators list
for combination in char_combinations:
numerator = numerator * combination
numerators += [numerator]
total_numerators = sum(numerators)
total_probability = (total_numerators / denominator) * 100
return total_probability
# Function to create a ranked list of the probabilities of words of a certain length.
# Only works for 7-letter words currently
def probability_of_all(word_length, number_to_display):
prob_dict = {}
with open('NSWL2020.txt') as f:
for line in f:
words = line.split()
if len(words[0]) == word_length:
try:
prob_dict[words[0]] = probability(all_blanks(words[0]))
except ValueError:
pass
sorted_probabilities = dict(sorted(prob_dict.items(), key=lambda item: item[1], reverse=True))
for key, value in list(sorted_probabilities.items())[:number_to_display]:
print(key, value)
if __name__ == "__main__":
word_to_check = input("Word to check: ").upper()
probability_to_check = "".join(sorted(word_to_check))
if not is_valid(word_to_check):
print("This is not a valid Scrabble word.")
else:
print(is_valid(word_to_check)[1].strip())
print("Probability: " + str(probability(all_blanks(probability_to_check))))
while True:
probability_list = input("Would you like to see a list of the most probable 7-letter words? (Y or N)").upper()
if probability_list == "N":
break
if probability_list == "Y":
while True:
try:
list_length = int(input("List length: (between 10 and 1000)"))
except ValueError:
print("Please enter a valid integer")
continue
else:
if list_length < 10 or list_length > 1000:
print("Please enter a list length from 10 to 1000")
continue
else:
probability_of_all(7, list_length)
break
else:
print("Please type Y or N")
continue