lcd-m6sp.c: remove \r
[kugel-rb.git] / apps / plugins / reversi / reversi-gui.c
blob67ccf19456f0e329427c591dcb8ffc75771a07b7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (c) 2006 Alexander Levin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 GUI part of reversi. Code is inspired by sudoku code by Dave Chapman
24 which is copyright (c) 2005 Dave Chapman and is released under the
25 GNU General Public License.
28 User instructions
29 -----------------
31 Use the arrow keys to move cursor, and press TOGGLE to place a stone.
33 At any time during the game, press MENU to bring up the game menu with
34 further options:
35 - Save
36 - Reload
37 - Clear
40 #include "plugin.h"
42 #ifdef HAVE_LCD_BITMAP
44 #include "reversi-game.h"
45 #include "reversi-strategy.h"
46 #include "reversi-gui.h"
48 #include "lib/playback_control.h"
50 PLUGIN_HEADER
52 /* This is initialized at the start of the plugin and used to determine the
53 * Appropriate game board size/legend spacing if the font is larger than a cell
54 * height/width.
56 static int font_width;
57 static int font_height;
59 /* Where the board begins */
60 #define XOFS 4
61 #define YOFS 4
63 #if LCD_HEIGHT > LCD_WIDTH
64 #define MARGIN_W (XOFS*2+1)
65 #define MARGIN_H (YOFS*2+1)
66 #define MARGIN_C_W 0
67 #define MARGIN_C_H 2
68 #else
69 #define MARGIN_W (XOFS*2 + 16)
70 #define MARGIN_H (YOFS*2+1)
71 #define MARGIN_C_W 1
72 #define MARGIN_C_H 0
73 #endif
75 #if ( (LCD_WIDTH - MARGIN_W) / (BOARD_SIZE+MARGIN_C_W)) < \
76 ( (LCD_HEIGHT - MARGIN_H) / (BOARD_SIZE+MARGIN_C_H))
78 #define CELL_PRE ( ( (LCD_WIDTH * LCD_PIXEL_ASPECT_WIDTH / \
79 LCD_PIXEL_ASPECT_HEIGHT) - MARGIN_W) / \
80 (BOARD_SIZE+MARGIN_C_W) )
82 #define CELL_WIDTH (CELL_PRE*LCD_PIXEL_ASPECT_HEIGHT / LCD_PIXEL_ASPECT_WIDTH)
83 #define CELL_HEIGHT (CELL_PRE)
84 #else
85 #define CELL_PRE ( ( (LCD_HEIGHT * LCD_PIXEL_ASPECT_HEIGHT / \
86 LCD_PIXEL_ASPECT_WIDTH) - MARGIN_H) / \
87 (BOARD_SIZE+MARGIN_C_H) )
89 #define CELL_WIDTH (CELL_PRE)
90 #define CELL_HEIGHT (CELL_PRE*LCD_PIXEL_ASPECT_WIDTH / LCD_PIXEL_ASPECT_HEIGHT)
91 #endif
93 /* Total width and height of the board without enclosing box */
94 #define BOARD_WIDTH (CELL_WIDTH*BOARD_SIZE)
95 #define BOARD_HEIGHT (CELL_HEIGHT*BOARD_SIZE)
97 /* Thickness of the white cells' lines */
98 #if (CELL_WIDTH >= 10) && (CELL_HEIGHT >= 10)
99 #define CELL_LINE_THICKNESS CELL_WIDTH/5
100 #else
101 #define CELL_LINE_THICKNESS 1
102 #endif
104 /* Margins within a cell */
105 #define STONE_MARGIN 2
107 #define CURSOR_MARGIN 1
109 /* Upper left corner of a cell */
110 #define CELL_X(c) (XOFS + (c)*CELL_WIDTH)
111 #define CELL_Y(r) (YOFS + (r)*CELL_HEIGHT)
113 /* Used for touchscreen to convert an X/Y location to a cell location */
114 #define CELL_C(x) (((x)-XOFS)/CELL_WIDTH)
115 #define CELL_R(y) (((y)-YOFS)/CELL_HEIGHT)
117 #if LCD_HEIGHT > LCD_WIDTH
118 #define LEGEND_X(lc) (CELL_X(lc))
119 #define LEGEND_Y(lr) ((CELL_HEIGHT > font_height) ? \
120 CELL_Y(BOARD_SIZE+lr) + YOFS + 1 : \
121 BOARD_HEIGHT + 2*YOFS + font_height*(lr-BOARD_SIZE))
122 #else
123 #define LEGEND_X(lc) (CELL_X(BOARD_SIZE+lc) + XOFS + 1)
124 #define LEGEND_Y(lr) (CELL_HEIGHT > font_height ? \
125 CELL_Y(lr) : font_height*(lr)+YOFS)
126 #endif
129 /* Board state */
130 static reversi_board_t game;
132 /* --- Setting values --- */
134 /* Playing strategies used by white and black players */
135 const game_strategy_t *white_strategy;
136 const game_strategy_t *black_strategy;
138 /* Cursor position */
139 static int cur_row, cur_col;
141 /* Color for the next move (BLACK/WHITE) */
142 static int cur_player;
144 /* Active cursor wrapping mode */
145 static cursor_wrap_mode_t cursor_wrap_mode;
147 static bool quit_plugin;
148 static bool game_finished;
150 #ifdef HAVE_TOUCHSCREEN
151 #include "lib/pluginlib_touchscreen.h"
152 /* This uses the touchscreen library functions/structures. */
154 /* This defines the number of buttons used; only used in this C file. */
155 #define TOUCHBUTTON_COUNT 3
157 /* Define the button locations, widths and heights */
159 #if LCD_HEIGHT < LCD_WIDTH
160 /* Define Menu button x, y, width, height */
161 #define B_MENU_X LEGEND_X(0)
162 #define B_MENU_Y (LCD_HEIGHT-LCD_HEIGHT/2)
163 #define B_MENU_W (LCD_WIDTH-LEGEND_X(0))
164 #define B_MENU_H (LCD_HEIGHT/4)
165 /* Define Quit Button x, y, width, height */
166 #define B_QUIT_X LEGEND_X(0)
167 #define B_QUIT_Y (LCD_HEIGHT-LCD_HEIGHT/4)
168 #define B_QUIT_W (LCD_WIDTH-LEGEND_X(0))
169 #define B_QUIT_H (LCD_HEIGHT/4)
170 #else
171 /* Define Menu button x, y, width, height */
172 #define B_MENU_X (LCD_WIDTH/2)
173 #define B_MENU_Y (CELL_HEIGHT*BOARD_SIZE+YOFS*2)
174 #define B_MENU_W (LCD_WIDTH/4)
175 #define B_MENU_H (2*CELL_HEIGHT)
176 /* Define Quit Button x, y, width, height */
177 #define B_QUIT_X (LCD_WIDTH-LCD_WIDTH/4)
178 #define B_QUIT_Y (CELL_HEIGHT*BOARD_SIZE+YOFS*2)
179 #define B_QUIT_W (LCD_WIDTH/4)
180 #define B_QUIT_H (2*CELL_HEIGHT)
181 #endif
183 /* This is the button initialization/definition. The first element is the
184 * Viewport. This is defined in lcd.h, but the elements are:
185 * int x - X location of button/viewport
186 * int y - Y location of button/viewport
187 * int width - Width of button/viewport
188 * int height - Height of button/viewport
189 * int font - Font to be used on button/viewport
190 * int drawmode- Modes defined in lcd.h
191 * unsigned fg_pattern - foreground color
192 * unsigned bg_pattern - backbround color
193 * unsigned lss_pattern - Selector colors (currently unused)
194 * unsigned lse_pattern - |
195 * unsigned lst_pattern - \/
197 * The rest of the touch button elements are:
198 * bool repeat - requires the area be held for the action
199 * int action - action this button will return
200 * bool invisible - Is this an invisible button?
201 * char *title - Specify a title
202 * fb_data *pixmap- Currently unused, but will allow for a graphic
204 struct touchbutton reversi_buttons[TOUCHBUTTON_COUNT] =
206 { {B_MENU_X, B_MENU_Y, B_MENU_W, B_MENU_H, 0, FONT_UI,
207 STYLE_DEFAULT, 0, 0xFFFF, 0, 0, 0},
208 false, REVERSI_BUTTON_MENU, false, "Menu", NULL },
210 { {B_QUIT_X, B_QUIT_Y, B_QUIT_W, B_QUIT_H, 0, FONT_UI,
211 STYLE_DEFAULT, 0, 0xFFFF, 0, 0, 0},
212 false, REVERSI_BUTTON_QUIT, false, "Quit", NULL },
214 { {0, 0, XOFS+BOARD_WIDTH, YOFS+BOARD_HEIGHT, 0, 0,
215 STYLE_DEFAULT, 0, 0xFFFF, 0, 0, 0},
216 false, REVERSI_BUTTON_MAKE_MOVE, true, NULL, NULL }
218 #endif
220 /* Initialises the state of the game (starts a new game) */
221 static void reversi_gui_init(void) {
222 reversi_init_game(&game);
223 game_finished = false;
224 cur_player = BLACK;
226 /* Place the cursor so that WHITE can make a move */
227 cur_row = 2;
228 cur_col = 3;
232 /* Draws the cursor in the specified cell. Cursor is drawn in the complement
233 * mode, i.e. drawing it twice will result in no changes on the screen.
235 static void reversi_gui_display_cursor(int row, int col) {
236 int old_mode, x, y;
237 old_mode = rb->lcd_get_drawmode();
238 x = CELL_X(col);
239 y = CELL_Y(row);
241 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
242 rb->lcd_drawline(x+CURSOR_MARGIN, y+CURSOR_MARGIN,
243 x+CELL_WIDTH-CURSOR_MARGIN, y+CELL_HEIGHT-CURSOR_MARGIN);
244 rb->lcd_drawline(x+CURSOR_MARGIN, y+CELL_HEIGHT-CURSOR_MARGIN,
245 x+CELL_WIDTH-CURSOR_MARGIN, y+CURSOR_MARGIN);
247 /* Draw the shadows */
248 rb->lcd_hline(x, x+CELL_WIDTH-1, YOFS-3);
249 rb->lcd_hline(x, x+CELL_WIDTH-1, YOFS+BOARD_HEIGHT+3);
250 rb->lcd_vline(XOFS-3, y, y+CELL_HEIGHT-1);
251 rb->lcd_vline(XOFS+BOARD_WIDTH+3, y, y+CELL_HEIGHT-1);
253 rb->lcd_set_drawmode(old_mode);
254 rb->lcd_update();
258 /* Draws the cell of the specified color (WHITE/BLACK) assuming that
259 * the upper left corner of the cell is at (x, y) */
260 static void reversi_gui_draw_cell(int x, int y, int color) {
261 int i;
262 if (color == WHITE) {
263 for (i = 0; i < CELL_LINE_THICKNESS; i++) {
264 rb->lcd_drawrect(
265 x+STONE_MARGIN+i,
266 y+STONE_MARGIN+i,
267 CELL_WIDTH+1-2*(STONE_MARGIN+i),
268 CELL_HEIGHT+1-2*(STONE_MARGIN+i)
271 } else if (color == BLACK) {
272 rb->lcd_fillrect(x+STONE_MARGIN, y+STONE_MARGIN,
273 CELL_WIDTH-STONE_MARGIN-1, CELL_HEIGHT-1-STONE_MARGIN);
274 } else {
275 /* Cell is free -> nothing to do */
280 /* Draws the complete screen */
281 static void reversi_gui_display_board(void) {
282 int x, y, r, c, x_width, x_height;
283 /* This viewport is used to draw a scrolling score */
284 struct viewport tempvp;
285 char buf[8];
287 /* Clear the display buffer */
288 rb->lcd_clear_display();
289 rb->lcd_set_drawmode(DRMODE_FG);
291 /* Thicker board box */
292 rb->lcd_drawrect(XOFS-1, YOFS-1, BOARD_WIDTH+3, BOARD_HEIGHT+3);
294 /* Draw the gridlines */
295 for (r=0, x=XOFS, y=YOFS; r<=BOARD_SIZE;
296 r++, x+=CELL_WIDTH, y+=CELL_HEIGHT) {
297 rb->lcd_hline(XOFS, XOFS+BOARD_WIDTH, y);
298 rb->lcd_vline(x, YOFS, YOFS+BOARD_HEIGHT);
301 /* Draw the stones. This is not the most efficient way but more readable */
302 for (r=0; r<BOARD_SIZE; r++) {
303 y = CELL_Y(r);
304 for (c=0; c<BOARD_SIZE; c++) {
305 x = CELL_X(c);
306 reversi_gui_draw_cell(x, y, game.board[r][c]);
310 /* Draw the cursor */
311 reversi_gui_display_cursor(cur_row, cur_col);
313 /* Draw the current score */
314 reversi_count_occupied_cells(&game, &r, &c);
315 rb->lcd_getstringsize("x", &x_width, &x_height);
317 x = LEGEND_X(0);
318 y = LEGEND_Y(0);
319 reversi_gui_draw_cell(x, y+(LEGEND_Y(1)-LEGEND_Y(0))/2-CELL_WIDTH/2, BLACK);
320 rb->snprintf(buf, sizeof(buf), "%01d", c);
322 tempvp.x=x+CELL_WIDTH+2;
323 tempvp.y=y;
324 tempvp.width=LCD_WIDTH-tempvp.x;
325 tempvp.height=LEGEND_Y(1);
327 tempvp.font=FONT_UI;
328 tempvp.drawmode=STYLE_DEFAULT;
329 #if LCD_DEPTH > 1
330 tempvp.fg_pattern=0;
331 tempvp.bg_pattern=0xFFFF;
332 #ifdef HAVE_LCD_COLOR
333 tempvp.lss_pattern=0;
334 tempvp.lse_pattern=0;
335 tempvp.lst_pattern=0;
336 #endif
337 #endif
339 rb->screens[SCREEN_MAIN]->set_viewport(&tempvp);
340 rb->lcd_puts_scroll(0, 0, buf);
341 rb->screens[SCREEN_MAIN]->set_viewport(NULL);
343 y = LEGEND_Y(1);
345 reversi_gui_draw_cell(x, y+(LEGEND_Y(1)-LEGEND_Y(0))/2-CELL_WIDTH/2, WHITE);
346 rb->snprintf(buf, sizeof(buf), "%01d", r);
348 tempvp.y=y;
349 rb->screens[SCREEN_MAIN]->set_viewport(&tempvp);
350 rb->lcd_puts_scroll(0, 0, buf);
351 rb->screens[SCREEN_MAIN]->set_viewport(NULL);
353 /* Draw the box around the current player */
354 r = (cur_player == BLACK ? 0 : 1);
355 y = LEGEND_Y(r)+(LEGEND_Y(1)-LEGEND_Y(0))/2-CELL_WIDTH/2;
356 rb->lcd_drawrect(x, y, CELL_WIDTH+1, CELL_HEIGHT+1);
358 #if defined(HAVE_TOUCHSCREEN)
359 touchbutton_draw(reversi_buttons, TOUCHBUTTON_COUNT);
360 #endif
362 /* Update the screen */
363 rb->lcd_update();
368 * Menu related stuff
371 /* Menu entries and the corresponding values for cursor wrap mode */
372 #define MENU_TEXT_WRAP_MODE "Cursor wrap mode"
373 static const struct opt_items cursor_wrap_mode_settings[] = {
374 { "Flat board", -1 },
375 { "Sphere", -1 },
376 { "Torus", -1 },
378 static const cursor_wrap_mode_t cursor_wrap_mode_values[3] = {
379 WRAP_FLAT, WRAP_SPHERE, WRAP_TORUS };
382 /* Menu entries and the corresponding values for available strategies */
383 #define MENU_TEXT_STRAT_WHITE "Strategy for white"
384 #define MENU_TEXT_STRAT_BLACK "Strategy for black"
386 static struct opt_items strategy_settings[] = {
387 { "Human", -1 },
388 { "Naive robot", -1 },
389 { "Simple robot", -1 },
390 //{ "AB robot", -1 },
392 static const game_strategy_t * const strategy_values[] = {
393 &strategy_human, &strategy_naive, &strategy_simple, /*&strategy_ab*/ };
396 /* Sets the strategy for the specified player. 'player' is the
397 pointer to the player to set the strategy for (actually,
398 either white_strategy or black_strategy). propmpt is the
399 text to show as the prompt in the menu */
400 static bool reversi_gui_choose_strategy(
401 const game_strategy_t **player, const char *prompt) {
402 int index = 0, i;
403 int num_items = sizeof(strategy_settings)/sizeof(strategy_settings[0]);
404 bool result;
406 for (i = 0; i < num_items; i++) {
407 if ((*player) == strategy_values[i]) {
408 index = i;
409 break;
413 result =
414 rb->set_option(prompt, &index, INT, strategy_settings, num_items, NULL);
416 (*player) = strategy_values[index];
418 if((*player)->init_func)
419 (*player)->init_func(&game);
421 return result;
425 /* Returns true iff USB ws connected while in the menu */
426 static bool reversi_gui_menu(void) {
427 int index, num_items, i;
428 int result;
430 MENUITEM_STRINGLIST(menu, "Reversi Menu", NULL,
431 "Start new game", "Pass the move",
432 MENU_TEXT_STRAT_BLACK, MENU_TEXT_STRAT_WHITE,
433 MENU_TEXT_WRAP_MODE, "Playback Control", "Quit");
435 #ifdef HAVE_TOUCHSCREEN
436 /* Entering Menu, set the touchscreen to the global setting */
437 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
438 #endif
440 result = rb->do_menu(&menu, NULL, NULL, false);
442 switch (result) {
443 case 0: /* Start a new game */
444 reversi_gui_init();
445 break;
447 case 1: /* Pass the move to the partner */
448 cur_player = reversi_flipped_color(cur_player);
449 break;
451 case 2: /* Strategy for black */
452 reversi_gui_choose_strategy(&black_strategy, MENU_TEXT_STRAT_BLACK);
453 break;
455 case 3: /* Strategy for white */
456 reversi_gui_choose_strategy(&white_strategy, MENU_TEXT_STRAT_WHITE);
457 break;
459 case 4: /* Cursor wrap mode */
460 num_items = sizeof(cursor_wrap_mode_values) /
461 sizeof(cursor_wrap_mode_values[0]);
462 index = 0;
463 for (i = 0; i < num_items; i++) {
464 if (cursor_wrap_mode == cursor_wrap_mode_values[i]) {
465 index = i;
466 break;
469 rb->set_option(MENU_TEXT_WRAP_MODE, &index, INT,
470 cursor_wrap_mode_settings, 3, NULL);
471 cursor_wrap_mode = cursor_wrap_mode_values[index];
472 break;
474 case 5:
475 playback_control(NULL);
476 break;
478 case 6: /* Quit */
479 quit_plugin = true;
480 break;
483 #ifdef HAVE_TOUCHSCREEN
484 /* Leaving the menu, set back to pointer mode */
485 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
486 #endif
488 return (result == MENU_ATTACHED_USB);
492 /* Calculates the new cursor position if the user wants to move it
493 * vertically as specified by delta. Current wrap mode is respected.
494 * The cursor is not actually moved.
496 * Returns true iff the cursor would be really moved. In any case, the
497 * new cursor position is stored in (new_row, new_col).
499 static bool
500 reversi_gui_cursor_pos_vmove(int row_delta, int *new_row, int *new_col) {
501 *new_row = cur_row + row_delta;
502 *new_col = cur_col;
504 if (*new_row < 0) {
505 switch (cursor_wrap_mode) {
506 case WRAP_FLAT:
507 *new_row = cur_row;
508 break;
509 case WRAP_SPHERE:
510 *new_row = BOARD_SIZE - 1;
511 break;
512 case WRAP_TORUS:
513 *new_row = BOARD_SIZE - 1;
514 (*new_col)--;
515 if (*new_col < 0) {
516 *new_col = BOARD_SIZE - 1;
518 break;
520 } else if (*new_row >= BOARD_SIZE) {
521 switch (cursor_wrap_mode) {
522 case WRAP_FLAT:
523 *new_row = cur_row;
524 break;
525 case WRAP_SPHERE:
526 *new_row = 0;
527 break;
528 case WRAP_TORUS:
529 *new_row = 0;
530 (*new_col)++;
531 if (*new_col >= BOARD_SIZE) {
532 *new_col = 0;
534 break;
538 return (cur_row != (*new_row)) || (cur_col != (*new_col));
542 /* Calculates the new cursor position if the user wants to move it
543 * horisontally as specified by delta. Current wrap mode is respected.
544 * The cursor is not actually moved.
546 * Returns true iff the cursor would be really moved. In any case, the
547 * new cursor position is stored in (new_row, new_col).
549 static bool
550 reversi_gui_cursor_pos_hmove(int col_delta, int *new_row, int *new_col) {
551 *new_row = cur_row;
552 *new_col = cur_col + col_delta;
554 if (*new_col < 0) {
555 switch (cursor_wrap_mode) {
556 case WRAP_FLAT:
557 *new_col = cur_col;
558 break;
559 case WRAP_SPHERE:
560 *new_col = BOARD_SIZE - 1;
561 break;
562 case WRAP_TORUS:
563 *new_col = BOARD_SIZE - 1;
564 (*new_row)--;
565 if (*new_row < 0) {
566 *new_row = BOARD_SIZE - 1;
568 break;
570 } else if (*new_col >= BOARD_SIZE) {
571 switch (cursor_wrap_mode) {
572 case WRAP_FLAT:
573 *new_col = cur_col;
574 break;
575 case WRAP_SPHERE:
576 *new_col = 0;
577 break;
578 case WRAP_TORUS:
579 *new_col = 0;
580 (*new_row)++;
581 if (*new_row >= BOARD_SIZE) {
582 *new_row = 0;
584 break;
588 return (cur_row != (*new_row)) || (cur_col != (*new_col));
592 /* Actually moves the cursor to the new position and updates the screen */
593 static void reversi_gui_move_cursor(int new_row, int new_col) {
594 int old_row, old_col;
596 old_row = cur_row;
597 old_col = cur_col;
599 cur_row = new_row;
600 cur_col = new_col;
602 /* Only update the changed cells since there are no global changes */
603 reversi_gui_display_cursor(old_row, old_col);
604 reversi_gui_display_cursor(new_row, new_col);
608 /* plugin entry point */
609 enum plugin_status plugin_start(const void *parameter) {
610 bool exit, draw_screen;
611 int button;
612 #ifdef HAVE_TOUCHSCREEN
613 int button_x, button_y;
614 #endif
615 int lastbutton = BUTTON_NONE;
616 int row, col;
617 int w_cnt, b_cnt;
618 char msg_buf[30];
620 /* Initialize Font Width and height */
621 rb->lcd_getstringsize("0", &font_width, &font_height);
623 #ifdef HAVE_TOUCHSCREEN
624 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
625 #endif
627 #if LCD_DEPTH > 1
628 rb->lcd_set_backdrop(NULL);
629 rb->lcd_set_foreground(LCD_BLACK);
630 rb->lcd_set_background(LCD_WHITE);
631 #endif
633 /* Avoid compiler warnings */
634 (void)parameter;
636 rb->srand(*rb->current_tick); /* Some AIs use rand() */
637 white_strategy = &strategy_human;
638 black_strategy = &strategy_human;
640 reversi_gui_init();
641 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
642 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
643 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
644 cursor_wrap_mode = WRAP_TORUS;
645 #else
646 cursor_wrap_mode = WRAP_FLAT;
647 #endif
648 /* The main game loop */
649 exit = false;
650 quit_plugin = false;
651 draw_screen = true;
652 while (!exit && !quit_plugin) {
653 const game_strategy_t *cur_strategy = NULL;
654 if (draw_screen) {
655 reversi_gui_display_board();
656 draw_screen = false;
658 switch(cur_player) {
659 case BLACK:
660 cur_strategy = black_strategy;
661 break;
662 case WHITE:
663 cur_strategy = white_strategy;
664 break;
667 if(cur_strategy->is_robot && !game_finished) {
668 move_t m = cur_strategy->move_func(&game, cur_player);
669 reversi_make_move(&game, MOVE_ROW(m), MOVE_COL(m), cur_player);
670 cur_player = reversi_flipped_color(cur_player);
671 draw_screen = true;
672 /* TODO: Add some delay to prevent it from being too fast ? */
673 /* TODO: Don't duplicate end of game check */
674 if (reversi_game_is_finished(&game, cur_player)) {
675 reversi_count_occupied_cells(&game, &w_cnt, &b_cnt);
676 rb->snprintf(msg_buf, sizeof(msg_buf),
677 "Game over. %s won.",
678 (w_cnt>b_cnt?"WHITE":"BLACK"));
679 rb->splash(HZ*2, msg_buf);
680 draw_screen = true; /* Must update screen after splash */
681 game_finished = true;
683 continue;
686 /***********************************************************************
687 * Button handling code happens below here
688 **********************************************************************/
689 button = rb->button_get(true);
691 /* The touchscreen buttons can act as true buttons so OR them in */
692 #ifdef HAVE_TOUCHSCREEN
693 button |= touchbutton_get(reversi_buttons, button, TOUCHBUTTON_COUNT);
694 #endif
696 /* All of these button presses wait for the release event */
697 if(button&BUTTON_REL) {
698 #ifdef REVERSI_BUTTON_QUIT
699 if(button&REVERSI_BUTTON_QUIT) {
700 exit = true;
702 #endif
704 #ifdef HAVE_TOUCHSCREEN
705 if(button&BUTTON_TOUCHSCREEN) {
706 button_x = rb->button_get_data();
707 button_y = button_x & 0xffff;
708 button_x >>= 16;
710 /* Check if the click was in the gameboard, if so move cursor.
711 * This has to happen before MAKE_MOVE is processed.
713 if( (CELL_R(button_y)<BOARD_SIZE) &&
714 (CELL_C(button_x)<BOARD_SIZE) )
716 reversi_gui_move_cursor(CELL_R(button_y), CELL_C(button_x));
719 #endif
721 if( (button&REVERSI_BUTTON_MENU)
722 #if defined(REVERSI_BUTTON_MENU_LONGPRESS)
723 && (lastbutton&BUTTON_REPEAT)
724 #endif
726 if (reversi_gui_menu()) {
727 return PLUGIN_USB_CONNECTED;
729 draw_screen = true;
732 if(button&REVERSI_BUTTON_MAKE_MOVE
733 #if defined(REVERSI_BUTTON_MAKE_MOVE_SHORTPRESS)
734 && !(lastbutton&BUTTON_REPEAT)
735 #endif
737 /* If you touch the game board instead of hitting menu after it
738 * has completed the game will exit out.
740 if (game_finished)
741 break;
742 if (reversi_make_move(&game, cur_row, cur_col, cur_player) > 0) {
743 /* Move was made. Global changes on the board are possible */
744 draw_screen = true; /* Redraw the screen next time */
745 cur_player = reversi_flipped_color(cur_player);
746 if (reversi_game_is_finished(&game, cur_player)) {
747 reversi_count_occupied_cells(&game, &w_cnt, &b_cnt);
748 rb->snprintf(msg_buf, sizeof(msg_buf),
749 "Game over. %s won.",
750 (w_cnt>b_cnt?"WHITE":"BLACK"));
751 rb->splash(HZ*2, msg_buf);
752 draw_screen = true; /* Must update screen after splash */
753 game_finished = true;
755 } else {
756 /* An attempt to make an invalid move */
757 rb->splash(HZ/2, "Illegal move!");
758 draw_screen = true;
759 /* Ignore any button presses during the splash */
760 rb->button_clear_queue();
765 /* These button presses will run on a release or a repeat event */
766 if(button&BUTTON_REL || button&BUTTON_REPEAT) {
767 /* Move cursor left */
768 if(button&REVERSI_BUTTON_LEFT) {
769 if (reversi_gui_cursor_pos_hmove(-1, &row, &col)) {
770 reversi_gui_move_cursor(row, col);
773 /* Move cursor right */
774 if(button&REVERSI_BUTTON_RIGHT) {
775 if (reversi_gui_cursor_pos_hmove(1, &row, &col)) {
776 reversi_gui_move_cursor(row, col);
779 /* Move cursor up */
780 if(button&REVERSI_BUTTON_UP) {
781 if (reversi_gui_cursor_pos_vmove(-1, &row, &col)) {
782 reversi_gui_move_cursor(row, col);
785 /* Move cursor down */
786 if(button&REVERSI_BUTTON_DOWN) {
787 if (reversi_gui_cursor_pos_vmove(1, &row, &col)) {
788 reversi_gui_move_cursor(row, col);
793 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
794 /* Quit if USB has been connected */
795 return PLUGIN_USB_CONNECTED;
798 if (button != BUTTON_NONE) {
799 lastbutton = button;
803 return PLUGIN_OK;
806 #endif