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
25
#include "../pixmaps/chess.xpm"
27
#define BREAKTHROUGH_CELL_SIZE 54
28
#define BREAKTHROUGH_NUM_PIECES 2
30
#define BREAKTHROUGH_BOARD_WID 8
31
#define BREAKTHROUGH_BOARD_HEIT 8
33
#define BREAKTHROUGH_EMPTY 0
34
#define BREAKTHROUGH_WP 1
35
#define BREAKTHROUGH_BP 2
37
int breakthrough_initpos [BREAKTHROUGH_BOARD_WID*BREAKTHROUGH_BOARD_HEIT] =
39
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
40
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
41
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
42
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
43
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
44
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
45
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
46
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
50
char ** breakthrough_pixmaps [] =
56
int breakthrough_curx = -1, breakthrough_cury = -1;
58
static char breakthrough_colors[] =
61
static int breakthrough_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
62
static int breakthrough_getmove_kb (Pos *, int, Player, byte ** , int **);
63
void breakthrough_init ();
64
static ResultType breakthrough_who_won (Pos *, Player, char **);
65
static ResultType breakthrough_eval (Pos *, Player, float *eval);
66
static ResultType breakthrough_eval_incr (Pos *, byte *, float *);
67
static byte * breakthrough_movegen (Pos *);
68
static void *breakthrough_newstate (Pos *, byte *);
70
Game Breakthrough = { BREAKTHROUGH_CELL_SIZE, BREAKTHROUGH_BOARD_WID, BREAKTHROUGH_BOARD_HEIT,
71
BREAKTHROUGH_NUM_PIECES,
72
breakthrough_colors, breakthrough_initpos, breakthrough_pixmaps,
73
"Breakthrough", "Chess variants", breakthrough_init};
75
void breakthrough_init ()
77
game_getmove = breakthrough_getmove;
78
// game_who_won = breakthrough_who_won;
79
game_eval = breakthrough_eval;
80
// game_eval_incr = breakthrough_eval_incr;
81
game_movegen = breakthrough_movegen;
82
game_file_label = FILERANK_LABEL_TYPE_ALPHA;
83
game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC;
84
game_allow_flip = TRUE;
85
game_doc_about_status = STATUS_UNPLAYABLE;
89
"Status: Partially implemented\n"
90
"URL: "GAME_DEFAULT_URL ("breakthrough");
93
static gboolean eval_is_backward (byte *board, int x, int y)
96
int val = board[y * board_wid + x];
97
assert (val != BREAKTHROUGH_EMPTY);
98
incy = val == BREAKTHROUGH_WP ? 1 : -1;
99
other = val == BREAKTHROUGH_WP ? BREAKTHROUGH_BP : BREAKTHROUGH_WP;
101
for (j = y; j < board_heit && j >= 0; j -= incy)
103
if (x - 1 >= 0 && board[j * board_wid + x - 1] == val) return FALSE;
104
if (x + 1 < board_wid && board[j * board_wid + x + 1] == val) return FALSE;
107
for (j = y + incy; j < board_heit && j >= 0; j += incy)
109
if (board[j * board_wid + x] != BREAKTHROUGH_EMPTY) return FALSE;
110
if (x - 1 >= 0 && j + incy >= 0 && j + incy < board_heit &&
111
board[j * board_wid + x - 1] == val &&
112
board[(j + incy) * board_wid + x - 1] == other) return TRUE;
113
if (x + 1 >= 0 && j + incy >= 0 && j + incy < board_heit &&
114
board[j * board_wid + x + 1] == val &&
115
board[(j + incy) * board_wid + x + 1] == other) return TRUE;
120
// Is this pawn a passer?
121
static gboolean eval_is_passer (byte *board, int x, int y)
124
int val = board[y * board_wid + x];
125
assert (val != BREAKTHROUGH_EMPTY);
126
incy = val == BREAKTHROUGH_WP ? 1 : -1;
127
other = val == BREAKTHROUGH_WP ? BREAKTHROUGH_BP : BREAKTHROUGH_WP;
128
for (y += incy; y < board_heit && y >= 0; y += incy)
130
if (board[y * board_wid + x] != BREAKTHROUGH_EMPTY) return FALSE;
131
if (x - 1 >= 0 && board[y * board_wid + x - 1] == other) return FALSE;
132
if (x + 1 < board_wid && board[y * board_wid + x + 1] == other) return FALSE;
137
static gboolean eval_is_blocked (byte *board, int x, int y)
143
static ResultType breakthrough_eval (Pos *pos, Player player, float *eval)
147
int wcount[BREAKTHROUGH_BOARD_WID], bcount[BREAKTHROUGH_BOARD_WID];
148
float doubled_pawn_penalty = 0.2;
149
float edge_pawn_bonus = 0.1;
150
float backward_pawn_penalty = 0.5;
151
float blocked_pawn_penalty = 0.1;
153
int passer_min_white = board_heit, passer_min_black = board_heit;
155
for (i=0; i<board_wid; i++)
157
// cheap optimization trick
158
if (pos->board [0 * board_wid + i] == BREAKTHROUGH_WP &&
159
pos->board [(board_heit - 1) * board_wid + i] == BREAKTHROUGH_BP)
161
for (j=0; j<board_heit; j++)
163
int val = pos->board[j * board_wid + i];
164
if (val == BREAKTHROUGH_EMPTY) continue;
165
if (eval_is_passer (pos->board, i, j))
167
if (val == BREAKTHROUGH_WP && (board_wid -1 - j < passer_min_white))
168
passer_min_white = board_wid -1 - j;
169
if (val == BREAKTHROUGH_BP && (j < passer_min_black))
170
passer_min_black = j;
174
if (passer_min_white < board_heit || passer_min_black < board_heit)
176
int diff = passer_min_white - passer_min_black;
177
if (diff < 0 || (diff == 0 && player == WHITE))
182
if (diff > 0 || (diff == 0 && player == BLACK))
189
for (i=0; i<board_wid; i++)
190
wcount[i] = bcount[i] = 0;
192
for (i=0; i<board_wid; i++)
193
for (j=0; j<board_heit; j++)
195
int val = pos->board [j * board_wid + i];
196
if (val == BREAKTHROUGH_EMPTY) continue;
197
if (val == BREAKTHROUGH_WP)
199
wtsum += (1 + 0.1 * j);
200
if (i == 0 || i == board_wid - 1)
201
wtsum += edge_pawn_bonus;
202
if (eval_is_backward (pos->board, i, j))
203
wtsum -= backward_pawn_penalty;
206
else if (val == BREAKTHROUGH_BP)
208
wtsum -= (1 + 0.1 * (board_wid - 1 - j));
209
if (i == 0 || i == board_wid - 1)
210
wtsum -= edge_pawn_bonus;
211
if (eval_is_backward (pos->board, i, j))
212
wtsum += backward_pawn_penalty;
217
for (i=0; i<board_wid; i++)
219
wtsum -= (wcount[i] > 1 ? wcount[i] - 1 : 0);
220
wtsum += (bcount[i] > 1 ? bcount[i] - 1 : 0);
224
return RESULT_NOTYET;
227
static ResultType breakthrough_eval_incr (Pos *pos, byte *move, float *eval)
229
byte *board = pos->board;
230
if (move[0] == move[3]) *eval = 0;
231
else *eval = (pos->player == WHITE ? 1 : -1);
232
*eval += 0.01 * random() / RAND_MAX;
233
return RESULT_NOTYET;
236
static byte * breakthrough_movegen (Pos *pos)
238
int i, j, m, n, xoff, yoff;
240
byte *movlist, *movp = movbuf;
241
byte *board = pos->board;
243
// generate a random permutation of the moves
244
xoff = random() % board_wid;
245
yoff = random() % board_heit;
246
for (m=0; m<board_wid; m++)
247
for (n=0; n<board_heit; n++)
250
i = (m + xoff) % board_wid;
251
j = (n + yoff) % board_heit;
252
if (board [j * board_wid + i] !=
253
(pos->player == WHITE ? BREAKTHROUGH_WP : BREAKTHROUGH_BP))
255
incy = board [j * board_wid + i] == BREAKTHROUGH_WP ? 1 : -1;
256
for (incx = -1; incx <= 1; incx += 1)
259
if (!ISINBOARD (i + incx, j + incy))
261
val = board [(j+incy) * board_wid + (i+incx)];
262
if ((val == BREAKTHROUGH_EMPTY || val == board [j * board_wid + i])
265
if (val != BREAKTHROUGH_EMPTY && incx == 0) continue;
268
*movp++ = (pos->player == WHITE ? BREAKTHROUGH_WP : BREAKTHROUGH_BP);
276
movlist = (byte *) (malloc (movp - movbuf));
277
memcpy (movlist, movbuf, (movp - movbuf));
281
int breakthrough_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player player,
282
byte **movp, int **rmovp)
284
static byte move[128];
287
if (type != GTKBOARD_BUTTON_RELEASE)
289
if (breakthrough_curx < 0)
291
if ((player == WHITE && pos->board [y * board_wid + x] == BREAKTHROUGH_WP)
292
|| (player == BLACK && pos->board [y * board_wid + x] == BREAKTHROUGH_BP))
294
int incy = player == WHITE ? 1 : -1;
295
int other = player == WHITE ? BREAKTHROUGH_BP : BREAKTHROUGH_WP;
296
if ((x == 0 || pos->board [(y + incy) * board_wid + x - 1] != other) &&
297
(x == board_wid - 1 ||
298
pos->board [(y + incy) * board_wid + x + 1] != other))
300
if (pos->board [(y + incy) * board_wid + x] != BREAKTHROUGH_EMPTY)
309
*mp++ = pos->board [y * board_wid + x];
317
breakthrough_curx = x;
318
breakthrough_cury = y;
324
diffx = x - breakthrough_curx;
325
diffy = y - breakthrough_cury;
326
if ((player == WHITE && pos->board [y * board_wid + x] == BREAKTHROUGH_WP)
327
|| (player == BLACK && pos->board [y * board_wid + x] == BREAKTHROUGH_BP))
329
breakthrough_curx = breakthrough_cury = -1;
332
else if (pos->board[y * board_wid + x] == BREAKTHROUGH_EMPTY
335
(player == WHITE && (diffy != 1 || diffx != 0))
337
(player == BLACK && (diffy != -1 || diffx != 0))
341
breakthrough_curx = breakthrough_cury = -1;
344
else if (((player == WHITE && pos->board [y * board_wid + x] == BREAKTHROUGH_BP)
345
|| (player == BLACK && pos->board [y * board_wid + x] == BREAKTHROUGH_WP))
347
((player == WHITE && (diffy != 1 || abs (diffx) != 1))
348
||(player == BLACK && (diffy != -1 || abs(diffx) != 1))))
350
breakthrough_curx = breakthrough_cury = -1;
355
*mp++ = (player == WHITE ? BREAKTHROUGH_WP : BREAKTHROUGH_BP);
356
*mp++ = breakthrough_curx;
357
*mp++ = breakthrough_cury;
361
breakthrough_curx = breakthrough_cury = -1;