|
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 quizzes.py
|
# quizzes - a set of quiz-oriented minigames for the "quiz" pygame app import vectors ; from vectors import * import things ; from things import * import pieces ; from pieces import * import boards ; from boards import * import goals ; from goals import * import romaji ; from romaji import * def pretty(roma): fixes = { 'SI': 'SHI', 'TI': 'CHI', 'HU': 'FU', 'TU': 'TSU', 'ZI': 'JI', 'si': 'shi', 'ti': 'chi', 'hu': 'fu', 'tu': 'tsu', 'zi': 'ji', } if roma in fixes: roma = fixes[roma] return roma import random #---------------------------------------------------------------------------- class Quiz (Board): '''A generic base class for a number of quiz mini-games. Each minigame in this family allows the user to drag cards from one zone to another zone; typically it reacts in some way when the right conditions are met, then allows the app to segue to some other game. ''' def __init__(self): super(Quiz, self).__init__() self.hint = '' self.font = App.resource('epkgobld.ttf', 84) self.zones = { } def make_zone(self, name, image, place): '''Most zones are just a static image, or None.''' if image: image = App.resource(image) zone = Zone(name, image, size=0.75) zone.follow(self) zone.place = place self.zones[name] = zone return zone def nearest_drop(self, thing, where): nearest = self.nearest_zone(where, test=None) if nearest: if nearest[0].is_style('trading'): # if dropping on a full zone that supports trading, move that # full zone's stuff onto the nearest empty trading zone instead stuff = nearest[0].followers() if stuff: test = lambda z: not z.followers() and z.is_style('trading') another = self.nearest_zone(where, test=test) if another: for thing in reversed(stuff): thing.goto(another[0]) else: # just find a plain old empty zone instead of this full one test=lambda z: not z.followers() nearest = self.nearest_zone(where, test=test) if nearest: return nearest return super(Quiz, self).nearest_drop(thing, where) def xnearest_drop(self, thing, where): nearest = self.nearest_zone(where, test=lambda z: not z.followers()) if nearest: return nearest return super(Quiz, self).nearest_drop(thing, where) def segue(self): '''We can proceed if the guilty card is idle on the guilty zone.''' if not 'guilty' in self.zones: return self guilty = self.zones['guilty'] cards = guilty.followers() if not cards: return self if not cards[0].is_style('guilty'): return self if not cards[0].is_style('complete'): cards[0].set_style('complete') cards[0].dazzle() if not cards[0].is_idle(): return self return None def make_card(self, front, back=None, size=0.75): if not back: back = front card = Card( (front, back), font=self.font, size=size ) return card def make_tile(self, front, back=None, size=0.75): if not back: back = front tile = Ingot( (front, back), font=self.font, size=size ) return tile #---------------------------------------------------------------------------- class IntroQuiz (Quiz): '''The very first quiz that starts the game. This requires the user to figure out the visual scheme used in all of the early quizzes: drag a card to the right target zone. Once this quiz is accomplished, it's never seen again. ''' def __init__(self): super(IntroQuiz, self).__init__() x = random.choice( [ -150, 150 ] ) home = self.make_zone('home', 'zone-blue.png', V(360, 150, 0)) wrong = self.make_zone('wrong', 'zone-red-x.png', V(360+x, 220, 0)) right = self.make_zone('guilty', 'zone-green-o.png', V(360-x, 220, 0)) self.card = self.make_card(u'\u3007') # maru self.card.set_style('guilty') self.card.follow(home) self.card.wait(dt=0.2) self.card.flip() #---------------------------------------------------------------------------- class FlybyQuiz (Quiz): '''A card flies by, while a floating text string explains.''' def __init__(self, roma, explanation): super(FlybyQuiz, self).__init__() card = self.make_card(roma, kana(roma), size=1) card.follow(self) card.place = V(-50, 175, 4) for x in range(5): card.move(V(85, 0, 0), relative=True, dt=0.7) card.wait() card.flip() card.wait() card.wait(dt=2, todo=lambda g,c=card: c.dazzle()) self.card = card # any of them self.explanation = card.font.render(explanation, 1, (0x00,0x00,0x00)) def segue(self): for card in self.joins: if not card.is_idle(): return self return None class LineupQuiz (Quiz): '''Five cards arranged in a police line-up. One card is a rogue.''' def __init__(self, lineup, rogues): super(LineupQuiz, self).__init__() self.hint = 'Which one does not belong?' # self.lineup gets card names, not cards self.rogue = random.choice(rogues) self.lineup = [ self.rogue ] + random.sample(lineup, 4) random.shuffle(self.lineup) y = random.choice( [ -100, 100 ] ) for i in range(len(self.lineup)): zone = self.make_zone('suspect%d' % i, 'zone-blue.png', V(100+130*i, 200-y, 0)) zone.set_style('trading') card = self.make_card(kana(self.lineup[i])) if self.lineup[i] == self.rogue: card.set_style('guilty') card.follow(zone) card.wait(dt=0.1*i) card.flip() i = random.choice(range(1, 5)) self.make_zone('guilty', 'zone-red-x.png', V(100+130*i, 200+y, 0)) class MugshotQuiz (LineupQuiz): '''Just like LineupQuiz, except we see romaji for the desired kana.''' def __init__(self, lineup): lineup = list(lineup) random.shuffle(lineup) rogue = lineup.pop() super(MugshotQuiz, self).__init__(lineup, (rogue,)) self.hint = 'Which one looks right?' mugshot = self.make_tile(pretty(rogue)) place = self.zones['guilty'].place self.zones['guilty'].set_image('zone-green-o.png', size=0.75) mugshot.set_style('draggable', False) mugshot.follow(self) mugshot.move(place + V(-130, 0, 0)) class OrderingQuiz (Quiz): '''A number of scrambled cards on a row of zones. Reorder to pass.''' def __init__(self, lineup): super(OrderingQuiz, self).__init__() self.hint = 'Put these into the right order!' # self.lineup gets card names, not cards self.dazzled = False self.lineup = list(lineup) if len(lineup) < 2: raise ValueError, 'cannot matchup one item or less' if len(lineup) > 10: raise ValueError, 'cannot matchup more than ten items' self.mixup = list(lineup[:]) while self.mixup == self.lineup: random.shuffle(self.mixup) self.flip = y = random.choice( [ -100, 100 ] ) self.matching = [ ] for i in range(len(self.lineup)): if i == 5: y = -y zone = self.make_zone('suspect%d' % i, 'zone-blue.png', V(100+130*(i % 5), 200-y, 0)) zone.set_style('trading') self.matching.append(zone) # card = self.make_card(kana(self.mixup[i])) card.name = self.mixup[i] card.follow(zone) card.wait(dt=0.1*i) card.flip() def segue(self): i = 0 for zone in self.matching: cards = zone.followers() if not cards: return self card = cards[0] if card.name != self.lineup[i]: return self if not card.is_idle(): return self i += 1 if not self.dazzled: self.dazzled = True i = 0 for zone in self.matching: cards = zone.followers() card = cards[0] card.wait(dt=0.1*i,todo=lambda g,c=card: c.dazzle()) i += 1 return self return None class MatchupQuiz (OrderingQuiz): '''Up to five cards to reorder, showing desired order with flipped cards.''' def __init__(self, lineup): super(MatchupQuiz, self).__init__(lineup) self.hint = 'Put these into the same order!' if len(lineup) > 5: raise ValueError, 'cannot matchup more than five' y = self.flip for i in range(len(self.lineup)): tile = self.make_tile(self.lineup[i]) tile.set_style('draggable', False) tile.follow(self) tile.place = V(100+130*i, 200+y, 0) tile.wait(dt=0.6-0.1*i) tile.flip() _figures = { } class SketchQuiz (Quiz): '''Draw the kana on a clingpad sketching board.''' def __init__(self, lineup): self.passed = False lineup = list(lineup) random.shuffle(lineup) self.rogue = lineup.pop() super(SketchQuiz, self).__init__() self.mugshot = self.make_card(pretty(self.rogue)) self.mugshot.set_style('draggable', False) self.mugshot.follow(self) self.mugshot.move(V(180, 200, 0)) self.mugshot.wait(dt=0.2) self.mugshot.flip() font = App.resource('epkgobld.ttf', 300) guide = font.render(kana(self.rogue), 1, (0x00,0x80,0x00)) alpha = surfarray.pixels_alpha(guide) alpha /= Numeric.array(8).astype(Numeric.UInt8) self.clingpad = ClingPad(guide=guide) self.clingpad.set_style('draggable', False) self.clingpad.follow(self) self.clingpad.move(V(450, 200, 0)) def event(self, event): super(SketchQuiz, self).event(event) if event.type == KEYDOWN: if event.key in [ K_KP_ENTER, K_RETURN ]: self.passed = True self.mugshot.dazzle() if event.key == K_F4: figure = self.clingpad.figure print str(figure) figure.cook() if not self.rogue in _figures: _figures[self.rogue] = [ ] _figures[self.rogue].append(figure) def segue(self): if self.passed: if self.clingpad.is_idle(): if self.mugshot.is_idle(): return None return self #---------------------------------------------------------------------------- def _TestQ1(): return MugshotQuiz(('ka','ki','ku','ke','ko')) def _TestQ2(): return LineupQuiz(('ka','ki','ku','ke','ko'), ('ta','chi','tsu','te','to')) def _TestQ3(): return SketchQuiz( (romaji.choice(family='hiragana'), ) ) def _TestQ4(): return MatchupQuiz( ('ka', 'ki', 'ku', 'ke', 'ko') ) if __name__ == '__main__': app = App('Quiz Demos', (720, 420)) Piece._shadows = True app.graph = { 'MugshotQuiz': _TestQ3, 'SketchQuiz': _TestQ2, 'LineupQuiz': _TestQ1, 'MatchupQuiz': _TestQ4, } app.space = _TestQ4( ) app.run() |
|
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. |
|