1
/* This file is a part of gtkboard, a board games system.
2
Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net>
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
27
#define STOPGATE_CELL_SIZE 40
28
#define STOPGATE_NUM_PIECES 4
30
#define STOPGATE_BOARD_WID 9
31
#define STOPGATE_BOARD_HEIT 9
33
char stopgate_colors[6] = {180, 200, 180, 200, 140, 140};
35
static char * blue_gate_north_40_xpm [] =
82
static char * blue_gate_south_40_xpm [] =
129
static char * blue_gate_east_40_xpm [] =
148
" ..........................",
149
" ..........................",
150
" ..........................",
151
" ..........................",
152
" ..........................",
153
" ..........................",
154
" ..........................",
155
" ..........................",
156
" ..........................",
157
" ..........................",
158
" ..........................",
159
" ..........................",
176
static char * blue_gate_west_40_xpm [] =
195
".......................... ",
196
".......................... ",
197
".......................... ",
198
".......................... ",
199
".......................... ",
200
".......................... ",
201
".......................... ",
202
".......................... ",
203
".......................... ",
204
".......................... ",
205
".......................... ",
206
".......................... ",
224
char ** stopgate_pixmaps [] =
226
blue_gate_north_40_xpm,
227
blue_gate_south_40_xpm,
228
blue_gate_east_40_xpm,
229
blue_gate_west_40_xpm,
233
#define STOPGATE_NORTH 1
234
#define STOPGATE_SOUTH 2
235
#define STOPGATE_EAST 3
236
#define STOPGATE_WEST 4
237
#define STOPGATE_EMPTY 0
239
#define abs(x) ((x) < 0 ? -(x) : (x))
241
int stopgate_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
242
void stopgate_init ();
243
ResultType stopgate_who_won (Pos *, Player, char **);
244
ResultType stopgate_eval (Pos *, Player, float *eval);
245
byte * stopgate_movegen (Pos *);
247
Game Stopgate = { STOPGATE_CELL_SIZE, STOPGATE_BOARD_WID, STOPGATE_BOARD_HEIT,
249
stopgate_colors, NULL, stopgate_pixmaps, "Stopgate", "Nimlike games", stopgate_init};
251
static int stopgate_curx = - 1, stopgate_cury = -1;
254
void stopgate_init ()
256
game_getmove = stopgate_getmove;
257
game_who_won = stopgate_who_won;
258
game_eval = stopgate_eval;
259
game_movegen = stopgate_movegen;
260
game_white_string = "Vertical";
261
game_black_string = "Horizontally";
262
game_doc_about_status = STATUS_COMPLETE;
263
game_doc_rules = "Two players take turns in placing dominoes on the board. The first player places them vertically and the second horizontally. To place a domino, press the mouse button on a square, drag the mouse to the adjacent square and release the mouse button. The goal is to be the last player to place a domino; the game ends when it becomes obvious who the winner is.";
264
game_doc_strategy = "Make parallel columns of dominoes such that you will be able to play in between the columns but the opponent won't.";
267
static int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
268
static int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
270
ResultType stopgate_who_won (Pos *pos, Player player, char ** commp)
272
char *who_str[2] = {"Vertical won", "Horizontal won"};
273
int wscore, bscore, i, j;
276
result = stopgate_eval (pos, player, &eval);
277
if (result == RESULT_WHITE) *commp = who_str[0];
278
if (result == RESULT_BLACK) *commp = who_str[1];
282
#define EVAL_ISEMPTY(x, y) ((ISINBOARD((x), (y))) && (board[(y) * board_wid + (x)] == STOPGATE_EMPTY))
284
#define EVAL_OPENSQUARE(x, y) (EVAL_ISEMPTY ((x), (y)) && (EVAL_ISEMPTY ((x)-1,(y)) || EVAL_ISEMPTY ((x)+1, (y))) && (EVAL_ISEMPTY ((x),(y)-1) || EVAL_ISEMPTY ((x), (y)+1)))
287
REGION_WHITE = STOPGATE_NUM_PIECES + 1,
289
REGION_OPEN_X = 1 << 4,
290
REGION_OPEN_Y = 1 << 5,
295
static int regions[STOPGATE_BOARD_WID * STOPGATE_BOARD_HEIT];
297
/* Find which regions are open, which are vertical (REGION_WHITE) and which
298
are horizontal (REGION_BLACK)
299
clever algo that avoids a queue: every square in an open region must
300
be on a straight line from a square which has unfilled nbrs in both directions
302
static void find_regions (byte *board)
305
static int count = 0;
306
for (i=0; i<board_wid*board_heit; i++)
308
for (i=0; i < board_wid; i++)
309
for (j=0; j < board_heit; j++)
312
if (regions [j * board_wid + i] & REGION_OPEN_X)
314
if (EVAL_OPENSQUARE (i, j))
316
for (x=i; EVAL_ISEMPTY (x, j); x++)
317
regions [j * board_wid + x] |= REGION_OPEN_X;
318
for (x=i; EVAL_ISEMPTY (x, j); x--)
319
regions [j * board_wid + x] |= REGION_OPEN_X;
322
for (i=0; i < board_wid; i++)
323
for (j=0; j < board_heit; j++)
326
if (regions [j * board_wid + i] & REGION_OPEN_Y)
328
if (EVAL_OPENSQUARE (i, j))
330
for (y=j; EVAL_ISEMPTY (i, y); y++)
331
regions [y * board_wid + i] |= REGION_OPEN_Y;
332
for (y=j; EVAL_ISEMPTY (i, y); y--)
333
regions [y * board_wid + i] |= REGION_OPEN_Y;
336
for (i=0; i < board_wid; i++)
337
for (j=0; j < board_heit; j++)
338
if (board [j * board_wid + i] == 0 && regions[j * board_wid + i] == 0)
340
if (EVAL_ISEMPTY (i,j+1) || EVAL_ISEMPTY (i,j-1))
341
regions[j * board_wid + i] = REGION_WHITE;
342
else if (EVAL_ISEMPTY (i+1,j) || EVAL_ISEMPTY (i-1,j))
343
regions[j * board_wid + i] = REGION_BLACK;
345
// TODO: find the lengths of the runs also
349
byte * stopgate_movegen (Pos *pos)
352
byte movbuf [512], *movp = movbuf, *movlist;
353
byte *board = pos->board;
354
Player player = pos->player;
355
for (i=0; i<board_wid; i++)
356
for (j=0; j<board_heit; j++)
358
int incx = (player == WHITE ? 0 : 1), incy = (player == WHITE ? 1 : 0);
359
if (board [j * board_wid + i] != STOPGATE_EMPTY) continue;
360
if (!ISINBOARD (i + incx, j + incy)) continue;
361
if (pos->board [(j + incy) * board_wid + (i + incx)] != STOPGATE_EMPTY) continue;
362
if (!EVAL_OPENSQUARE (i, j) && !EVAL_OPENSQUARE (i + incx, j + incy))
366
*movp++ = (player == WHITE ? STOPGATE_NORTH : STOPGATE_EAST);
369
*movp++ = (player == WHITE ? STOPGATE_SOUTH : STOPGATE_WEST);
373
movlist = (byte *) (malloc (movp - movbuf));
374
memcpy (movlist, movbuf, (movp - movbuf));
379
ResultType stopgate_eval (Pos *pos, Player player, float *eval)
383
gboolean wfound = FALSE, bfound = FALSE, openfound = FALSE;
385
int run_eval_w = 0, run_eval_b = 0;
386
byte *board = pos->board;
387
find_regions (board);
388
for (i=0; i<board_wid; i++)
390
for (j=0; j<board_heit; j++)
391
if (regions[j * board_wid + i] == REGION_WHITE)
395
run_eval_w += 2 * (run_len / 2);
398
run_eval_w += 2 * (run_len / 2);
401
for (j=0; j<board_heit; j++)
403
for (i=0; i<board_wid; i++)
404
if (regions[j * board_wid + i] == REGION_BLACK)
408
run_eval_b += 2 * (run_len / 2);
411
run_eval_b += 2 * (run_len / 2);
414
val = run_eval_w - run_eval_b;
415
/* if (++count == 5000)
418
val = run_eval_w - run_eval_b;
419
printf ("%d, %d\n", run_eval_w, run_eval_b);
420
for (j=board_heit-1; j>=0; j--)
422
for (i=0; i<board_wid; i++)
424
if (board [j * board_wid + i])
426
else if (regions[j * board_wid + i] == REGION_WHITE)
428
else if (regions[j * board_wid + i] == REGION_BLACK)
437
for (i=0; i<board_wid; i++)
438
for (j=0; j<board_heit; j++)
440
if (board [j * board_wid + i] != STOPGATE_EMPTY) continue;
441
if (regions[j * board_wid + i] == REGION_WHITE)
443
else if (regions[j * board_wid + i] == REGION_BLACK)
447
if (EVAL_ISEMPTY (i, j+1) || EVAL_ISEMPTY (i, j-1))
453
if (EVAL_ISEMPTY (i+1, j) || EVAL_ISEMPTY (i-1, j))
463
val += (player == WHITE ? -1 : 1);
465
return val > 0 ? RESULT_WHITE : RESULT_BLACK;
467
if (player == WHITE && !wfound)
472
if (player == BLACK && !bfound)
477
*eval = val + 0.01 * random () / RAND_MAX;
478
return RESULT_NOTYET;
481
int stopgate_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play,
482
byte **movp, int **rmovp)
484
int i, j, sw_len, found=0;
485
static byte move[128];
487
int diffx, diffy, dir1 = -1, dir2 = -1;
488
if (type == GTKBOARD_BUTTON_PRESS)
490
if (pos->board [y * board_wid + x] != STOPGATE_EMPTY)
496
if (type != GTKBOARD_BUTTON_RELEASE)
498
if (stopgate_curx < 0) return -1;
499
diffx = x - stopgate_curx;
500
diffy = y - stopgate_cury;
501
if (to_play == WHITE && diffx == 0 && diffy == 1)
502
dir1 = STOPGATE_NORTH, dir2 = STOPGATE_SOUTH;
503
else if (to_play == WHITE && diffx == 0 && diffy == -1)
504
dir1 = STOPGATE_SOUTH, dir2 = STOPGATE_NORTH;
505
else if (to_play == BLACK && diffx == 1 && diffy == 0)
506
dir1 = STOPGATE_EAST, dir2 = STOPGATE_WEST;
507
else if (to_play == BLACK && diffx == -1 && diffy == 0)
508
dir1 = STOPGATE_WEST, dir2 = STOPGATE_EAST;
511
stopgate_curx = stopgate_cury = -1;
514
if (pos->board [y * board_wid + x] != STOPGATE_EMPTY)
516
stopgate_curx = stopgate_cury = -1;
519
*mp++ = stopgate_curx;
520
*mp++ = stopgate_cury;