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 DNB_CELL_SIZE 24
28
#define DNB_NUM_PIECES 5
30
#define DNB_BOARD_SIZE 10
32
#define DNB_BOARD_WID (2*DNB_BOARD_SIZE+1)
33
#define DNB_BOARD_HEIT (2*DNB_BOARD_SIZE+1)
35
char dnb_colors[6] = {220, 220, 220, 220, 220, 220};
37
static char * dnb_red_24_xpm [] =
67
static char * dnb_blue_24_xpm [] =
97
static char * dnb_vertical_24_xpm [] =
128
static char * dnb_horizontal_24_xpm [] =
142
"........................",
143
"........................",
144
"........................",
145
"........................",
146
"........................",
147
"........................",
160
/*char ** dnb_pixmaps [] =
162
blue_gate_horiz_40_xpm,
163
blue_gate_south_40_xpm,
164
blue_gate_east_40_xpm,
165
blue_gate_west_40_xpm,
176
#define abs(x) ((x) < 0 ? -(x) : (x))
178
int dnb_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
179
void dnb_search (Pos *pos, byte **movp);
181
ResultType dnb_who_won (Pos *, Player, char **);
182
void dnb_set_init_pos (Pos *pos);
183
char ** dnb_get_pixmap (int idx, int color);
184
int dnb_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play,
185
byte **movp, int **rmovp);
186
static void dnb_get_render (Pos *pos, byte *move, int **rmovp);
188
Game Dnb = { DNB_CELL_SIZE, DNB_BOARD_WID, DNB_BOARD_HEIT,
189
DNB_NUM_PIECES, dnb_colors, NULL, NULL, "Dots and Boxes", "Nimlike games", dnb_init};
191
static int dnb_curx = - 1, dnb_cury = -1;
196
// game_getmove = dnb_getmove;
197
/* game_who_won = dnb_who_won;
198
game_eval = dnb_eval;
199
game_movegen = dnb_movegen;
201
game_set_init_pos = dnb_set_init_pos;
202
game_get_pixmap = dnb_get_pixmap;
203
game_get_render = dnb_get_render;
204
game_white_string = "Red";
205
game_black_string = "Blue";
206
game_getmove = dnb_getmove;
207
game_search = dnb_search;
208
game_allow_flip = TRUE;
209
game_doc_about_status = STATUS_UNPLAYABLE;
213
"Status: partially implemented (the AI is totally dumb)\n"
214
"URL: "GAME_DEFAULT_URL ("dnb");
217
char ** dnb_get_pixmap (int idx, int color)
220
char *colors = dnb_colors;
221
static char pixbuf[DNB_CELL_SIZE * (DNB_CELL_SIZE+1)];
222
if (color == BLACK) colors += 3;
223
for(i=0, bg=0;i<3;i++)
224
{ int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));}
226
return pixmap_ball_gen (DNB_CELL_SIZE, pixbuf, 0x101010, bg, 8, 30);
227
if (idx == DNB_VERT) return dnb_vertical_24_xpm;
228
if (idx == DNB_HOR) return dnb_horizontal_24_xpm;
229
if (idx == DNB_RED) return dnb_red_24_xpm;
230
if (idx == DNB_BLUE) return dnb_blue_24_xpm;
234
void dnb_set_init_pos (Pos *pos)
237
for (i=0; i<board_wid; i++)
238
for (j=0; j<board_heit; j++)
239
if (i%2 == 0 && j%2 == 0)
240
pos->board[j * board_wid + i] = DNB_DOT;
242
pos->board[j * board_wid + i] = DNB_EMPTY;
246
ResultType dnb_who_won (Pos *pos, Player player, char ** commp)
248
char *who_str[2] = {"Vertical won", "Horizontal won"};
249
int wscore, bscore, i, j;
252
result = dnb_eval (pos, player, &eval);
253
if (result == RESULT_WHITE) *commp = who_str[0];
254
if (result == RESULT_BLACK) *commp = who_str[1];
255
printf ("%f\n", eval);
260
static int dnb_incx[] = {-1, 0, 0, 1};
261
static int dnb_incy[] = {0, -1, 1, 0};
263
static int num_nbr_walls (byte *board, int *render, int x, int y)
267
if (x % 2 == 0 || y % 2 == 0)
269
for (k=0, count=0; k<4; k++)
271
newx = x + dnb_incx[k];
272
newy = y + dnb_incy[k];
273
if (board [newy * board_wid + newx] != DNB_EMPTY ||
274
(render && render[newy * board_wid + newx] != RENDER_NONE))
280
int dnb_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player player,
281
byte **movp, int **rmovp)
285
static byte move[2048];
286
static int rmove[16];
292
if (type == GTKBOARD_BUTTON_PRESS)
294
if (pos->board [y * board_wid + x] != DNB_DOT)
301
if (type != GTKBOARD_BUTTON_RELEASE)
304
if (dnb_curx < 0) return -1;
306
if ((x != dnb_curx && y != dnb_cury) || (x == dnb_curx && y == dnb_cury))
307
{ dnb_curx = dnb_cury = -1; return -1; }
312
incy = y > dnb_cury ? 1 : -1;
317
incx = x > dnb_curx ? 1 : -1;
320
newx = dnb_curx + incx;
321
newy = dnb_cury + incy;
322
if (pos->board [newy * board_wid + newx] != DNB_EMPTY ||
323
pos->render [newy * board_wid + newx] != RENDER_NONE)
324
{ dnb_curx = dnb_cury = -1; return -1; }
328
*rp++ = RENDER_REPLACE | ((dnb_curx == x ? DNB_VERT : DNB_HOR) << 8);
329
dnb_curx = dnb_cury = -1;
331
// do we complete a square
335
x = newx + dnb_incx[k];
336
y = newy + dnb_incy[k];
337
if (pos->board [y * board_wid + x] == DNB_EMPTY)
338
if (num_nbr_walls (pos->board, pos->render, x, y) == 3)
342
*rp++ = RENDER_REPLACE | ((player == WHITE ? DNB_RED : DNB_BLUE) << 8);
355
for (i=0; rmove[3*i] >= 0; i++)
356
if ((rmove [3*i+2] & 0xff) == RENDER_REPLACE)
359
*mp++ = rmove [3*i+1];
360
*mp++ = rmove [3*i+2] >> 8;
362
for (i=0; i<board_wid; i++)
363
for (j=0; j<board_heit; j++)
364
if ((pos->render [j * board_wid + i] & 0xff) == RENDER_REPLACE)
368
*mp++ = pos->render [j * board_wid + i] >> 8;
376
static void dnb_get_render (Pos *pos, byte *move, int **rmovp)
378
static int rmove[2048];
381
for (i=0; i<board_wid; i++)
382
for (j=0; j<board_heit; j++)
383
if (pos->render [j * board_wid + i] != RENDER_NONE)
394
void dnb_search (Pos *pos, byte **movp)
396
/* first greedily close all possible squares, then choose some edge arbitrarily */
397
// TODO: this AI needs MAJOR improvement
398
static byte move[2048];
402
static byte newboard[DNB_BOARD_WID * DNB_BOARD_HEIT];
403
Player player = pos->player;
404
memcpy (newboard, pos->board, board_wid * board_heit);
406
do // very slow, but speed probably doesn't matter here
409
for (i=1; i<board_wid; i+=2)
410
for (j=1; j<board_heit; j+=2)
411
if (num_nbr_walls (newboard, NULL, i, j) == 3)
413
int k, newx, newy, newval;
416
newx = i + dnb_incx[k];
417
newy = j + dnb_incy[k];
418
if (newboard [newy * board_wid + newx] == DNB_EMPTY)
420
newval = (newx % 2 == 0 ? DNB_VERT : DNB_HOR);
424
newboard [newy * board_wid + newx] = newval;
427
newval = (player == WHITE ? DNB_RED : DNB_BLUE);
431
newboard [j * board_wid + i] = newval;
436
while (1) // FIXME: inf. loop when game is over
438
i = random() % board_wid;
439
j = random() % board_heit;
440
if ((i+j) % 2 == 0) continue;
441
if (newboard [j * board_wid + i] != DNB_EMPTY) continue;
444
*mp++ = (i % 2 == 0 ? DNB_VERT : DNB_HOR);