summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Cellerier <dionoea@videolan.org>2007-06-30 20:04:42 +0000
committerAntoine Cellerier <dionoea@videolan.org>2007-06-30 20:04:42 +0000
commitb4b34f0c0723c29f368d7793889ef92bc6404a52 (patch)
tree0dfeb4a5b0a2a54f85a0deb227baafed92ae6549
parent9789acc3e04a8cd23fe0a2359a0fb8801ee7255e (diff)
downloadrockbox-b4b34f0c0723c29f368d7793889ef92bc6404a52.tar.gz
rockbox-b4b34f0c0723c29f368d7793889ef92bc6404a52.zip
FS #6509 - "Plugin for playing reversi game" by Alexander Levin + changes by me to make it compile due to the menu api change and compile for e200.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13745 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/SUBDIRS1
-rw-r--r--apps/plugins/reversi/Makefile111
-rw-r--r--apps/plugins/reversi/SOURCES3
-rw-r--r--apps/plugins/reversi/reversi-game.c370
-rw-r--r--apps/plugins/reversi/reversi-game.h75
-rw-r--r--apps/plugins/reversi/reversi-gui.c669
-rw-r--r--apps/plugins/reversi/reversi-gui.h117
-rw-r--r--apps/plugins/reversi/reversi-strategy.c59
-rw-r--r--apps/plugins/reversi/reversi-strategy.h44
9 files changed, 1449 insertions, 0 deletions
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index 5ac85a3115..6665f41e4e 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -12,6 +12,7 @@ rockboy
12#ifdef HAVE_LCD_BITMAP 12#ifdef HAVE_LCD_BITMAP
13chessbox 13chessbox
14sudoku 14sudoku
15reversi
15#endif 16#endif
16 17
17/* For all 2bpp and colour targets */ 18/* For all 2bpp and colour targets */
diff --git a/apps/plugins/reversi/Makefile b/apps/plugins/reversi/Makefile
new file mode 100644
index 0000000000..b008738335
--- /dev/null
+++ b/apps/plugins/reversi/Makefile
@@ -0,0 +1,111 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $$Id: $$
8#
9
10INCLUDES = -I$(APPSDIR) -I.. -I. $(TARGET_INC) -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
11 -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR) \
12 -I$(BUILDDIR)/pluginbitmaps
13CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET) $(EXTRA_DEFINES) \
14 -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN
15
16ifdef APPEXTRA
17 INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
18endif
19
20LINKFILE := $(OBJDIR)/link.lds
21DEPFILE = $(OBJDIR)/dep-reversi
22
23# This sets up 'SRC' based on the files mentioned in SOURCES
24include $(TOOLSDIR)/makesrc.inc
25
26SOURCES = $(SRC)
27OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
28DIRS = .
29
30ifndef SIMVER
31 LDS := ../plugin.lds
32 OUTPUT = $(OUTDIR)/reversi.rock
33else ## simulators
34 OUTPUT = $(OUTDIR)/reversi.rock
35endif
36
37all: $(OUTPUT)
38
39ifndef SIMVER
40$(OBJDIR)/reversi.elf: $(OBJS) $(LINKFILE) $(BITMAPLIBS)
41 $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \
42 $(LINKBITMAPS) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/reversi.map
43
44$(OUTPUT): $(OBJDIR)/reversi.elf
45 $(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@
46else
47
48ifeq ($(SIMVER), x11)
49###################################################
50# This is the X11 simulator version
51
52$(OUTPUT): $(OBJS)
53 $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@
54ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
55# 'x' must be kept or you'll have "Win32 error 5"
56# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
57# #define ERROR_ACCESS_DENIED 5L
58else
59 @chmod -x $@
60endif
61
62else # end of x11-simulator
63ifeq ($(SIMVER), sdl)
64###################################################
65# This is the SDL simulator version
66
67$(OUTPUT): $(OBJS)
68 $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -o $@
69ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
70# 'x' must be kept or you'll have "Win32 error 5"
71# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
72# #define ERROR_ACCESS_DENIED 5L
73else
74 @chmod -x $@
75endif
76
77else # end of sdl-simulator
78###################################################
79# This is the win32 simulator version
80DLLTOOLFLAGS = --export-all
81DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
82
83$(OUTPUT): $(OBJS)
84 $(call PRINTS,DLL $(@F))$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
85 $(SILENT)$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
86 $(BUILDDIR)/libplugin.a $(BITMAPLIBS) -o $@
87ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
88# 'x' must be kept or you'll have "Win32 error 5"
89# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
90# #define ERROR_ACCESS_DENIED 5L
91else
92 @chmod -x $@
93endif
94endif # end of win32-simulator
95endif
96endif # end of simulator section
97
98
99include $(TOOLSDIR)/make.inc
100
101# MEMORYSIZE should be passed on to this makefile with the chosen memory size
102# given in number of MB
103$(LINKFILE): $(LDS)
104 $(call PRINTS,build $(@F))cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \
105 $(DEFINES) -E -P - >$@
106
107clean:
108 $(call PRINTS,cleaning reversi)rm -rf $(OBJDIR)/reversi
109 $(SILENT)rm -f $(OBJDIR)/reversi.* $(DEPFILE)
110
111-include $(DEPFILE)
diff --git a/apps/plugins/reversi/SOURCES b/apps/plugins/reversi/SOURCES
new file mode 100644
index 0000000000..342e4d0e26
--- /dev/null
+++ b/apps/plugins/reversi/SOURCES
@@ -0,0 +1,3 @@
1reversi-game.c
2reversi-strategy.c
3reversi-gui.c
diff --git a/apps/plugins/reversi/reversi-game.c b/apps/plugins/reversi/reversi-game.c
new file mode 100644
index 0000000000..80893b7270
--- /dev/null
+++ b/apps/plugins/reversi/reversi-game.c
@@ -0,0 +1,370 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/*
21 * Reversi. Code is heavily based on othello code by Claudio Clemens which is
22 * copyright (c) 2003-2006 Claudio Clemens <asturio at gmx dot net> and is
23 * released under the GNU General Public License as published by the Free
24 * Software Foundation; either version 2, or (at your option) any later version.
25 */
26
27#include <stddef.h>
28#include "reversi-game.h"
29
30/*
31 * Constants for directions. The values are chosen so that
32 * they can be bit combined.
33 */
34#define DIR_UP 1 /* UP */
35#define DIR_DO 2 /* DOWN */
36#define DIR_LE 4 /* LEFT */
37#define DIR_RI 8 /* RIGHT */
38#define DIR_UL 16 /* UP LEFT */
39#define DIR_UR 32 /* UP RIGHT */
40#define DIR_DL 64 /* DOWN LEFT */
41#define DIR_DR 128 /* DOWN RIGHT */
42
43/* Array of directions for easy iteration through all of them */
44static int DIRECTIONS[] =
45 {DIR_UP, DIR_DO, DIR_LE, DIR_RI, DIR_UL, DIR_UR, DIR_DL, DIR_DR};
46#define NUM_OF_DIRECTIONS 8
47
48
49/* Initializes a reversi game */
50void reversi_init_game(reversi_board_t *game) {
51 int r, c;
52 for (r = 0; r < BOARD_SIZE; r++) {
53 for (c = 0; c < BOARD_SIZE; c++) {
54 game->board[r][c] = FREE;
55 }
56 }
57 game->board[3][3] = WHITE;
58 game->board[4][4] = WHITE;
59 game->board[3][4] = BLACK;
60 game->board[4][3] = BLACK;
61
62 /* Invalidate the history */
63 c = sizeof(game->history) / sizeof(game->history[0]);
64 for (r = 0; r < c; r++) {
65 game->history[r] = MOVE_INVALID;
66 }
67}
68
69
70/* Returns the 'flipped' color, e.g. WHITE for BLACK and vice versa */
71int reversi_flipped_color(const int color) {
72 switch (color) {
73 case WHITE:
74 return BLACK;
75
76 case BLACK:
77 return WHITE;
78
79 default:
80 return FREE;
81 }
82}
83
84
85/* Counts and returns the number of occupied cells on the board.
86 * If white_count and/or black_count is not null, the number of
87 * white/black stones is placed there. */
88int reversi_count_occupied_cells(const reversi_board_t *game,
89 int *white_count, int *black_count) {
90 int w_cnt, b_cnt, r, c;
91 w_cnt = b_cnt = 0;
92 for (r = 0; r < BOARD_SIZE; r++) {
93 for (c = 0; c < BOARD_SIZE; c++) {
94 if (game->board[r][c] == WHITE) {
95 w_cnt++;
96 } else if (game->board[r][c] == BLACK) {
97 b_cnt++;
98 }
99 }
100 }
101 if (white_count != NULL) {
102 *white_count = w_cnt;
103 }
104 if (black_count != NULL) {
105 *black_count = b_cnt;
106 }
107 return w_cnt + b_cnt;
108}
109
110
111/* Returns the number of free cells on the board */
112static int reversi_count_free_cells(const reversi_board_t *game) {
113 int cnt;
114 cnt = reversi_count_occupied_cells(game, NULL, NULL);
115 return BOARD_SIZE*BOARD_SIZE - cnt;
116}
117
118
119/* Checks whether the game is finished. That means that nobody
120 * can make a move. Note that the implementation is not correct
121 * as a game may be finished even if there are free cells
122 */
123bool reversi_game_is_finished(const reversi_board_t *game) {
124 return (reversi_count_free_cells(game) == 0);
125}
126
127
128/* Finds out who should place the next stone. It's the partner
129 * of the last move or WHITE if the game is just started.
130 *
131 * Returns WHITE or BLACK.
132 */
133int reversi_get_turn(const reversi_board_t *game) {
134 int moves;
135 moves = reversi_count_moves(game);
136 if (moves == 0) {
137 return WHITE;
138 } else {
139 return reversi_flipped_color(MOVE_PLAYER(game->history[moves-1]));
140 }
141}
142
143
144/* Returns the total number of moves made so far */
145int reversi_count_moves(const reversi_board_t *game) {
146 int cnt;
147 cnt = reversi_count_occupied_cells(game, NULL, NULL);
148 return cnt - INIT_STONES;
149}
150
151
152/* Returns the number of moves made by the specified
153 * player (WHITE or BLACK) so far
154 */
155static int reversi_count_player_moves(const reversi_board_t *game,
156 const int player) {
157 int moves, cnt, i;
158 moves = reversi_count_moves(game);
159 cnt = 0;
160 for (i = 0; i < moves; i++) {
161 if (MOVE_PLAYER(game->history[i]) == player) {
162 cnt++;
163 }
164 }
165 return cnt;
166}
167
168
169/* Returns the number of moves made by WHITE so far */
170int reversi_count_white_moves(const reversi_board_t *game) {
171 return reversi_count_player_moves(game, WHITE);
172}
173
174
175/* Returns the number of moves made by BLACK so far */
176int reversi_count_black_moves(const reversi_board_t *game) {
177 return reversi_count_player_moves(game, BLACK);
178}
179
180
181/* Checks whether the specified position is on the board
182 * (and not beyond)
183 */
184static bool reversi_is_position_on_board(const int row, const int col) {
185 return (row >= 0) && (row < BOARD_SIZE) &&
186 (col >= 0) && (col < BOARD_SIZE);
187}
188
189
190/* Returns the delta for row to move in the specified direction */
191static int reversi_row_delta(const int direction) {
192 switch (direction) {
193 case DIR_UP:
194 case DIR_UL:
195 case DIR_UR:
196 return -1;
197
198 case DIR_DO:
199 case DIR_DL:
200 case DIR_DR:
201 return 1;
202
203 default:
204 return 0;
205 }
206}
207
208
209/* Returns the delta for column to move in the specified direction */
210static int reversi_column_delta(const int direction) {
211 switch (direction) {
212 case DIR_LE:
213 case DIR_UL:
214 case DIR_DL:
215 return -1;
216
217 case DIR_RI:
218 case DIR_UR:
219 case DIR_DR:
220 return 1;
221
222 default:
223 return 0;
224 }
225}
226
227
228/* Checks if some stones would be captured in the specified direction
229 * if a stone were placed in the specified cell by the specified player.
230 *
231 * Returns 0 if no stones would be captured or 'direction' otherwise
232 */
233static int reversi_is_valid_direction(const reversi_board_t *game,
234 const int row, const int col, const int player, const int direction) {
235 int row_delta, col_delta, r, c;
236 int other_color;
237 int flip_cnt; /* Number of stones that would be flipped */
238
239 row_delta = reversi_row_delta(direction);
240 col_delta = reversi_column_delta(direction);
241 other_color = reversi_flipped_color(player);
242
243 r = row + row_delta;
244 c = col + col_delta;
245
246 flip_cnt = 0;
247 while (reversi_is_position_on_board(r, c) &&
248 (game->board[r][c] == other_color)) {
249 r += row_delta;
250 c += col_delta;
251 flip_cnt++;
252 }
253
254 if ((flip_cnt > 0) && reversi_is_position_on_board(r, c) &&
255 (game->board[r][c] == player)) {
256 return direction;
257 } else {
258 return 0;
259 }
260}
261
262
263/* Checks whether the move at the specified position would be valid.
264 * Params:
265 * - game: current state of the game
266 * - row: 0-based row number of the move in question
267 * - col: 0-based column number of the move in question
268 * - player: who is about to make the move (WHITE/BLACK)
269 *
270 * Checks if the place is empty, the coordinates are legal,
271 * and some stones can be captured.
272 *
273 * Returns 0 if the move is not valid or, otherwise, the or'd
274 * directions in which stones would be captured.
275 */
276static int reversi_is_valid_move(const reversi_board_t *game,
277 const int row, const int col, const int player) {
278 int dirs, i;
279 dirs = 0;
280
281 /* Check if coordinates are legal */
282 if (!reversi_is_position_on_board(row, col)) {
283 return dirs;
284 }
285
286 /* Check if the place is free */
287 if (game->board[row][col] != FREE) {
288 return dirs;
289 }
290
291 /* Check the directions of capture */
292 for (i = 0; i < NUM_OF_DIRECTIONS; i++) {
293 dirs |= reversi_is_valid_direction(game, row, col, player, DIRECTIONS[i]);
294 }
295
296 return dirs;
297}
298
299
300/* Flips the stones in the specified direction after the specified
301 * player has placed a stone in the specified cell. The move is
302 * assumed to be valid.
303 *
304 * Returns the number of flipped stones in that direction
305 */
306static int reversi_flip_stones(reversi_board_t *game,
307 const int row, const int col, const int player, const int direction) {
308 int row_delta, col_delta, r, c;
309 int other_color;
310 int flip_cnt; /* Number of stones flipped */
311
312 row_delta = reversi_row_delta(direction);
313 col_delta = reversi_column_delta(direction);
314 other_color = reversi_flipped_color(player);
315
316 r = row + row_delta;
317 c = col + col_delta;
318
319 flip_cnt = 0;
320 while (reversi_is_position_on_board(r, c) &&
321 (game->board[r][c] == other_color)) {
322 game->board[r][c] = player;
323 r += row_delta;
324 c += col_delta;
325 flip_cnt++;
326 }
327
328 return flip_cnt;
329}
330
331
332/* Tries to make a move (place a stone) at the specified position.
333 * If the move is valid the board is changed. Otherwise nothing happens.
334 *
335 * Params:
336 * - game: current state of the game
337 * - row: 0-based row number of the move to make
338 * - col: 0-based column number of the move to make
339 * - player: who makes the move (WHITE/BLACK)
340 *
341 * Returns the number of flipped (captured) stones (>0) iff the move
342 * was valid or 0 if the move was not valid. Note that in the case of
343 * a valid move, the stone itself is not counted.
344 */
345int reversi_make_move(reversi_board_t *game,
346 const int row, const int col, const int player) {
347 int dirs, cnt, i;
348
349 dirs = reversi_is_valid_move(game, row, col, player);
350 if (dirs == 0) {
351 return 0;
352 }
353
354 /* Place the stone into the cell */
355 game->board[row][col] = player;
356
357 /* Capture stones in all possible directions */
358 cnt = 0;
359 for (i = 0; i < NUM_OF_DIRECTIONS; i++) {
360 if (dirs & DIRECTIONS[i]) {
361 cnt += reversi_flip_stones(game, row, col, player, DIRECTIONS[i]);
362 }
363 }
364
365 /* Remember the move */
366 i = reversi_count_moves(game);
367 game->history[i-1] = MAKE_MOVE(row, col, player);
368
369 return cnt;
370}
diff --git a/apps/plugins/reversi/reversi-game.h b/apps/plugins/reversi/reversi-game.h
new file mode 100644
index 0000000000..a7d0329d1f
--- /dev/null
+++ b/apps/plugins/reversi/reversi-game.h
@@ -0,0 +1,75 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef _REVERSI_GAME_H
21#define _REVERSI_GAME_H
22
23#include <stdbool.h>
24
25#define WHITE 1 /* WHITE constant, it always plays first (as in chess) */
26#define BLACK 2 /* BLACK constant */
27#define FREE 0 /* Free place constant */
28
29#define BOARD_SIZE 8
30#define INIT_STONES 4
31
32/* Description of a move. A move is stored as a byte in the following format:
33 * - bit 7 : 0 for valid entries (i.e. those containing a move info,
34 * 1 for invalid entries
35 * - bits 6..4: row
36 * - bit 3 : 0 if it's white move, 1 if it's black move
37 * - bits 2..0: column
38 */
39typedef unsigned char move_t;
40
41#define MOVE_ROW(h) (((h) >> 4) & 0x7)
42#define MOVE_COL(h) ((h) & 0x7)
43#define MOVE_PLAYER(h) (((h) & 0x8) ? BLACK : WHITE)
44#define MAKE_MOVE(r,c,player) ( ((r)<<4) | ((c)&0x7) | \
45 ((player) == WHITE ? 0 : 0x8) )
46#define MOVE_INVALID 0x80
47
48
49/* State of a board */
50typedef struct _reversi_board_t {
51 /* The current state of the game (BLACK/WHITE/FREE) */
52 char board[BOARD_SIZE][BOARD_SIZE];
53
54 /* Game history. First move (mostly, but not necessarily, black) is stored
55 * in history[0], second move (mostly, but not necessarily, white) is
56 * stored in history[1] etc.
57 */
58 move_t history[BOARD_SIZE*BOARD_SIZE - INIT_STONES];
59} reversi_board_t;
60
61
62void reversi_init_game(reversi_board_t *game);
63int reversi_flipped_color(const int color);
64bool reversi_game_is_finished(const reversi_board_t *game);
65int reversi_get_turn(const reversi_board_t *game);
66int reversi_count_occupied_cells(const reversi_board_t *game,
67 int *white_count, int *black_count);
68int reversi_count_moves(const reversi_board_t *game);
69int reversi_count_white_moves(const reversi_board_t *game);
70int reversi_count_black_moves(const reversi_board_t *game);
71int reversi_make_move(reversi_board_t *game, const int row,
72 const int col, const int player);
73
74
75#endif
diff --git a/apps/plugins/reversi/reversi-gui.c b/apps/plugins/reversi/reversi-gui.c
new file mode 100644
index 0000000000..e543563729
--- /dev/null
+++ b/apps/plugins/reversi/reversi-gui.c
@@ -0,0 +1,669 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/*
21GUI part of reversi. Code is inspired by sudoku code by Dave Chapman
22which is copyright (c) 2005 Dave Chapman and is released under the
23GNU General Public License.
24
25
26User instructions
27-----------------
28
29Use the arrow keys to move cursor, and press TOGGLE to place a stone.
30
31At any time during the game, press MENU to bring up the game menu with
32further options:
33
34 - Save
35 - Reload
36 - Clear
37
38*/
39
40#include "plugin.h"
41
42#ifdef HAVE_LCD_BITMAP
43
44#include "reversi-game.h"
45#include "reversi-strategy.h"
46#include "reversi-gui.h"
47
48#include "../lib/oldmenuapi.h"
49
50PLUGIN_HEADER
51
52/* The global api struct pointer. While not strictly necessary,
53 it's nice not to have to pass the api pointer in all function
54 calls in the plugin */
55static struct plugin_api* rb;
56
57/* Thickness of the grid lines */
58#define LINE_THCK 1
59
60#if LCD_HEIGHT <= LCD_WIDTH /* Horizontal layout */
61
62#if (LCD_HEIGHT==64) && (LCD_WIDTH==112)
63/* Archos Recorders and Ondios - 112x64, 8 cells @ 8x6 with 9 border lines */
64
65/* Internal dimensions of a cell */
66#define CELL_WIDTH 8
67#define CELL_HEIGHT 6
68#define SMALL_BOARD
69
70#elif (LCD_HEIGHT==110) && (LCD_WIDTH==138)
71/* iPod Mini - 138x110, 8 cells @ 10x10 with 9 border lines */
72
73/* Internal dimensions of a cell */
74#define CELL_WIDTH 10
75#define CELL_HEIGHT 10
76
77#elif (LCD_HEIGHT==128) && (LCD_WIDTH==128)
78/* iriver H10 5-6GB - 128x128, 8 cells @ 10x10 with 9 border lines */
79
80/* Internal dimensions of a cell */
81#define CELL_WIDTH 10
82#define CELL_HEIGHT 10
83
84#elif ((LCD_HEIGHT==128) && (LCD_WIDTH==160)) || \
85 ((LCD_HEIGHT==132) && (LCD_WIDTH==176))
86/* iAudio X5, Iriver H1x0, iPod G3, G4 - 160x128; */
87/* iPod Nano - 176x132, 8 cells @ 12x12 with 9 border lines */
88
89/* Internal dimensions of a cell */
90#define CELL_WIDTH 12
91#define CELL_HEIGHT 12
92
93#elif ((LCD_HEIGHT==176) && (LCD_WIDTH==220)) || \
94 ((LCD_HEIGHT==220) && (LCD_WIDTH==176))
95/* Iriver h300, iPod Color/Photo - 220x176, 8 cells @ 16x16 with 9 border lines */
96
97/* Internal dimensions of a cell */
98#define CELL_WIDTH 16
99#define CELL_HEIGHT 16
100
101#elif (LCD_HEIGHT>=240) && (LCD_WIDTH>=320)
102/* iPod Video - 320x240, 8 cells @ 24x24 with 9 border lines */
103
104/* Internal dimensions of a cell */
105#define CELL_WIDTH 24
106#define CELL_HEIGHT 24
107
108#else
109 #error REVERSI: Unsupported LCD size
110#endif
111
112#else /* Vertical layout */
113#define VERTICAL_LAYOUT
114
115#if (LCD_HEIGHT>=320) && (LCD_WIDTH>=240)
116/* Gigabeat - 240x320, 8 cells @ 24x24 with 9 border lines */
117
118/* Internal dimensions of a cell */
119#define CELL_WIDTH 24
120#define CELL_HEIGHT 24
121
122#elif (LCD_HEIGHT>=220) && (LCD_WIDTH>=176)
123/* e200 - 176x220, 8 cells @ 12x12 with 9 border lines */
124
125/* Internal dimensions of a cell */
126#define CELL_WIDTH 18
127#define CELL_HEIGHT 18
128
129#else
130 #error REVERSI: Unsupported LCD size
131#endif
132
133#endif /* Layout */
134
135
136/* Where the board begins */
137#define XOFS 4
138#define YOFS 4
139
140/* Total width and height of the board without enclosing box */
141#define BOARD_WIDTH (CELL_WIDTH*BOARD_SIZE + LINE_THCK*(BOARD_SIZE+1))
142#define BOARD_HEIGHT (CELL_HEIGHT*BOARD_SIZE + LINE_THCK*(BOARD_SIZE+1))
143
144/* Thickness of the white cells' lines */
145#if (CELL_WIDTH >= 15) && (CELL_HEIGHT >= 15)
146#define CELL_LINE_THICKNESS 2
147#else
148#define CELL_LINE_THICKNESS 1
149#endif
150
151/* Margins within a cell */
152#if (CELL_WIDTH >= 10) && (CELL_HEIGHT >= 10)
153#define STONE_MARGIN 2
154#else
155#define STONE_MARGIN 1
156#endif
157
158#define CURSOR_MARGIN (STONE_MARGIN + CELL_LINE_THICKNESS)
159
160/* Upper left corner of a cell */
161#define CELL_X(c) (XOFS + (c)*CELL_WIDTH + ((c)+1)*LINE_THCK)
162#define CELL_Y(r) (YOFS + (r)*CELL_HEIGHT + ((r)+1)*LINE_THCK)
163
164
165#ifdef VERTICAL_LAYOUT
166#define LEGEND_X(lc) (CELL_X(lc))
167#define LEGEND_Y(lr) (CELL_Y(BOARD_SIZE+(lr)) + CELL_HEIGHT/2)
168#else
169#define LEGEND_X(lc) (CELL_X(BOARD_SIZE+(lc)) + CELL_WIDTH/2)
170#define LEGEND_Y(lr) (CELL_Y(lr))
171#endif
172
173
174/* Board state */
175static reversi_board_t game;
176
177/* --- Setting values --- */
178
179/* Playing strategies used by white and black players */
180const game_strategy_t *white_strategy;
181const game_strategy_t *black_strategy;
182
183/* Cursor position */
184static int cur_row, cur_col;
185
186/* Color for the next move (BLACK/WHITE) */
187static int cur_player;
188
189/* Active cursor wrapping mode */
190static cursor_wrap_mode_t cursor_wrap_mode;
191
192static bool quit_plugin;
193
194
195/* Initialises the state of the game (starts a new game) */
196static void reversi_gui_init(void) {
197 reversi_init_game(&game);
198 white_strategy = &strategy_human;
199 black_strategy = &strategy_human;
200 cur_player = BLACK;
201
202 /* Place the cursor so that WHITE can make a move */
203 cur_row = 2;
204 cur_col = 3;
205}
206
207
208/* Draws the cursor in the specified cell. Cursor is drawn in the complement
209 * mode, i.e. drawing it twice will result in no changes on the screen.
210 */
211static void reversi_gui_display_cursor(int row, int col) {
212 int old_mode, x, y;
213 old_mode = rb->lcd_get_drawmode();
214 x = CELL_X(col);
215 y = CELL_Y(row);
216
217 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
218 rb->lcd_drawline(x+CURSOR_MARGIN, y+CURSOR_MARGIN,
219 x+CELL_WIDTH-CURSOR_MARGIN-1, y+CELL_HEIGHT-CURSOR_MARGIN-1);
220 rb->lcd_drawline(x+CURSOR_MARGIN, y+CELL_HEIGHT-CURSOR_MARGIN-1,
221 x+CELL_WIDTH-CURSOR_MARGIN-1, y+CURSOR_MARGIN);
222
223 /* Draw the shadows */
224 rb->lcd_hline(x, x+CELL_WIDTH-1, YOFS-3);
225 rb->lcd_hline(x, x+CELL_WIDTH-1, YOFS+BOARD_HEIGHT+2);
226 rb->lcd_vline(XOFS-3, y, y+CELL_HEIGHT-1);
227 rb->lcd_vline(XOFS+BOARD_WIDTH+2, y, y+CELL_HEIGHT-1);
228
229 rb->lcd_set_drawmode(old_mode);
230 rb->lcd_update();
231}
232
233
234/* Draws the cell of the specified color (WHITE/BLACK) assuming that
235 * the upper left corner of the cell is at (x, y) */
236static void reversi_gui_draw_cell(int x, int y, int color) {
237 int i;
238 if (color == WHITE) {
239 for (i = 0; i < CELL_LINE_THICKNESS; i++) {
240 rb->lcd_drawrect(x+STONE_MARGIN+i, y+STONE_MARGIN+i,
241 CELL_WIDTH-2*(STONE_MARGIN+i), CELL_HEIGHT-2*(STONE_MARGIN+i));
242 }
243 } else if (color == BLACK) {
244 rb->lcd_fillrect(x+STONE_MARGIN, y+STONE_MARGIN,
245 CELL_WIDTH-2*STONE_MARGIN, CELL_HEIGHT-2*STONE_MARGIN);
246 } else {
247 /* Cell is free -> nothing to do */
248 }
249}
250
251
252/* Draws the complete screen */
253static void reversi_gui_display_board(void) {
254 int x, y, r, c, x_width, x_height;
255 char buf[8];
256
257 /* Clear the display buffer */
258 rb->lcd_clear_display();
259 rb->lcd_set_drawmode(DRMODE_FG);
260
261 /* Thicker board box */
262 rb->lcd_drawrect(XOFS-1, YOFS-1, BOARD_WIDTH+2, BOARD_HEIGHT+2);
263
264 /* Draw the gridlines */
265 for (r=0, x=XOFS, y=YOFS; r<=BOARD_SIZE;
266 r++, x+=CELL_WIDTH+LINE_THCK, y+=CELL_HEIGHT+LINE_THCK) {
267 rb->lcd_hline(XOFS, XOFS+BOARD_WIDTH-1, y);
268 rb->lcd_vline(x, YOFS, YOFS+BOARD_HEIGHT-1);
269 }
270
271 /* Draw the stones. This is not the most efficient way but more readable */
272 for (r=0; r<BOARD_SIZE; r++) {
273 y = CELL_Y(r);
274 for (c=0; c<BOARD_SIZE; c++) {
275 x = CELL_X(c);
276 reversi_gui_draw_cell(x, y, game.board[r][c]);
277 }
278 }
279
280 /* Draw the cursor */
281 reversi_gui_display_cursor(cur_row, cur_col);
282
283 /* Draw the current score */
284 reversi_count_occupied_cells(&game, &r, &c);
285 rb->lcd_getstringsize("x", &x_width, &x_height);
286
287 x = LEGEND_X(0);
288 y = LEGEND_Y(0);
289 reversi_gui_draw_cell(x, y, BLACK);
290 rb->snprintf(buf, sizeof(buf), "%d", c);
291 y += (CELL_HEIGHT-x_height) / 2;
292 rb->lcd_putsxy(x + CELL_WIDTH + CELL_WIDTH/2, y, buf);
293
294 y = LEGEND_Y(1);
295 reversi_gui_draw_cell(x, y, WHITE);
296 rb->snprintf(buf, sizeof(buf), "%d", r);
297 y += (CELL_HEIGHT-x_height) / 2;
298 rb->lcd_putsxy(x + CELL_WIDTH + CELL_WIDTH/2, y, buf);
299
300 /* Draw the box around the current player */
301 r = (cur_player == BLACK ? 0 : 1);
302 y = LEGEND_Y(r);
303 rb->lcd_drawrect(x-1, y-1, CELL_WIDTH+2, CELL_HEIGHT+2);
304
305 /* Update the screen */
306 rb->lcd_update();
307}
308
309
310/*
311 * Menu related stuff
312 */
313
314/* Menu entries and the corresponding values for cursor wrap mode */
315#define MENU_TEXT_WRAP_MODE "Cursor wrap mode"
316static const struct opt_items cursor_wrap_mode_settings[] = {
317 { "Flat board", NULL },
318 { "Sphere", NULL },
319 { "Torus", NULL },
320};
321static const cursor_wrap_mode_t cursor_wrap_mode_values[3] = {
322 WRAP_FLAT, WRAP_SPHERE, WRAP_TORUS };
323
324
325/* Menu entries and the corresponding values for available strategies */
326#define MENU_TEXT_STRAT_WHITE "Strategy for white"
327#define MENU_TEXT_STRAT_BLACK "Strategy for black"
328
329static struct opt_items strategy_settings[] = {
330 { "Human", NULL },
331 { "Silly robot", NULL },
332 { "Smart robot", NULL },
333};
334static const game_strategy_t * const strategy_values[] = {
335 &strategy_human, &strategy_novice, &strategy_expert };
336
337
338/* Sets the strategy for the specified player. 'player' is the
339 pointer to the player to set the strategy for (actually,
340 either white_strategy or black_strategy). propmpt is the
341 text to show as the prompt in the menu */
342static bool reversi_gui_choose_strategy(
343 const game_strategy_t **player, const char *prompt) {
344 int index = 0, i;
345 int num_items = sizeof(strategy_settings)/sizeof(strategy_settings[0]);
346 bool result;
347
348 for (i = 0; i < num_items; i++) {
349 if ((*player) == strategy_values[i]) {
350 index = i;
351 break;
352 }
353 }
354 result = rb->set_option(prompt, &index, INT, strategy_settings, num_items, NULL);
355 (*player) = strategy_values[index];
356
357 return result;
358}
359
360
361/* Returns true iff USB ws connected while in the menu */
362static bool reversi_gui_menu(void) {
363 int m, index, num_items, i;
364 int result;
365
366 static const struct menu_item items[] = {
367 { "Start new game", NULL },
368 { "Pass the move", NULL },
369 { MENU_TEXT_STRAT_BLACK, NULL },
370 { MENU_TEXT_STRAT_WHITE, NULL },
371 { MENU_TEXT_WRAP_MODE, NULL },
372 { "Quit", NULL },
373 };
374
375 m = menu_init(rb, items, sizeof(items) / sizeof(*items),
376 NULL, NULL, NULL, NULL);
377
378 result = menu_show(m);
379
380 switch (result) {
381 case 0: /* Start a new game */
382 reversi_gui_init();
383 break;
384
385 case 1: /* Pass the move to the partner */
386 cur_player = reversi_flipped_color(cur_player);
387 break;
388
389 case 2: /* Strategy for black */
390 reversi_gui_choose_strategy(&black_strategy, MENU_TEXT_STRAT_BLACK);
391 break;
392
393 case 3: /* Strategy for white */
394 reversi_gui_choose_strategy(&white_strategy, MENU_TEXT_STRAT_WHITE);
395 break;
396
397 case 4: /* Cursor wrap mode */
398 num_items = sizeof(cursor_wrap_mode_values)/sizeof(cursor_wrap_mode_values[0]);
399 index = 0;
400 for (i = 0; i < num_items; i++) {
401 if (cursor_wrap_mode == cursor_wrap_mode_values[i]) {
402 index = i;
403 break;
404 }
405 }
406 rb->set_option(MENU_TEXT_WRAP_MODE, &index, INT,
407 cursor_wrap_mode_settings, 3, NULL);
408 cursor_wrap_mode = cursor_wrap_mode_values[index];
409 break;
410
411 case 5: /* Quit */
412 quit_plugin = true;
413 break;
414 }
415
416 menu_exit(m);
417
418 return (result == MENU_ATTACHED_USB);
419}
420
421
422/* Calculates the new cursor position if the user wants to move it
423 * vertically as specified by delta. Current wrap mode is respected.
424 * The cursor is not actually moved.
425 *
426 * Returns true iff the cursor would be really moved. In any case, the
427 * new cursor position is stored in (new_row, new_col).
428 */
429static bool reversi_gui_cursor_pos_vmove(int row_delta, int *new_row, int *new_col) {
430 *new_row = cur_row + row_delta;
431 *new_col = cur_col;
432
433 if (*new_row < 0) {
434 switch (cursor_wrap_mode) {
435 case WRAP_FLAT:
436 *new_row = cur_row;
437 break;
438 case WRAP_SPHERE:
439 *new_row = BOARD_SIZE - 1;
440 break;
441 case WRAP_TORUS:
442 *new_row = BOARD_SIZE - 1;
443 (*new_col)--;
444 if (*new_col < 0) {
445 *new_col = BOARD_SIZE - 1;
446 }
447 break;
448 }
449 } else if (*new_row >= BOARD_SIZE) {
450 switch (cursor_wrap_mode) {
451 case WRAP_FLAT:
452 *new_row = cur_row;
453 break;
454 case WRAP_SPHERE:
455 *new_row = 0;
456 break;
457 case WRAP_TORUS:
458 *new_row = 0;
459 (*new_col)++;
460 if (*new_col >= BOARD_SIZE) {
461 *new_col = 0;
462 }
463 break;
464 }
465 }
466
467 return (cur_row != (*new_row)) || (cur_col != (*new_col));
468}
469
470
471/* Calculates the new cursor position if the user wants to move it
472 * horisontally as specified by delta. Current wrap mode is respected.
473 * The cursor is not actually moved.
474 *
475 * Returns true iff the cursor would be really moved. In any case, the
476 * new cursor position is stored in (new_row, new_col).
477 */
478static bool reversi_gui_cursor_pos_hmove(int col_delta, int *new_row, int *new_col) {
479 *new_row = cur_row;
480 *new_col = cur_col + col_delta;
481
482 if (*new_col < 0) {
483 switch (cursor_wrap_mode) {
484 case WRAP_FLAT:
485 *new_col = cur_col;
486 break;
487 case WRAP_SPHERE:
488 *new_col = BOARD_SIZE - 1;
489 break;
490 case WRAP_TORUS:
491 *new_col = BOARD_SIZE - 1;
492 (*new_row)--;
493 if (*new_row < 0) {
494 *new_row = BOARD_SIZE - 1;
495 }
496 break;
497 }
498 } else if (*new_col >= BOARD_SIZE) {
499 switch (cursor_wrap_mode) {
500 case WRAP_FLAT:
501 *new_col = cur_col;
502 break;
503 case WRAP_SPHERE:
504 *new_col = 0;
505 break;
506 case WRAP_TORUS:
507 *new_col = 0;
508 (*new_row)++;
509 if (*new_row >= BOARD_SIZE) {
510 *new_row = 0;
511 }
512 break;
513 }
514 }
515
516 return (cur_row != (*new_row)) || (cur_col != (*new_col));
517}
518
519
520/* Actually moves the cursor to the new position and updates the screen */
521static void reversi_gui_move_cursor(int new_row, int new_col) {
522 int old_row, old_col;
523
524 old_row = cur_row;
525 old_col = cur_col;
526
527 cur_row = new_row;
528 cur_col = new_col;
529
530 /* Only update the changed cells since there are no global changes */
531 reversi_gui_display_cursor(old_row, old_col);
532 reversi_gui_display_cursor(new_row, new_col);
533}
534
535
536/* plugin entry point */
537enum plugin_status plugin_start(struct plugin_api *api, void *parameter) {
538 bool exit, draw_screen;
539 int button;
540 int lastbutton = BUTTON_NONE;
541 int row, col;
542 int w_cnt, b_cnt;
543 char msg_buf[30];
544
545 /* plugin init */
546 rb = api;
547 /* end of plugin init */
548
549#if LCD_DEPTH > 1
550 rb->lcd_set_backdrop(NULL);
551 rb->lcd_set_foreground(LCD_BLACK);
552 rb->lcd_set_background(LCD_WHITE);
553#endif
554
555 /* Avoid compiler warnings */
556 (void)parameter;
557
558 reversi_gui_init();
559 cursor_wrap_mode = WRAP_FLAT;
560
561 /* The main game loop */
562 exit = false;
563 quit_plugin = false;
564 draw_screen = true;
565 while (!exit && !quit_plugin) {
566 if (draw_screen) {
567 reversi_gui_display_board();
568 draw_screen = false;
569 }
570 button = rb->button_get(true);
571
572 switch (button) {
573#ifdef REVERSI_BUTTON_QUIT
574 /* Exit game */
575 case REVERSI_BUTTON_QUIT:
576 exit = true;
577 break;
578#endif
579
580#ifdef REVERSI_BUTTON_ALT_MAKE_MOVE
581 case REVERSI_BUTTON_ALT_MAKE_MOVE:
582#endif
583 case REVERSI_BUTTON_MAKE_MOVE:
584#ifdef REVERSI_BUTTON_MAKE_MOVE_PRE
585 if ((button == REVERSI_BUTTON_MAKE_MOVE)
586 && (lastbutton != REVERSI_BUTTON_MAKE_MOVE_PRE))
587 break;
588#endif
589 if (reversi_make_move(&game, cur_row, cur_col, cur_player) > 0) {
590 /* Move was made. Global changes on the board are possible */
591 draw_screen = true; /* Redraw the screen next time */
592 cur_player = reversi_flipped_color(cur_player);
593 if (reversi_game_is_finished(&game)) {
594 reversi_count_occupied_cells(&game, &w_cnt, &b_cnt);
595 rb->snprintf(msg_buf, sizeof(msg_buf),
596 "Game over. %s have won.",
597 (w_cnt>b_cnt?"WHITE":"BLACK"));
598 rb->splash(HZ*2, msg_buf);
599 draw_screen = true; /* Must update screen after splash */
600 }
601 } else {
602 /* An attempt to make an invalid move */
603 rb->splash(HZ/2, "Illegal move!");
604 draw_screen = true;
605 /* Ignore any button presses during the splash */
606 rb->button_clear_queue();
607 }
608 break;
609
610 /* Move cursor left */
611 case REVERSI_BUTTON_LEFT:
612 case (REVERSI_BUTTON_LEFT | BUTTON_REPEAT):
613 if (reversi_gui_cursor_pos_hmove(-1, &row, &col)) {
614 reversi_gui_move_cursor(row, col);
615 }
616 break;
617
618 /* Move cursor right */
619 case REVERSI_BUTTON_RIGHT:
620 case (REVERSI_BUTTON_RIGHT | BUTTON_REPEAT):
621 if (reversi_gui_cursor_pos_hmove(1, &row, &col)) {
622 reversi_gui_move_cursor(row, col);
623 }
624 break;
625
626 /* Move cursor up */
627 case REVERSI_BUTTON_UP:
628 case (REVERSI_BUTTON_UP | BUTTON_REPEAT):
629 if (reversi_gui_cursor_pos_vmove(-1, &row, &col)) {
630 reversi_gui_move_cursor(row, col);
631 }
632 break;
633
634 /* Move cursor down */
635 case REVERSI_BUTTON_DOWN:
636 case (REVERSI_BUTTON_DOWN | BUTTON_REPEAT):
637 if (reversi_gui_cursor_pos_vmove(1, &row, &col)) {
638 reversi_gui_move_cursor(row, col);
639 }
640 break;
641
642 case REVERSI_BUTTON_MENU:
643#ifdef REVERSI_BUTTON_MENU_PRE
644 if (lastbutton != REVERSI_BUTTON_MENU_PRE) {
645 break;
646 }
647#endif
648 if (reversi_gui_menu()) {
649 return PLUGIN_USB_CONNECTED;
650 }
651 draw_screen = true;
652 break;
653
654 default:
655 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
656 /* Quit if USB has been connected */
657 return PLUGIN_USB_CONNECTED;
658 }
659 break;
660 }
661 if (button != BUTTON_NONE) {
662 lastbutton = button;
663 }
664 }
665
666 return PLUGIN_OK;
667}
668
669#endif
diff --git a/apps/plugins/reversi/reversi-gui.h b/apps/plugins/reversi/reversi-gui.h
new file mode 100644
index 0000000000..61168e7034
--- /dev/null
+++ b/apps/plugins/reversi/reversi-gui.h
@@ -0,0 +1,117 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef _REVERSI_GUI_H
21#define _REVERSI_GUI_H
22
23#include "plugin.h"
24
25#define GAME_FILE PLUGIN_DIR "/reversi.rev"
26
27/* variable button definitions */
28#if CONFIG_KEYPAD == RECORDER_PAD
29#define REVERSI_BUTTON_QUIT BUTTON_OFF
30#define REVERSI_BUTTON_UP BUTTON_UP
31#define REVERSI_BUTTON_DOWN BUTTON_DOWN
32#define REVERSI_BUTTON_LEFT BUTTON_LEFT
33#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
34#define REVERSI_BUTTON_MAKE_MOVE BUTTON_PLAY
35#define REVERSI_BUTTON_MENU BUTTON_F1
36
37#elif CONFIG_KEYPAD == ONDIO_PAD
38#define REVERSI_BUTTON_QUIT BUTTON_OFF
39#define REVERSI_BUTTON_UP BUTTON_UP
40#define REVERSI_BUTTON_DOWN BUTTON_DOWN
41#define REVERSI_BUTTON_LEFT BUTTON_LEFT
42#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
43#define REVERSI_BUTTON_MAKE_MOVE_PRE BUTTON_MENU
44#define REVERSI_BUTTON_MAKE_MOVE (BUTTON_MENU | BUTTON_REL)
45#define REVERSI_BUTTON_ALT_MAKE_MOVE (BUTTON_MENU | BUTTON_DOWN)
46#define REVERSI_BUTTON_MENU_PRE BUTTON_MENU
47#define REVERSI_BUTTON_MENU (BUTTON_MENU | BUTTON_REPEAT)
48
49#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
50 (CONFIG_KEYPAD == IRIVER_H300_PAD)
51#define REVERSI_BUTTON_QUIT BUTTON_OFF
52#define REVERSI_BUTTON_UP BUTTON_UP
53#define REVERSI_BUTTON_DOWN BUTTON_DOWN
54#define REVERSI_BUTTON_LEFT BUTTON_LEFT
55#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
56#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
57#define REVERSI_BUTTON_MENU BUTTON_MODE
58
59#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
60 (CONFIG_KEYPAD == IPOD_3G_PAD)
61#define REVERSI_BUTTON_UP BUTTON_SCROLL_BACK
62#define REVERSI_BUTTON_DOWN BUTTON_SCROLL_FWD
63#define REVERSI_BUTTON_LEFT BUTTON_LEFT
64#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
65#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
66#define REVERSI_BUTTON_MENU BUTTON_MENU
67
68#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
69#define REVERSI_BUTTON_QUIT BUTTON_POWER
70#define REVERSI_BUTTON_UP BUTTON_UP
71#define REVERSI_BUTTON_DOWN BUTTON_DOWN
72#define REVERSI_BUTTON_LEFT BUTTON_LEFT
73#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
74#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
75#define REVERSI_BUTTON_MENU BUTTON_PLAY
76
77#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
78#define REVERSI_BUTTON_QUIT BUTTON_A
79#define REVERSI_BUTTON_UP BUTTON_UP
80#define REVERSI_BUTTON_DOWN BUTTON_DOWN
81#define REVERSI_BUTTON_LEFT BUTTON_LEFT
82#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
83#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
84#define REVERSI_BUTTON_MENU BUTTON_MENU
85
86#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
87#define REVERSI_BUTTON_QUIT BUTTON_POWER
88#define REVERSI_BUTTON_UP BUTTON_SCROLL_UP
89#define REVERSI_BUTTON_DOWN BUTTON_SCROLL_DOWN
90#define REVERSI_BUTTON_LEFT BUTTON_LEFT
91#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
92#define REVERSI_BUTTON_MAKE_MOVE BUTTON_REW
93#define REVERSI_BUTTON_MENU BUTTON_PLAY
94
95#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
96#define REVERSI_BUTTON_QUIT BUTTON_POWER
97#define REVERSI_BUTTON_UP BUTTON_UP
98#define REVERSI_BUTTON_DOWN BUTTON_DOWN
99#define REVERSI_BUTTON_LEFT BUTTON_LEFT
100#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
101#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
102#define REVERSI_BUTTON_MENU (BUTTON_SELECT|BUTTON_REPEAT)
103
104#elif
105 #error REVERSI: Unsupported keypad
106#endif
107
108
109/* Modes for the cursor behaviour at the board edges */
110typedef enum _cursor_wrap_mode_t {
111 WRAP_FLAT, /* No wrapping */
112 WRAP_SPHERE, /* (7,7) > right > (7,0); (7,7) > down > (0,7) */
113 WRAP_TORUS, /* (7,7) > right > (0,0); (7,7) > down > (0,0) */
114} cursor_wrap_mode_t;
115
116
117#endif
diff --git a/apps/plugins/reversi/reversi-strategy.c b/apps/plugins/reversi/reversi-strategy.c
new file mode 100644
index 0000000000..831c0cd92b
--- /dev/null
+++ b/apps/plugins/reversi/reversi-strategy.c
@@ -0,0 +1,59 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "reversi-strategy.h"
21#include <stddef.h>
22
23
24/* Implementation of a rather weak player strategy */
25static move_t novice_move_func(const reversi_board_t *game, int color) {
26 /* TODO: Implement novice_move_func */
27 (void)game;
28 (void)color;
29 return MOVE_INVALID;
30}
31
32
33/* Implementation of a good player strategy */
34static move_t expert_move_func(const reversi_board_t *game, int color) {
35 /* TODO: Implement expert_move_func */
36 (void)game;
37 (void)color;
38 return MOVE_INVALID;
39}
40
41
42
43/* Strategy that requires interaction with the user */
44const game_strategy_t strategy_human = {
45 false,
46 NULL
47};
48
49/* Robot that plays not very well (novice) */
50const game_strategy_t strategy_novice = {
51 true,
52 novice_move_func
53};
54
55/* Robot that is hard to beat (expert) */
56const game_strategy_t strategy_expert = {
57 true,
58 expert_move_func
59};
diff --git a/apps/plugins/reversi/reversi-strategy.h b/apps/plugins/reversi/reversi-strategy.h
new file mode 100644
index 0000000000..57bc3faf57
--- /dev/null
+++ b/apps/plugins/reversi/reversi-strategy.h
@@ -0,0 +1,44 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2006 Alexander Levin
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef _REVERSI_STRATEGY_H
21#define _REVERSI_STRATEGY_H
22
23#include "reversi-game.h"
24
25
26/* Function for making a move. Is called only for robots.
27 Should return the game history entry for the advised move if
28 a move has been considered or HISTORY_INVALID_ENTRY if no move
29 has been considered. The board should not be modified. */
30typedef move_t (*move_func_t)(const reversi_board_t *game, int color);
31
32/* A playing party/strategy */
33typedef struct _game_strategy_t {
34 const bool is_robot; /* Is the player a robot or does it require user input? */
35 move_func_t move_func; /* Function for advicing a move */
36} game_strategy_t;
37
38
39/* --- Possible playing strategies --- */
40extern const game_strategy_t strategy_human;
41extern const game_strategy_t strategy_novice;
42extern const game_strategy_t strategy_expert;
43
44#endif