-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathgre.py
259 lines (236 loc) · 8.74 KB
/
gre.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
257
258
259
import json
import sys
import tty
import termios
import arrow
import random
import os
import eggshell
import requests
import operator
from xtermcolor import colorize
alphabet = 'abcdefghijklmnopqrstuvwxyz'
main_menu = """Select mode:
(1) All words, ranked
(2) All words, unranked
(3) Only one starting letter, ranked
(4) Only one starting letter, unranked
(5) From word list, ranked
(6) From word list, unranked
(7) All words, ranked, only choose worst 25%
(R)esults
re(L)oad dictionary
Toggle (W)ordsAPI
(Q)uit
> """
quiz_menu = """
Quiz mode options:
(M)ain menu
(Q)uit
(S)peak word
Toggle (W)ordsAPI
(H)elp (or ?)
"""
words_api_enabled = False
words_api_token = os.getenv('WORDS_API_TOKEN')
def words_api_definitions(word):
r = requests.get('https://www.wordsapi.com/words/{word}?accessToken={token}'.format(
word=word,
token=words_api_token
))
j = json.loads(r.text)
definitions = j['results']
print('\n{}'.format(colorize('WordsAPI Definitions:', ansi=9)))
for i, definition in enumerate(definitions):
print(' {}. ({}) {}'.format(i+1, colorize(definition['partOfSpeech'] if 'partOfSpeech' in definition else 'N/A', ansi=6), definition['definition']))
print('')
def getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
print(ch)
return ch
def get_words():
words = {}
with open('words.txt') as fp:
for line in fp.read().split('\n'):
line = line.strip()
if len(line) > 0:
(word, definition) = line.split(' - ')
words[word.lower().strip()] = definition.strip()
return words
def prompt(question, choices, incorrect=None):
while True:
sys.stdout.write(question)
sys.stdout.flush()
ch = getch().lower()
if ch in choices or ord(ch) in choices:
return ch
if incorrect is not None:
print(incorrect)
def parse_entry(entry):
date = arrow.get(entry[:19], 'YYYY-MM-DD HH:mm:ss')
parts = entry[20:].split(',')
word = parts[0].replace('word=', '')
correct = True if parts[1].replace('correct=', '') == 'y' else False
return (date, word, correct)
def get_word_accuracy(words):
accuracy = {}
for word in words:
accuracy[word] = []
with open('results.txt') as fp:
for line in fp.read().split('\n'):
if len(line) == 0: continue
(date, word, correct) = parse_entry(line)
if word in accuracy:
accuracy[word].append(correct)
for word, lst in accuracy.items():
accuracy[word] = round(sum(lst)/len(lst) * 100) if len(lst) else 0
return accuracy
def results():
with open('results.txt') as fp:
entries = list(map(parse_entry, filter(lambda x: len(x), fp.read().split('\n'))))
count = {
'correct': 0,
'incorrect': 0,
'total': len(entries)
}
cards_by_date = {}
for (date, word, correct) in entries:
if correct: count['correct'] += 1
if not correct: count['incorrect'] += 1
if date.format('YYYY-MM-DD') not in cards_by_date:
cards_by_date[date.format('YYYY-MM-DD')] = 1
else:
cards_by_date[date.format('YYYY-MM-DD')] += 1
print('Total flash cards: {}'.format(count['total']))
print('Correct: {}'.format(count['correct']))
print('Incorrect: {}'.format(count['incorrect']))
print('Flash cards today: {}'.format(cards_by_date[arrow.now('US/Eastern').format('YYYY-MM-DD')]))
def get_quiz_words(dictionary, number):
if number != -1:
all_words = list(dictionary.keys())
words = []
random.seed()
for i in range(number):
word = random.choice(all_words)
all_words.remove(word)
words.append(word)
return words
else:
return list(dictionary.keys())
def quiz(dictionary, number, ranked=False):
global words_api_enabled
quiz_words = get_quiz_words(dictionary, number)
quiz_words_accuracy = get_word_accuracy(quiz_words)
quiz_words_iteration = []
if len(quiz_words) == 0:
sys.exit('No words to quiz')
print(quiz_menu)
print(colorize('Set contains {} words:'.format(len(quiz_words)), ansi=4))
print(', '.join(['{} ({}%)'.format(word, quiz_words_accuracy[word]) for word in quiz_words]))
while True:
if len(quiz_words_iteration) == 0:
quiz_words_iteration = list(quiz_words) # Copy
print(colorize("Reloading words", ansi=4))
word = random.choice(quiz_words_iteration)
quiz_words_iteration.remove(word)
while True:
number = len(quiz_words) - len(quiz_words_iteration)
question = "{}. {} [enter/q/m/h/s/w] ".format(number, colorize(word, ansi=1))
ch = prompt(question, ['q', 'm', 'h', 's', 'w', 13])
if ch == 'q':
sys.exit(0)
elif ch == 'h':
print(quiz_menu)
continue
elif ch == 'm':
return
elif ch == 's':
(rc, out, err) = eggshell.run('say {}'.format(word))
continue
elif ch == 'w':
words_api_enabled = not words_api_enabled
print("WordsAPI Enabled: {}".format(words_api_enabled))
continue
elif ord(ch) == 13:
print(colorize(dictionary[word], ansi=2))
if words_api_enabled:
words_api_definitions(word)
break
if ranked:
correct = prompt("Correct? [y/n/s] ", ['y', 'n', 's'])
if correct != 's':
now = arrow.now('US/Eastern')
with open('results.txt', 'a') as fp:
fp.write('{} word={},correct={}\n'.format(now.format('YYYY-MM-DD HH:mm:ss'), word, correct))
print(json.dumps(words, indent=4))
print(ranked)
def menu():
while True:
words = get_words()
sys.stdout.write(main_menu)
sys.stdout.flush()
ch = getch().lower()
if ch in list('34'):
letter = prompt("Which letter? ", list(alphabet))
subset_words = {word: definition for word, definition in words.items() if word[0] == letter.lower()}
if ch in list('56'):
lists = [x for x in os.listdir('.') if x.endswith('.list')]
for i, word_list in enumerate(lists):
print('({}) {}'.format(i+1, word_list))
index = prompt("Which list? ", list(map(str, list(range(1, len(lists) + 1)))))
with open(lists[int(index) - 1]) as fp:
list_words = [x.lower().strip() for x in fp.read().split('\n') if len(x.strip()) > 0]
for word in list_words:
if word not in words:
print(colorize("{} is not in the dictionary".format(word), ansi=1))
subset_words = {word: definition for word, definition in words.items() if word in list_words}
if ch == '7':
accuracy = get_word_accuracy(words)
accuracy = sorted(accuracy.items(), key=operator.itemgetter(1))
accuracy = accuracy[:round(len(accuracy)/4)]
subset_words = {}
for word, percent in accuracy:
subset_words[word] = words[word]
if ch in list('1234567'):
number = input("How many words to quiz? [all] ").strip()
try:
number = int(number) if len(number) else -1
except ValueError:
print(colorize("Must be numeric", ansi=1))
continue
if ch == '1':
quiz(words, number, ranked=True)
elif ch == '2':
quiz(words, number, ranked=False)
elif ch == '3':
quiz(subset_words, number, ranked=True)
elif ch == '4':
quiz(subset_words, number, ranked=False)
elif ch == '5':
quiz(subset_words, number, ranked=True)
elif ch == '6':
quiz(subset_words, number, ranked=False)
elif ch == '7':
quiz(subset_words, number, ranked=True)
elif ch == 'r':
results()
prompt('[enter]', [13])
elif ch == 'l':
words = get_words()
print(colorize('Dictionary reloaded.', ansi=4))
elif ch == 'w':
global words_api_enabled, words_api_token
words_api_enabled = not words_api_enabled
print(colorize('WordsAPI {}'.format('Enabled' if words_api_enabled else 'Disabled'), ansi=4))
if not words_api_token and words_api_enabled:
words_api_token = input("WordsAPI token: ")
elif ch == 'q':
sys.exit(0)
if __name__ == '__main__':
menu()