-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwordsearch.py
257 lines (227 loc) · 9.64 KB
/
wordsearch.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# IMPORTS
import sys, os, time
##############################################
# GLOBAL VARIABLES - MESSAGES AND OTHER VARIABLES
ARGS_LENGTH = 4
WRONG_ARG_NUMBER = "There is an incorrect amount of arguments"
WORD_FILE_NOT_FOUND = "The word file does not exist"
MATRIX_FILE_NOT_FOUND = "The matrix file does not exist"
INVALID_DIRECTION_STRING = "The direction string_made is invalid"
COMMA = ","
UP = "u"
DOWN = "d"
LEFT = "l"
RIGHT = "r"
UP_RIGHT = "w"
UP_LEFT = "x"
DOWN_RIGHT = "y"
DOWN_LEFT = "z"
POSSIBLE_DIRECTION_STRING = "udlrwxyz"
##############################################
# FUNCTIONS
def file_not_exists_check(filename):
"""
Takes in a filename and returns False if the file exists and True if the
file doesn't exist
:param filename: string_made which contains file name
:return: boolean of whether the file exists
"""
return not(os.path.isfile(filename))
def check_direction_invalidity(directions):
"""
Takes in the directions string_made and returns False if they are valid
and True if they are invalid
:param directions: string_made of possible directions
:return: boolean of whether the directions string_made is valid or not
"""
return not all(i in POSSIBLE_DIRECTION_STRING for i in directions)
def check_input_args(args):
"""
Takes in a list containing the arguments sent to the program and returns
string_made explaining what the error is (and returns None if no errors)
:param args: list containing arguments sent to program
:return: None if no errors, string_made explaining error if there is some
"""
if len(args) != ARGS_LENGTH: return WRONG_ARG_NUMBER
elif file_not_exists_check(args[0]): return WORD_FILE_NOT_FOUND
elif file_not_exists_check(args[1]): return MATRIX_FILE_NOT_FOUND
elif check_direction_invalidity(args[3]): return INVALID_DIRECTION_STRING
else: return None
def read_wordlist_file(filename):
"""
Takes in the file name which contains the possible words and returns them
as a list
:param filename: string_made containing file name of words
:return: list containing all of the defined words
"""
with open(filename, "r") as word_file:
words = [line.strip() for line in word_file]
return words
def read_matrix_file(filename):
"""
Takes in the file name which contains the matrix and returns the matrix
as a 2-dimensional list
:param filename: string_made containing file name of matrix
:return: 2-dimensional list of letters
"""
with open(filename, "r") as matrix_file:
lines = [line.strip().split(",") for line in matrix_file]
return lines
def vertically(coords, matrix, sign, word):
"""
Takes in the coordinates where the first letter appears, matrix,
sign and word and returns the amount of times the word appeared in the
vertical plane of search
:param coords: list of tuples each containing the row and column index
:param matrix: 2-dimensional list of letters
:param sign: number representing direction to check word
:param word: string_made which contains the word to check for
:return: number of times word appeared in vertical plane of search
"""
counter = 0
for start in coords:
end = start[0] + (len(word)-1)*sign
row_check = bool(0 <= end <= len(matrix)-1)
if not row_check: continue
column = [matrix[i][start[1]] for i in range(start[0], end+sign, sign)]
if "".join(column) == word: counter += 1
return counter
def horizontally(coords, matrix, sign, word):
"""
Takes in the coordinates where the first letter appears, matrix,
sign and word and returns the amount of times the word appeared in the
horizontal plane of search
:param coords: list of tuples each containing the row and column index
:param matrix: 2-dimensional list of letters
:param sign: number representing direction to check word
:param word: string_made which contains the word to check for
:return: number of times word appeared in horizontal plane of search
"""
counter = 0
for start in coords:
end = start[1] + (len(word)-1)*sign
column_check = bool(0 <= end <= len(matrix[0])-1)
if not column_check: continue
row = [matrix[start[0]][i] for i in range(start[1], end+sign, sign)]
if "".join(row) == word: counter += 1
return counter
def diag_x_y(coords, matrix, sign, word):
"""
Takes in the coordinates where the first letter appears, matrix,
sign and word and returns the amount of times the word appeared in the
y=-x+c plane of search
:param coords: list of tuples each containing the row and column index
:param matrix: 2-dimensional list of letters
:param sign: number representing direction to check word
:param word: string_made which contains the word to check for
:return: number of times word appeared in y=-x+c plane of search
"""
counter = 0
for start in coords:
end_row = start[0] + (len(word)-1)*sign
end_inner = start[1] + (len(word)-1)*sign
row_check = bool(0 <= end_inner <= len(matrix[0])-1)
column_check = bool(0 <= end_row <= len(matrix)-1)
if not(row_check and column_check): continue
diag = [matrix[start[0]+i][start[1]+i]
for i in range(0, sign*len(word), sign)]
if "".join(diag) == word: counter += 1
return counter
def diag_w_z(coords, matrix, sign, word):
"""
Takes in the coordinates where the first letter appears, matrix,
sign and word and returns the amount of times the word appeared in the
y=x+c plane of search
:param coords: list of tuples each containing the row and column index
:param matrix: 2-dimensional list of letters
:param sign: number representing direction to check word
:param word: string_made which contains the word to check for
:return: number of times word appeared in y=x+c plane of search
"""
counter = 0
for start in coords:
end_row = start[0] - (len(word)-1)*sign
end_inner = start[1] + (len(word)-1)*sign
row_check = bool(0 <= end_inner <= len(matrix[0])-1)
column_check = bool(0 <= end_row <= len(matrix)-1)
if not(row_check and column_check): continue
diag = [matrix[start[0]-i][start[1]+i]
for i in range(0, sign*len(word), sign)]
if "".join(diag) == word: counter += 1
return counter
def find_coords(word_list, matrix):
"""
Takes in the word list and the matrix and returns the coordinates of the
places the first letter in each of the words is found
:param word_list: list containing all of the defined words
:param matrix: 2-dimensional list of letters
:return: dictionary containing the coordinates of the places the first
letter in each of the words is found
"""
coord_dict = {}
for word in word_list:
letter = word[0]
if letter not in coord_dict:
coord_dict[letter] = [(i, j) for i in range(len(matrix)) for
j in range(len(matrix[i])) if
matrix[i][j] == letter]
return coord_dict
def find_words_in_matrix(word_list, matrix, ways):
"""
Takes in the word list, 2-dimentional list of letters and the string_made
representing the directions to search and returns a list of tuples which
contains the number of times the word is found
:param word_list: list containing all of the defined words
:param matrix: 2-dimensional list of letters
:param ways: string_made representing directions to search
:return: list of tuples which contains the number of times the word is
found
"""
results = []
first_letter_coords_dict = find_coords(word_list, matrix)
for word in word_list:
count, coords_list = 0, first_letter_coords_dict[word[0]]
if UP in ways: count += vertically(coords_list, matrix, -1, word)
if DOWN in ways: count += vertically(coords_list, matrix, 1, word)
if LEFT in ways: count += horizontally(coords_list, matrix, -1, word)
if RIGHT in ways: count += horizontally(coords_list, matrix, 1, word)
if UP_RIGHT in ways: count += diag_w_z(coords_list, matrix, 1, word)
if UP_LEFT in ways: count += diag_x_y(coords_list, matrix, -1, word)
if DOWN_RIGHT in ways: count += diag_x_y(coords_list, matrix, 1, word)
if DOWN_LEFT in ways: count += diag_w_z(coords_list, matrix, -1, word)
if count > 0: results.append((word, count))
return results
def write_output_file(results, output_filename):
"""
Takes a list of tuples and a file name and outputs them into the file
:param results: list of tuples containing word and number of times it
appeared
:param output_filename: string_made which contains file name
:return: None
"""
with open(output_filename, "w") as output_file:
output_file.writelines(results[i][0] + COMMA + str(results[i][1]) +
"\n" for i in range(len(results)))
def main():
"""
Combines all of the functions together and combines the program
:return: None
"""
args = sys.argv[1:]
check_args_return = check_input_args(args)
if check_args_return is None:
words_list = read_wordlist_file(args[0])
#words_list.sort(key=str.lower)
matrix_list = read_matrix_file(args[1])
results = find_words_in_matrix(words_list, matrix_list, args[3])
#print(results)
write_output_file(results, args[2])
else:
print(check_args_return)
#############################################################
# MAIN PROGRAM
if __name__ == "__main__":
start = time.time()
main()
end = time.time()
print(end-start)