#! /usr/bin/env python from sys import argv argv = ['', 'vocab.tex'] from re import compile from Tkinter import Button,Radiobutton,Scale,Frame,Listbox,IntVar,Label,Scrollbar from random import choice,uniform from string import replace from math import exp from pickle import dump,load chop_item = compile(' *?\\\\item(?P.*)$') chop_section = compile(' *?\\\\section(?P.*)$') radio_text = ['German to English', 'English to German', 'random'] init_freq, total_freq = 5, 9 conv_from = ['\\\"A', '\\\"O', '\\\"U', '\\\"a', '\\\"o', '\\\"u', '\\\'e', '\\ss ', '\\ss', '\\dot ', '\\dot', '\\ldots ', '\\ldots', '\\\"', '\\ ', '\'\'', '``'] conv_to = [u'\xc4', u'\xd6', u'\xdc', u'\xe4', u'\xf6', u'\xfc', u'\xe9', u'\xdf', u'\xdf', u'\xb7', u'\xb7', u'\u2026', u'\u2026', u'\"', ' ', u'\u201c', u'\u201d'] class Querybutton(Frame): curdef, active_query, fresh_query, word_id = None, 0, 0, None def update_freq(self, freq): if self.curdef: buckets = self.master.buckets old = buckets[self.word_id[0]][self.curdef[2][0] - 1] new = buckets[self.word_id[0]][freq - 1] self.curdef[2][0] = freq old.remove(self.word_id[1]) new.append(self.word_id[1]) def update_query(self, id=None): if id or not self.active_query: if id: self.word_id = id self.curdef = dict[1][id[0]][id[1]] self.fresh_query = 0 elif len(self.master.chapter_box.chapter_list.curselection()): self.curdef, self.word_id = self.master.find_word() self.fresh_query = 1 self.master.history.clear_def() else: self.button['text'] = '[select chapters first!]' self.curdef = None return self.active_query = 1 self.button['text'] = self.curdef[0] + '\n\n' #self.button['width'] = max(30, len(self.curdef[0])) self.master.freq_scale.set_freq(self.curdef[2][0]) else: if self.fresh_query: self.master.history.add_word(self.word_id) self.button['text'] = self.curdef[0] + '\n\n' + self.curdef[1] #self.button['width'] = max(self['width'], len(self.curdef[1])) self.active_query = 0 def __init__(self, master): Frame.__init__(self,master) self.label = Label(self) self.label['text'] = 'Quiz button:' self.label.grid(column = 0, row = 0) self.button = Button(self) self.button['text'] = '[click to generate word]' self.button['width'] = 80 self.button['height'] = 4 self.button['command'] = self.update_query self.button.grid(column = 0, row = 1, sticky='ew') class HistoryBox(Frame): word_history = [] def add_word(self, word_id): self.word_history.append(word_id) defn = dict[1][word_id[0]][word_id[1]] self.listbox.insert('end', defn[0]) self.listbox.see('end') def clear_def(self): self.listbox.selection_clear(0, len(self.word_history)) def select_def(self, event): if self.listbox.curselection(): selected = int(self.listbox.curselection()[0]) self.master.query.update_query(self.word_history[selected]) def reset_list(self): self.listbox.delete(0, 'end') for word_id in self.word_history: self.listbox.insert('end', dict[1][word_id[0]][word_id[1]][0]) def __init__(self, master): Frame.__init__(self,master) self.label = Label(self) self.label['text'] = 'Previous words:' self.label.grid(row = 0, column = 0, columnspan = 2) self.listbox = Listbox(self) self.listbox['exportselection'] = 0 self.listbox['width'] = 36 self.listbox['height'] = 14 self.listbox.grid(row = 1, column = 0, sticky = 'nesw') self.yScroll = Scrollbar(self) self.yScroll['orient'] = 'vertical' self.yScroll['command'] = self.listbox.yview self.listbox['yscrollcommand'] = self.yScroll.set self.yScroll.grid(row = 1, column = 1, sticky = 'ns') for event in ['', '', '', '', '']: self.listbox.bind(event, self.select_def) class ChapterBox(Frame): def __init__(self,master): Frame.__init__(self,master) self.label = Label(self) self.label['text'] = 'Chapter selection:' self.label.grid(column = 0, row = 0) self.chapter_list = Listbox(self) self.chapter_list['selectmode'] = 'multiple' self.chapter_list['width'] = 44 self.chapter_list['height'] = 12 self.chapter_list.insert(0, *self.master.dict[0]) self.chapter_list.grid(column = 0, row = 1, sticky='n') class FrequencyScale(Frame): def set_freq(self, freq): self.frequency.set(freq) def update_freq(self, num): self.master.query.update_freq(int(num)) def __init__(self, master): Frame.__init__(self,master) self.frequency = IntVar() self.frequency.set(init_freq) self.freq_label = Label(self) self.freq_label['text'] = 'Word frequency:' self.freq_label.grid(column = 0, row = 0, sticky = 'e') self.freq_display = Label(self) self.freq_display['textvariable'] = self.frequency self.freq_display.grid(column = 1, row = 0, sticky = 'w') self.freq_select = Scale(self) self.freq_select['from_'] = 1 self.freq_select['to'] = total_freq self.freq_select['length'] = 260 self.freq_select['orient'] = 'horizontal' self.freq_select['showvalue'] = 0 self.freq_select['variable'] = self.frequency self.freq_select['command'] = self.update_freq self.freq_select.grid(column = 0, columnspan = 2, sticky = 'ew') class ModeSelector(Frame): def __init__(self, master): Frame.__init__(self, master) self.label = Label(self) self.label['text'] = 'Mode selection:' self.label.grid() self.radios = [] self.radio_control = IntVar() for i in range(0,3): radio = Radiobutton(self) radio['text'] = radio_text[i] radio['anchor'] = 'w' radio['variable'] = self.radio_control radio['value'] = i radio.grid(sticky = 'w') self.radios.append(radio) class Application(Frame): def __init__(self, master=None): Frame.__init__(self, master) self.master.title('flasher (jwl)') self.pack() def save_session(self): dump((self.buckets, self.history.word_history), open('prog.dat', 'w')) def load_session(self): self.buckets, self.history.word_history = load(open('prog.dat')) self.history.reset_list() for chapter in zip(dict[1], self.buckets): for freq in range(1, total_freq + 1): for item in chapter[1][freq - 1]: chapter[0][item][2][0] = freq def find_word(self): chapter = int(choice(self.chapter_box.chapter_list.curselection())) cur_buckets, bucket = self.buckets[chapter], 0 total, freq_sum = 0.0, [] for i in range(0, total_freq): total += len(cur_buckets[i]) * exp(i) freq_sum.append(total) point = uniform(0, total) while bucket < total_freq and freq_sum[bucket] < point: bucket += 1 id = (chapter, choice(cur_buckets[bucket])) tempdef = dict[1][chapter][id[1]] if self.radio_mode.radio_control.get() * choice([1,2]) % 4: return (tempdef[1], tempdef[0], tempdef[2]), id else: return (tempdef[0], tempdef[1], tempdef[2]), id def set_probabilities(self): self.buckets = [] for chapter in dict[1]: bucket = [[] for i in range(0, total_freq)] bucket[init_freq - 1] = range(0, len(chapter)) self.buckets.append(bucket) def create_chapters(self): self.chapter_box = ChapterBox(self) self.chapter_box.grid(column = 0, row = 0, columnspan = 2, sticky = 'n') def create_query(self): self.query = Querybutton(self) self.query.grid(column = 0, columnspan = 3, row = 3, sticky = 'we', padx = 2) def create_mode_selector(self): self.radio_mode = ModeSelector(self) self.radio_mode.grid(column = 1, row = 1, rowspan = 2) def create_freq_selector(self): self.freq_scale = FrequencyScale(self) self.freq_scale.grid(column = 2, row = 2, sticky = 'e') def create_history(self): self.history = HistoryBox(self) self.history.grid(column = 2, row = 0, rowspan = 2, sticky = 'n') def create_session(self): self.session_frame = Frame(self) self.session_frame.grid(column = 0, row = 1, rowspan = 2, sticky = 'n') self.session_label = Label(self.session_frame) self.session_label['text'] = 'Session progress:' self.session_label.grid(column = 0, row = 0) self.save = Button(self.session_frame) self.save['text'] = 'save to \'prog.dat\'' self.save['command'] = self.save_session self.save.grid(column = 0, row = 1, sticky = 'ew') self.load = Button(self.session_frame) self.load['text'] = 'load from \'prog.dat\'' self.load['command'] = self.load_session self.load.grid(column = 0, row = 2, sticky = 'ew') def draw_app(self, dict): self.dict = dict self.set_probabilities() self.create_chapters() self.create_query() self.create_mode_selector() self.create_freq_selector() self.create_history() self.create_session() def utf_8(line): for conv in zip(conv_from, conv_to): line = replace(line, conv[0], conv[1]) return line.encode('utf-8') def find_closing_parenthesis(line): n, pos = 0, 0 for c in line: pos += 1 if c in '[{(': n += 1 elif c in ')}]': n -= 1 if n == 0: return pos def extract_section_name(line): entry = chop_section.match(line) if entry == None: return line = utf_8(entry.group('name')) pos = find_closing_parenthesis(line) return line[1:pos - 1] def parse_word_definition(line): entry = chop_item.match(line) if entry == None: return line = utf_8(entry.group('defn')) pos = find_closing_parenthesis(line) return (line[1:pos - 1].strip(), line[pos:].strip(), [init_freq]) def build_dictionary(file): section_names = [] definitions = [] for line in file: name = extract_section_name(line) defn = parse_word_definition(line) if name: section_names.append(name) definitions.append([]) elif defn: definitions[len(definitions) - 1].append(defn) return section_names, definitions def summarize_dictionary(dict): i = 0 for section in zip(*dict): i += 1 print 'Section ' + str(i) + ': \'' + section[0] + '\', ' + str(len(section[1])) + ' definitions' if len(argv) <> 2: print 'syntax: prompter.py input file' sys.exit() dict = build_dictionary(open(argv[1])) summarize_dictionary(dict) app = Application() app.draw_app(dict) app.mainloop()