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