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
24
#include "../pixmaps/chess.xpm"
27
#define ANTICHESS_CELL_SIZE 54
28
#define ANTICHESS_NUM_PIECES 12
30
#define ANTICHESS_BOARD_WID 8
31
#define ANTICHESS_BOARD_HEIT 8
33
#define ANTICHESS_EMPTY 0
34
#define ANTICHESS_WK 1
35
#define ANTICHESS_WQ 2
36
#define ANTICHESS_WR 3
37
#define ANTICHESS_WB 4
38
#define ANTICHESS_WN 5
39
#define ANTICHESS_WP 6
40
#define ANTICHESS_BK 7
41
#define ANTICHESS_BQ 8
42
#define ANTICHESS_BR 9
43
#define ANTICHESS_BB 10
44
#define ANTICHESS_BN 11
45
#define ANTICHESS_BP 12
47
#define ANTICHESS_ISWHITE(x) (x >= 1 && x <= 6)
48
#define ANTICHESS_ISBLACK(x) (x >= 7 && x <= 12)
51
#define abs(x) ((x) < 0 ? -(x) : (x))
54
static char antichess_colors[] =
57
char antichess_highlight_colors[9] = {0xff, 0, 0};
59
static int antichess_init_pos[] =
61
9 , 11, 10, 8 , 7 , 10, 11, 9 ,
62
12, 12, 12, 12, 12, 12, 12, 12 ,
63
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
64
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
65
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
66
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
67
6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ,
68
3 , 5 , 4 , 2 , 1 , 4 , 5 , 3 ,
70
static int antichess_max_moves = 200;
72
static char ** antichess_pixmaps[] =
91
void antichess_init ();
92
int antichess_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
93
ResultType antichess_who_won (Pos *, Player, char **);
94
byte *antichess_movegen (Pos *);
95
ResultType antichess_eval (Pos *, Player, float *);
96
ResultType antichess_eval_incr (Pos *, Player, byte *, float *);
99
{ ANTICHESS_CELL_SIZE, ANTICHESS_BOARD_WID, ANTICHESS_BOARD_HEIT,
100
ANTICHESS_NUM_PIECES,
101
antichess_colors, antichess_init_pos, antichess_pixmaps, "Antichess",
105
Game * plugin_game = &Antichess;
107
void antichess_init ()
109
game_getmove = antichess_getmove;
110
game_who_won = antichess_who_won;
111
game_movegen = antichess_movegen;
112
game_eval = antichess_eval;
113
// game_eval_incr = antichess_eval_incr;
114
game_file_label = FILERANK_LABEL_TYPE_ALPHA;
115
game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC;
116
game_highlight_colors = antichess_highlight_colors;
117
game_allow_flip = TRUE;
118
game_doc_about_status = STATUS_COMPLETE;
122
"Status: Fully implemented\n"
123
"URL: "GAME_DEFAULT_URL("antichess");
125
"The objective of the game is to force your opponent to capture all your pieces or to stalemate you. What makes this possible is that if you can capture, then you MUST.\n"
127
"The pieces move as in chess. However:\n"
128
" - The king is NOT a special piece. No check(mate), no castling. The king can be captured like any other piece.\n"
129
" - No taking en passant.\n"
130
" - Pawn promotion is as in chess.\n"
132
"A couple of notes on the gtkboard implementation of chess and antichess:\n"
133
" - Drag and drop doesn't work (yet). To make the move 1. e4, you have to click on e2 and then on e4.\n"
134
" - To promote, after clicking on the pawn and then on the promotion square, you have to click on a third square which indicates which piece you want to promote to. This square should be any one of the squares of the file of that piece. (Thus, to queen, click anywhere on the 'd' file, etc.)";
137
static int isfreeline (byte *pos, int oldx, int oldy, int newx, int newy)
139
int x = oldx, y = oldy, dx, dy, diffx = newx - oldx, diffy = newy - oldy;
140
if (abs (diffx) != abs(diffy) && diffx != 0 && diffy != 0)
142
dx = (diffx ? (diffx / abs (diffx)) : 0);
143
dy = (diffy ? (diffy / abs (diffy)) : 0);
144
for (x+=dx, y+=dy; x != newx || y != newy; x+=dx, y+=dy)
145
if (pos [y * board_wid + x] != 0)
150
static int islegal (Pos *pos, int oldx, int oldy, int x, int y, int player)
152
int piece = pos->board [oldy * board_wid + oldx];
153
byte *board = pos->board;
159
int diffx = abs (x - oldx), diffy = abs (y - oldy);
160
return diffx <= 1 && diffy <= 1;
164
return isfreeline (board, oldx, oldy, x, y);
167
if (!isfreeline (board, oldx, oldy, x, y))
169
if (oldx == x || oldy == y)
174
if (!isfreeline (board, oldx, oldy, x, y))
176
if (oldx == x || oldy == y)
182
int diffx = abs (x - oldx), diffy = abs (y - oldy);
183
if (diffx == 2 && diffy == 1)
185
if (diffx == 1 && diffy == 2)
190
if (board [y * board_wid + x] == 0)
191
return (x == oldx && (y == oldy + 1 ||
192
(y == 3 && oldy == 1 && board [(2*board_wid + x)] == 0)));
193
return y == oldy + 1 && (x == oldx + 1 || x == oldx - 1) ;
195
if (board [y * board_wid + x] == 0)
196
return (x == oldx && (y == oldy - 1 ||
197
(y == 4 && oldy == 6 && board [5*board_wid + x] == 0)));
198
return y == oldy - 1 && (x == oldx + 1 || x == oldx - 1) ;
204
static int can_capture (Pos *pos, int player)
206
int x1, y1, x2, y2, val;
207
for (x1 = 0; x1 < board_wid; x1++)
208
for (y1 = 0; y1 < board_heit; y1++)
210
val = pos->board [y1 * board_wid + x1];
211
if (player == WHITE && !ANTICHESS_ISWHITE (val)) continue;
212
if (player == BLACK && !ANTICHESS_ISBLACK (val)) continue;
213
for (x2 = 0; x2 < board_wid; x2++)
214
for (y2 = 0; y2 < board_heit; y2++)
216
val = pos->board [y2 * board_wid + x2];
217
if (player == WHITE && !ANTICHESS_ISBLACK (val)) continue;
218
if (player == BLACK && !ANTICHESS_ISWHITE (val)) continue;
219
if (islegal (pos, x1, y1, x2, y2, player)) return 1;
225
static int oppcolor (byte *pos, int oldx, int oldy, int x, int y)
226
/* True if one square is W and the other is B */
228
int oldv = pos [oldy * board_wid + oldx], v = pos [y * board_wid + x];
229
if (ANTICHESS_ISWHITE (oldv) && ANTICHESS_ISBLACK (v)) return 1;
230
if (ANTICHESS_ISBLACK (oldv) && ANTICHESS_ISWHITE (v)) return 1;
234
static int oldx = -1, oldy = -1, oldval = -1;
235
static int prom = 0, prom_x, prom_oldx;
237
void antichess_free ()
239
oldx = -1, oldy = -1, prom = 0;
242
int antichess_getmove (Pos *pos, int x, int y,
243
GtkboardEventType type, Player player, byte ** movep, int ** rmovep)
244
/* Translate mouse clicks into move */
246
static byte move [7];
247
static int rmove [7];
250
if (type != GTKBOARD_BUTTON_RELEASE)
253
val = pos->board [y * board_wid + x];
255
if (oldx >= 0 && x == oldx && y == oldy)
257
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
258
oldx = -1; oldy = -1; return 0;
261
// if you can capture you must capture
262
if (oldx >= 0 && can_capture (pos, player) &&
263
!((ANTICHESS_ISWHITE (val) && ANTICHESS_ISBLACK (oldval))
264
|| (ANTICHESS_ISBLACK (val) && ANTICHESS_ISWHITE (oldval))))
266
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
279
new_p = (player == WHITE ? ANTICHESS_WR : ANTICHESS_BR); break;
281
new_p = (player == WHITE ? ANTICHESS_WN : ANTICHESS_BN); break;
283
new_p = (player == WHITE ? ANTICHESS_WB : ANTICHESS_BB); break;
285
new_p = (player == WHITE ? ANTICHESS_WQ : ANTICHESS_BQ); break;
288
move[1] = (player == WHITE ? 6 : 1);
291
move[4] = (player == WHITE ? 7 : 0);
301
if (val == 0) return -1;
302
if (player == WHITE && !ANTICHESS_ISWHITE (val))
304
if (player == BLACK && !ANTICHESS_ISBLACK (val))
306
oldx = x; oldy = y, oldval = val;
307
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_HIGHLIGHT1; *rp++ = -1; *rmovep = rmove;
310
if (player == WHITE && ANTICHESS_ISWHITE (val))
312
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
313
oldx = -1; oldy = -1;
316
if (player == BLACK && ANTICHESS_ISBLACK (val))
318
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
319
oldx = -1; oldy = -1;
323
if (!islegal (pos, oldx, oldy, x, y, player))
325
//|| (can_capture (pos, player) && !oppcolor (pos, oldx, oldy, x, y)))
327
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
328
oldx = -1; oldy = -1;
333
if ((oldval == ANTICHESS_WP || oldval == ANTICHESS_BP) &&
334
(y == 0 || y == board_heit - 1))
339
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
344
move[0] = oldx; move[1] = oldy; move[2] = 0;
345
move[3] = x; move[4] = y; move[5] = pos->board [oldy * board_wid + oldx];
348
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
349
oldx = -1; oldy = -1;
354
/*if (player == WHITE && ANTICHESS_ISWHITE (val))
358
static int hasmove (Pos *pos, int player)
360
int x1, y1, x2, y2, val;
361
for (x1 = 0; x1 < board_wid; x1++)
362
for (y1 = 0; y1 < board_heit; y1++)
364
val = pos->board [y1 * board_wid + x1];
365
if (player == WHITE && !ANTICHESS_ISWHITE (val)) continue;
366
if (player == BLACK && !ANTICHESS_ISBLACK (val)) continue;
367
for (x2 = 0; x2 < board_wid; x2++)
368
for (y2 = 0; y2 < board_heit; y2++)
369
if (islegal (pos, x1, y1, x2, y2, player)) return 1;
374
ResultType antichess_who_won (Pos *pos, Player player, char **commp)
376
static char comment[32];
377
char *who_str [3] = { "White won", "Black won", "Draw" };
379
if (hasmove (pos, player)) //return RESULT_NOTYET;
381
if (pos->num_moves > antichess_max_moves)
383
fprintf (stderr, "max moves reached\n");
384
snprintf (comment, 32, "%s", who_str[2]);
388
return RESULT_NOTYET;
391
if (hasmove (pos, player == WHITE ? BLACK : WHITE))
393
strncpy (comment, who_str[player == WHITE ? 0 : 1], 31);
394
return player == WHITE ? RESULT_WHITE : RESULT_BLACK;
398
strncpy (comment, who_str[2], 31);
403
int antichess_movegen_square (byte *pos, byte **movp, int player,
404
int oldx, int oldy, int x, int y)
407
if (!ISINBOARD(x, y)) return 0;
408
val = pos [y * board_heit + x];
409
if ((player == WHITE && ANTICHESS_ISWHITE (val))
410
|| (player == BLACK && ANTICHESS_ISBLACK (val)))
417
*(*movp)++ = pos [oldy * board_heit + oldx];
422
int antichess_movegen_line (byte *pos, byte **movp, int player,
423
int x, int y, int incx, int incy)
425
int oldx = x, oldy = y;
426
int capture = 0, val;
429
if (capture) return 1;
432
val = pos [y * board_heit + x];
433
if (ISINBOARD (x, y) && oppcolor (pos, oldx, oldy, x, y))
435
} while (antichess_movegen_square (pos, movp, player, oldx, oldy, x, y));
439
static void antichess_movegen_promote (byte *board, byte **movp, int player,
440
int oldx, int oldy, int x, int y)
443
int promote_pieces[2][4] = {
444
{ANTICHESS_WQ, ANTICHESS_WR, ANTICHESS_WB, ANTICHESS_WN},
445
{ANTICHESS_BQ, ANTICHESS_BR, ANTICHESS_BB, ANTICHESS_BN}
447
i = (player == WHITE ? 0 : 1);
455
*(*movp)++ = promote_pieces[i][j];
460
byte *antichess_movegen (Pos *pos)
463
byte *realp = realbuf;
464
byte movbuf[4096], *movp = movbuf;
466
int i, j, k, x, y, capture = 0;
467
int incxr[] = {0, 0, 1, -1};
468
int incyr[] = {1, -1, 0, 0};
469
int incxb[] = {1, 1, -1, -1};
470
int incyb[] = {1, -1, 1, -1};
471
int incxn[] = {2, 2, -2, -2, 1, 1, -1, -1};
472
int incyn[] = {1, -1, 1, -1, 2, -2, 2, -2};
473
byte *board = pos->board;
474
Player player = pos->player;
475
for (i=0; i<board_wid; i++)
476
for (j=0; j<board_heit; j++)
478
int val = board[j * board_heit + i];
479
if ((player == WHITE && ANTICHESS_ISWHITE (val))
480
|| (player == BLACK && ANTICHESS_ISBLACK (val)))
485
if (ISINBOARD (i, j+1) && board [(j+1) * board_heit + i] == 0)
487
if (j == board_heit - 2)
488
antichess_movegen_promote(board, &movp, player,
491
antichess_movegen_square (board, &movp, player,
494
if (ISINBOARD (i+1, j+1) &&
495
ANTICHESS_ISBLACK (board [(j+1) * board_heit + i+1]))
497
if (j == board_heit - 2)
498
antichess_movegen_promote (board, &movp, player,
501
antichess_movegen_square (board, &movp, player,
505
if (ISINBOARD (i-1, j+1) &&
506
ANTICHESS_ISBLACK (board [(j+1) * board_heit + i-1]))
508
if (j == board_heit - 2)
509
antichess_movegen_promote (board, &movp, player,
512
antichess_movegen_square (board, &movp, player,
516
if (j == 1 && board [2 * board_heit + i] == 0
517
&& board [3 * board_heit + i] == 0)
518
antichess_movegen_square (board, &movp, player,
522
if (ISINBOARD (i, j-1) && board [(j-1) * board_heit + i] == 0)
525
antichess_movegen_promote (board, &movp, player,
528
antichess_movegen_square (board, &movp, player,
531
if (ISINBOARD (i+1, j-1) &&
532
ANTICHESS_ISWHITE (board [(j-1) * board_heit + i+1]))
535
antichess_movegen_promote (board, &movp, player,
538
antichess_movegen_square (board, &movp, player,
542
if (ISINBOARD (i-1, j-1) &&
543
ANTICHESS_ISWHITE (board [(j-1) * board_heit + i-1]))
546
antichess_movegen_promote (board, &movp, player,
549
antichess_movegen_square (board, &movp, player,
553
if (j == 6 && board [5 * board_heit + i] == 0
554
&& board [4 * board_heit + i] == 0)
555
antichess_movegen_square (board, &movp, player,
562
antichess_movegen_square(board, &movp, player,
563
i, j, i + incxr[k], j + incyr[k]);
564
if (ISINBOARD(i + incxr[k], j + incyr[k])
565
&& oppcolor (board, i, j, i+incxr[k], j+incyr[k]))
570
antichess_movegen_square(board, &movp, player,
571
i, j, i + incxb[k], j + incyb[k]);
572
if (ISINBOARD(i + incxb[k], j + incyb[k])
573
&& oppcolor (board, i, j, i+incxb[k], j+incyb[k]))
580
capture += antichess_movegen_line (board, &movp, player,
581
i, j, incxb[k], incyb[k]);
586
capture += antichess_movegen_line (board, &movp, player,
587
i, j, incxr[k], incyr[k]);
592
capture += antichess_movegen_line (board, &movp, player,
593
i, j, incxb[k], incyb[k]);
595
capture += antichess_movegen_line (board, &movp, player,
596
i, j, incxr[k], incyr[k]);
602
antichess_movegen_square(board, &movp, player,
603
i, j, i + incxn[k], j + incyn[k]);
604
if (ISINBOARD(i + incxn[k], j + incyn[k])
605
&& oppcolor (board, i, j, i+incxn[k], j+incyn[k]))
614
/* if there is a capture eliminate all other moves */
617
movlist = (byte *) malloc (movp - movbuf);
618
memcpy (movlist, movbuf, movp - movbuf);
629
/* a capture is a move that involves a W as well as a B piece */
630
for (tmp = movp; *tmp != -1; tmp += 3)
632
if (ANTICHESS_ISWHITE (board [tmp[1] * board_heit + tmp[0]])) w = 1;
633
if (ANTICHESS_ISBLACK (board [tmp[1] * board_heit + tmp[0]])) b = 1;
649
movlist = (byte *) malloc (realp - realbuf);
650
memcpy (movlist, realbuf, realp - realbuf);
654
// True if this square is a pawn and it can move
655
static gboolean eval_pawn_has_move (byte *board, int i, int j)
657
int val = board [j * board_wid + i];
659
if (val == ANTICHESS_WP) y = j+1;
660
else if (val == ANTICHESS_BP) y = j-1;
663
if (board [y * board_wid + i] == ANTICHESS_EMPTY) return TRUE;
665
for (x=i-1; x<=i+1; x+=2)
667
if (x < 0 || x >= board_wid) continue;
668
if (val == ANTICHESS_WP && ANTICHESS_ISBLACK (board [y * board_wid + x]))
670
if (val == ANTICHESS_BP && ANTICHESS_ISWHITE (board [y * board_wid + x]))
677
ResultType antichess_eval (Pos * pos, Player player, float *eval)
679
int wsum = 0, bsum = 0, i, j;
680
gboolean wfound = FALSE, bfound = FALSE;
681
for (i=0; i < board_wid; i++)
682
for (j=0; j < board_heit; j++)
683
if (ANTICHESS_ISWHITE (pos->board[j * board_wid + i]))
686
if (!wfound && eval_pawn_has_move (pos->board, i, j))
690
else if (ANTICHESS_ISBLACK (pos->board[j * board_wid + i]))
693
if (!bfound && eval_pawn_has_move (pos->board, i, j))
697
if (wsum == 0 || (!wfound && bfound && player == WHITE))
699
*eval = GAME_EVAL_INFTY;
702
if (bsum == 0 || (!bfound && wfound && player == BLACK))
704
*eval = -GAME_EVAL_INFTY;
707
if (!wfound && !bfound)
713
return RESULT_NOTYET;
716
ResultType antichess_eval_incr (Pos *pos, Player player, byte *move, float *eval)
717
// check if there's a capture
719
byte *board = pos->board;
722
if (move[2] && board[move[1] * board_wid + move[0]]) *eval = -1;
723
else if (move[5] && board[move[4] * board_wid + move[3]]) return -1;
728
if (move[2] && board[move[1] * board_wid + move[0]]) *eval = 1;
729
else if (move[5] && board[move[4] * board_wid + move[3]]) *eval = 1;
732
return RESULT_NOTYET;