1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 #include "solution.hh"
5 #include "panel.hh"
6 #include "board.hh"
7 #include "tile.hh"
8 
SolutionDisplay(Game * game,Board * board)9 SolutionDisplay::SolutionDisplay(Game *game, Board *board)
10   : _game(game), _board(board),
11     _on(false), _pos(0), _alarm(this), _state(0), _time_scale(3)
12 {
13 }
14 
15 
16 /* State values:
17    0 initial pause	0.2 s
18    1 flash on		0.3 s
19    2 flash off		0.2 s
20    3 flash on		0.3 s
21    4 remove		0.1 s -> state 1
22 */
23 
24 bool
turn_on(Panel * panel)25 SolutionDisplay::turn_on(Panel *panel)
26 {
27   if (_game->solution().size()) {
28     int moves = 0;
29     while (_game->undo())
30       moves++;
31     _state = 0;
32     _pos = 0;
33     _on = true;
34     alarm();
35     _alarm.schedule(Moment::now() + delay(200000 + 25000*moves));
36   } else {
37     panel->bell();
38     _on = false;
39   }
40   return _on;
41 }
42 
43 
44 void
real_turn_off()45 SolutionDisplay::real_turn_off()
46 {
47   if (_state == 2 || _state == 4) {
48     // Turn off the current highlighted move if necessary
49     Move cur_move = _game->solution()[_pos];
50     _board->unlight(cur_move.m1);
51     _board->unlight(cur_move.m2);
52     _board->flush();
53   }
54   _alarm.kill();
55   _on = false;
56   _time_scale = 3;
57 }
58 
59 
60 Moment
delay(long ival) const61 SolutionDisplay::delay(long ival) const
62 {
63   ival = ival * 3 / _time_scale;
64   return Moment(0, ival);
65 }
66 
67 
68 void
change_speed(bool faster)69 SolutionDisplay::change_speed(bool faster)
70 {
71   if (faster) {
72     if (_time_scale < 100)
73       _time_scale = 2 * _time_scale - 2;
74   } else {
75     if (_time_scale > 3)
76       _time_scale = (_time_scale + 2) / 2;
77   }
78 }
79 
80 
81 void
alarm()82 SolutionDisplay::alarm()
83 {
84   if (!_on) return;
85 
86   Moment now = Moment::now();
87   Move cur_move = _game->solution()[_pos];
88 
89   switch (_state) {
90 
91    case 0:
92     _alarm.schedule(now + delay(200000));
93     _state = 1;
94     break;
95 
96    case 1:
97    case 2:
98    case 3:
99      {
100        bool light = _state % 2;
101        _board->set_lit(cur_move.m1, light);
102        _board->set_lit(cur_move.m2, light);
103        _board->flush();
104        _alarm.schedule(now + delay(light ? 300000 : 200000));
105        _state++;
106        break;
107      }
108 
109    case 4:
110     if (!cur_move.m1->open() || !cur_move.m2->open())
111       fatal_error("solution trying to remove non-free tiles!\n\
112   This is a bug in xmahjongg. Please send mail to eddietwo@mit.edu telling\n\
113   him so. Include the board number, which is %lu; the board\n\
114   layout (e.g., \"default\" or \"bridge\"); and xmahjongg's\n\
115   version number, which you get by running `xmahjongg --version'.",
116 		  (unsigned long)_game->board_number());
117     _game->move(cur_move.m1, cur_move.m2);
118     _pos++;
119     if (_pos >= _game->solution().size()) {
120       _on = false;
121       _time_scale = 3;
122     } else {
123       _alarm.schedule(now + delay(100000));
124       _state = 1;
125     }
126     break;
127 
128   }
129 }
130