|
Programmer's Notebook |
All computer source code presented on this page, unless it includes attribution to another author, is provided by Ed Halley under the Artistic License. Use such code freely and without any expectation of support. I would like to know if you make anything cool with the code, or need questions answered.
python/ bindings.py boards.py buzz.py cache.py cards.py constraints.py csql.py english.py getopts.py gizmos.py goals.py improv.py interpolations.py namespaces.py nihongo.py nodes.py octalplus.py patterns.py persist.py physics.py pids.py pieces.py quizzes.py recipes.py relays.py romaji.py ropen.py sheets.py strokes.py subscriptions.py svgbuild.py testing.py things.py timing.py ucsv.py useful.py uuid.py vectors.py weighted.py java/ CSVReader.java CSVWriter.java GlobFilenameFilter.java RegexFilenameFilter.java StringBufferOutputStream.java ThreadSet.java Throttle.java TracingThread.java Utf8ConsoleTest.java droid/ ArrangeViewsTouchListener.java DownloadFileTask.java perl/ CVQM.pm Kana.pm Typo.pm cxx/ CCache.h equalish.cpp |
Download cards.py
|
__all__ = [ 'Card', 'Deck' ] import ucsv as csv import random import time class Card (object): def __init__(self, sides, **kwargs): if hasattr(sides, 'items'): self.names = [ pair[0] for pair in sides.items() if pair[1] ] self.sides = [ pair[1] for pair in sides.items() if pair[1] ] else: self.names = [ ('SIDE%d' % n) for n in range(len(sides)) ] self.sides = sides self.index = dict(zip( self.names, range(len(self.names)) )) self.stats = kwargs self.shown = 0 def show(self, side): if side in self.index: side = self.index[side] if side < 0 or side >= len(self.sides): raise ValueError, 'index out of range' self.shown = side def side(self, side): if side in self.index: side = self.index[side] if side < 0 or side >= len(self.sides): return None return self.sides[side] def has(self, side): return side in self.index def stat(self, var, val=None): if var in self.stats: if val is not None: self.stats[var] = val return self.stats[var] return val def __repr__(self): t = 'Card(names=%r, sides=%r, stats=%r)' % (self.names, self.sides, self.stats) return t def __str__(self): return u'%s' % self.sides[self.shown] class Deck (object): def __init__(self, cards=None): if cards is None: cards = [ ] self.cards = cards self.heads = [ ] def __len__(self): return len(self.cards) def __nonzero__(self): return len(self.cards) > 0 def __getitem__(self, n): return self.cards[n] def shuffle(self): random.shuffle(self.cards) def discard(self, count=1): count = min(count, len(self.cards)) self.cards = self.cards[:-count] def keep(self, count=1): count = min(count, len(self.cards)) self.cards = self.cards[:count] def loadCsv(self, filename, stats=None): if stats is None: stats = { } if isinstance(stats, (list,set,tuple)): stats = dict(zip( stats, [0,]*len(stats) )) f = file(filename, 'rb') c = csv.DictReader(f) for row in c: if not self.heads: self.heads = c.fieldnames s = { } for stat in stats: s[stat] = row.pop(stat, None) or stats[stat] c = Card(row, **s) if c.sides: self.cards.append(c) f.close() return len(self.cards) def saveCsv(self, filename): f = file(filename, 'wb') c = csv.DictWriter(f, self.heads, restval=u'') for card in self.cards: row = card.stats.copy() for n in range(len(card.sides)): row[card.names[n]] = card.sides[n] c.writerow(row) f.close() return len(self.cards) def similar(self, common=None, varies=None, tested=None): if common is None: common = self.heads if isinstance(common, (list, tuple, set)): common = random.choice(common) match = None tries = 0 while not match and tries < 100: tries += 1 match = random.choice(self.cards) if not match.has(tested): continue if not match.has(varies): continue if not match.has(common): continue match = match.side(common) if not match: return None hand = [ card for card in self.cards if card.side(common) == match and card.has(varies) and card.has(tested) ] if not hand: return None return Deck(hand) def __quiz(deck, common, varies, tested, count=4): hand = None tries = 0 while not hand: tries += 1 if tries > 100: return hand = deck.similar(common, varies, tested) if not hand: continue if len(hand) < count: hand = None hand.shuffle() hand.keep(count) quiz = random.randrange(0, count) print 'QUIZ:', hand[quiz].side(tested), '-' for n in range(count): card = hand[n] print u"(%s): %s" % (chr(ord('a')+n), card.side(varies)) hit = False choices = ', '.join( [ '(%s)' % chr(ord('a')+n) for n in range(count) ] ) guess = raw_input('Answer %s, or (Enter) to skip: ' % choices) if len(guess) > 0: hand[quiz].stats['SEEN'] += 1 hand[quiz].stats['LAST'] = int(time.time()) guess = ord(guess[0])-ord('a') if guess == quiz: print 'Correct!' hit = True else: print 'Incorrect.' hand[quiz].stats['HITS'] += 1 shown = [ hand[quiz].side(x) for x in hand[quiz].names if x != common ] print ' = '.join(shown) return hit if __name__ == '__main__': filename = 'vocab.csv' d = Deck() d.loadCsv(filename, 'SEEN,HITS,LAST'.split(',')) dirty = False import os import sys import romaji romaji.__utf8__() args = sys.argv args.pop(0) while args: arg = args.pop(0) if arg in ['-q','--quiz']: count = 10 try: count = args.pop(0) count = int(count) except: pass quizzes = [ {'common':'POS','varies':'KANA','tested':'ENGLISH'}, {'common':'POS','varies':'ENGLISH','tested':'KANJI'}, {'common':'POS','varies':'KANJI','tested':'KANA'}, {'common':'POS','varies':'KANA','tested':'KANJI'} ] for n in range(count): print q = random.choice(quizzes) __quiz(d, **q) dirty = True if arg in ['-a','--add']: dirty = True if dirty: os.rename(filename, filename+'~') d.saveCsv(filename) print 'Updated %s (%d cards).' % (filename, len(d.cards)) |
|
Contact Ed Halley by email at
ed@halley.cc. Text, code, layout and artwork are Copyright © 1996-2013 Ed Halley. Copying in whole or in part, with author attribution, is expressly allowed. Any references to trademarks are illustrative and are controlled by their respective owners. |
|