38
38
_FREQ_QUICK = 1
39
39
_ANSWER_SEC_QUICK = 2
40
40
_DEFAULT_SCORE_FONT = 'monospace'
41
+ _DEFAULT_ANSWER_SCHEME = 'NESW'
41
42
43
+ _KEYS_ARROWS = (pygame .K_UP , pygame .K_RIGHT , pygame .K_DOWN , pygame .K_LEFT )
44
+ # The order of the following matches the order of the above.
42
45
_KEYS_MINECRAFT_LOWER = 'wdsa'
43
46
_KEYS_MINECRAFT_UPPER = 'WDSA'
44
- _KEYS_ARROWS = (pygame .K_UP , pygame .K_RIGHT , pygame .K_DOWN , pygame .K_LEFT )
45
47
46
48
_home = os .path .expanduser ('~' )
47
49
_xdg_state_home = os .environ .get ('XDG_STATE_HOME' ) or os .path .join (_home , '.local' , 'state' )
@@ -67,6 +69,7 @@ def get_argument_parser():
67
69
parser .add_argument ('--show-feedback' , action = argparse .BooleanOptionalAction , help = 'Show feedback on wrong answers.' )
68
70
parser .add_argument ('--show-scores' , action = argparse .BooleanOptionalAction , help = 'Show scores in main window.' )
69
71
parser .add_argument ('--score-font' , help = 'Font to use for displaying scores (defaults to %s).' % _DEFAULT_SCORE_FONT )
72
+ parser .add_argument ('--answer-scheme' , choices = [_DEFAULT_ANSWER_SCHEME , 'EW' ], default = None , help = 'Where to show possible answers (letters stand for geographic directions relative to displayed question).' )
70
73
71
74
return parser
72
75
@@ -121,7 +124,7 @@ class Settings:
121
124
122
125
def __init__ (self , fs , parsed_args ):
123
126
self ._s = dict ((k , None ) for k in [
124
- 'limit' , 'show_scores' , 'show_feedback' , 'score_font' ])
127
+ 'limit' , 'show_scores' , 'show_feedback' , 'score_font' , 'answer_scheme' ])
125
128
self ._load_settings (fs )
126
129
self ._merge_settings (parsed_args )
127
130
self ._save_settings (fs )
@@ -142,6 +145,10 @@ def show_feedback(self):
142
145
def score_font (self ):
143
146
return self ._s ['score_font' ] or _DEFAULT_SCORE_FONT
144
147
148
+ @property
149
+ def answer_scheme (self ):
150
+ return self ._s ['answer_scheme' ] or _DEFAULT_ANSWER_SCHEME
151
+
145
152
def _load_settings (self , fs ):
146
153
loaded = fs .read ()
147
154
if not loaded :
@@ -299,6 +306,7 @@ def __init__(self, settings):
299
306
self ._should_show_scores = settings .show_scores
300
307
self ._should_show_feedback = settings .show_feedback
301
308
self ._score_font_name = settings .score_font
309
+ self ._answer_scheme = settings .answer_scheme
302
310
303
311
def __enter__ (self ):
304
312
logging .debug ('Initializing pygame.' )
@@ -327,10 +335,10 @@ def _tick(self):
327
335
self ._clock .tick (30 ) # low framerate is fine for this app
328
336
329
337
def answer_count (self ):
330
- return 4
338
+ return len ( self . _answer_scheme )
331
339
332
340
def solve_problem (self , problem , state ):
333
- answers = self ._display_problem (problem , state )
341
+ answer_map = self ._display_problem (problem , state )
334
342
335
343
asked_time = time .time ()
336
344
@@ -342,16 +350,12 @@ def solve_problem(self, problem, state):
342
350
logging .debug ('Initiating shutdown.' )
343
351
raise QuitException ()
344
352
if event .type == pygame .KEYDOWN :
345
- if event .unicode and event .unicode in _KEYS_MINECRAFT_LOWER :
346
- answer_index = _KEYS_MINECRAFT_LOWER .index (event .unicode )
347
- elif event .unicode and event .unicode in _KEYS_MINECRAFT_UPPER :
348
- answer_index = _KEYS_MINECRAFT_UPPER .index (event .unicode )
349
- elif event .key in _KEYS_ARROWS :
350
- answer_index = _KEYS_ARROWS .index (event .key )
353
+ logging .debug (answer_map )
354
+ if answer_map .has_answer_for (event ):
355
+ problem .answered (answer_map .answer_for (event ), asked_time )
356
+ return
351
357
else :
352
358
continue
353
- problem .answered (answers [answer_index ], asked_time )
354
- return
355
359
356
360
def provide_feedback (self , problem , state ):
357
361
if not self ._should_show_feedback :
@@ -374,12 +378,11 @@ def _display_problem(self, problem, state, reveal_solution=False):
374
378
self ._show_correct_score (state )
375
379
self ._show_error_score (state )
376
380
self ._show_question (problem )
377
- answers = problem .answers ()
378
- self ._show_answers (problem , answers , reveal_solution = reveal_solution )
381
+ answer_map = self ._show_answers (problem , problem .answers (), reveal_solution = reveal_solution )
379
382
logging .debug ('Updating display.' )
380
383
pygame .display .flip ()
381
384
logging .debug ('Problem displayed.' )
382
- return answers
385
+ return answer_map
383
386
384
387
def _show_correct_score (self , state ):
385
388
screen_bottom_left = self ._screen .get_rect ().bottomleft
@@ -412,26 +415,42 @@ def _show_question(self, problem):
412
415
413
416
def _show_answers (self , problem , answers , reveal_solution = False ):
414
417
screen_center = self ._screen .get_rect ().center
415
-
416
- answer_up = self ._font .render (answers [0 ], 1 , self ._text_color )
417
- answer_up_rect = answer_up .get_rect (center = (screen_center [0 ], int (1.5 * self ._digit_size [1 ])))
418
- pygame .draw .rect (self ._screen , self ._answer_color (problem , answers [0 ], reveal_solution ), answer_up_rect )
419
- self ._screen .blit (answer_up , answer_up_rect )
420
-
421
- answer_right = self ._font .render (answers [1 ], 1 , self ._text_color )
422
- answer_right_rect = answer_right .get_rect (center = (int (21 * self ._digit_size [0 ]), screen_center [1 ]))
423
- pygame .draw .rect (self ._screen , self ._answer_color (problem , answers [1 ], reveal_solution ), answer_right_rect )
424
- self ._screen .blit (answer_right , answer_right_rect )
425
-
426
- answer_down = self ._font .render (answers [2 ], 1 , self ._text_color )
427
- answer_down_rect = answer_down .get_rect (center = (screen_center [0 ], int (5.5 * self ._digit_size [1 ])))
428
- pygame .draw .rect (self ._screen , self ._answer_color (problem , answers [2 ], reveal_solution ), answer_down_rect )
429
- self ._screen .blit (answer_down , answer_down_rect )
430
-
431
- answer_left = self ._font .render (answers [3 ], 1 , self ._text_color )
432
- answer_left_rect = answer_left .get_rect (center = (int (3 * self ._digit_size [0 ]), screen_center [1 ]))
433
- pygame .draw .rect (self ._screen , self ._answer_color (problem , answers [3 ], reveal_solution ), answer_left_rect )
434
- self ._screen .blit (answer_left , answer_left_rect )
418
+ answers = list (answers ) # copy before mutating the list
419
+ answer_map = AnswerMap ()
420
+
421
+ if 'N' in self ._answer_scheme :
422
+ answer_up = answers .pop (0 )
423
+ answer_up_surface = self ._font .render (answer_up , 1 , self ._text_color )
424
+ answer_up_rect = answer_up_surface .get_rect (center = (screen_center [0 ], int (1.5 * self ._digit_size [1 ])))
425
+ pygame .draw .rect (self ._screen , self ._answer_color (problem , answer_up , reveal_solution ), answer_up_rect )
426
+ self ._screen .blit (answer_up_surface , answer_up_rect )
427
+ answer_map .answer_up (answer_up )
428
+
429
+ if 'E' in self ._answer_scheme :
430
+ answer_right = answers .pop (0 )
431
+ answer_right_surface = self ._font .render (answer_right , 1 , self ._text_color )
432
+ answer_right_rect = answer_right_surface .get_rect (center = (int (21 * self ._digit_size [0 ]), screen_center [1 ]))
433
+ pygame .draw .rect (self ._screen , self ._answer_color (problem , answer_right , reveal_solution ), answer_right_rect )
434
+ self ._screen .blit (answer_right_surface , answer_right_rect )
435
+ answer_map .answer_right (answer_right )
436
+
437
+ if 'S' in self ._answer_scheme :
438
+ answer_down = answers .pop (0 )
439
+ answer_down_surface = self ._font .render (answer_down , 1 , self ._text_color )
440
+ answer_down_rect = answer_down_surface .get_rect (center = (screen_center [0 ], int (5.5 * self ._digit_size [1 ])))
441
+ pygame .draw .rect (self ._screen , self ._answer_color (problem , answer_down , reveal_solution ), answer_down_rect )
442
+ self ._screen .blit (answer_down_surface , answer_down_rect )
443
+ answer_map .answer_down (answer_down )
444
+
445
+ if 'W' in self ._answer_scheme :
446
+ answer_left = answers .pop (0 )
447
+ answer_left_surface = self ._font .render (answer_left , 1 , self ._text_color )
448
+ answer_left_rect = answer_left_surface .get_rect (center = (int (3 * self ._digit_size [0 ]), screen_center [1 ]))
449
+ pygame .draw .rect (self ._screen , self ._answer_color (problem , answer_left , reveal_solution ), answer_left_rect )
450
+ self ._screen .blit (answer_left_surface , answer_left_rect )
451
+ answer_map .answer_left (answer_left )
452
+
453
+ return answer_map
435
454
436
455
437
456
def _answer_color (self , problem , answer , reveal_solution = False ):
@@ -440,8 +459,45 @@ def _answer_color(self, problem, answer, reveal_solution=False):
440
459
return self ._answer_correct_color if problem .correct_answer () == answer else self ._answer_error_color
441
460
442
461
462
+ class AnswerMap :
463
+
464
+ def __init__ (self ):
465
+ self ._answers = dict (
466
+ up = None ,
467
+ right = None ,
468
+ down = None ,
469
+ left = None )
470
+
471
+ def answer_up (self , answer ):
472
+ self ._answers ['up' ] = answer
473
+
474
+ def answer_right (self , answer ):
475
+ self ._answers ['right' ] = answer
476
+
477
+ def answer_down (self , answer ):
478
+ self ._answers ['down' ] = answer
479
+
480
+ def answer_left (self , answer ):
481
+ self ._answers ['left' ] = answer
482
+
483
+ def has_answer_for (self , event ):
484
+ return self .answer_for (event ) != None
485
+
486
+ def answer_for (self , event ):
487
+ if event .unicode and event .unicode in _KEYS_MINECRAFT_LOWER :
488
+ answer_index = _KEYS_MINECRAFT_LOWER .index (event .unicode )
489
+ elif event .unicode and event .unicode in _KEYS_MINECRAFT_UPPER :
490
+ answer_index = _KEYS_MINECRAFT_UPPER .index (event .unicode )
491
+ elif event .key and event .key in _KEYS_ARROWS :
492
+ answer_index = _KEYS_ARROWS .index (event .key )
493
+ else :
494
+ return None
495
+ direction = ['up' , 'right' , 'down' , 'left' ][answer_index ]
496
+ return self ._answers [direction ]
497
+
498
+
443
499
class Problem :
444
-
500
+
445
501
def __init__ (self , a , b , answer_count ):
446
502
self ._a = a
447
503
self ._b = b
0 commit comments