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 ATAXX_CELL_SIZE 55
28
#define ATAXX_NUM_PIECES 2
30
#define ATAXX_BOARD_WID 7
31
#define ATAXX_BOARD_HEIT 7
37
#define ATAXX_MOVEGEN_PLAUSIBLE 1
39
static char ataxx_colors[6] = {140, 160, 140, 200, 200, 200};
41
static int ataxx_init_pos [ATAXX_BOARD_WID*ATAXX_BOARD_HEIT] =
43
1 , 0 , 0 , 0 , 0 , 0 , 2 ,
44
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
45
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
46
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
47
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
48
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
49
2 , 0 , 0 , 0 , 0 , 0 , 1 ,
54
Game Ataxx = { ATAXX_CELL_SIZE, ATAXX_BOARD_WID, ATAXX_BOARD_HEIT,
56
ataxx_colors, ataxx_init_pos, NULL, "Ataxx", NULL, ataxx_init};
58
ResultType ataxx_eval (Pos *, Player, float *);
59
byte *ataxx_movegen (Pos *);
61
static int ataxx_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
62
static ResultType ataxx_who_won (Pos *, Player , char **);
63
unsigned char * ataxx_get_rgbmap (int, int);
64
void ataxx_reset_uistate ();
67
static int ataxx_max_moves = 200;
71
game_eval = ataxx_eval;
72
game_movegen = ataxx_movegen;
73
game_getmove = ataxx_getmove;
74
game_who_won = ataxx_who_won;
75
game_get_rgbmap = ataxx_get_rgbmap;
76
game_white_string = "Red";
77
game_black_string = "Blue";
78
game_file_label = FILERANK_LABEL_TYPE_ALPHA;
79
game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC;
80
game_reset_uistate = ataxx_reset_uistate;
81
game_allow_flip = TRUE;
82
game_doc_about_status = STATUS_COMPLETE;
86
"Status: Fully implemented\n"
87
"URL: "GAME_DEFAULT_URL("ataxx");
89
" - The objective of the game is to get as many balls of your color as possible.\n"
90
" - In each move you must click an existing ball of your color followed by an empty square.\n"
91
" - The new square should be at a distance of at most 2 from the first square (a diagonal counts as one unit).\n"
92
" - If the distance is two the first square becomes empty, but not if the distance is 1.\n"
93
" - In either case all balls adjacent to the new square, if they are the opponent's color, get converted to your color.\n"
94
" - If one player has no moves the player with more balls wins.\n";
97
ResultType ataxx_who_won (Pos *pos, Player to_play, char **commp)
99
static char comment[32];
100
int i, wscore = 0, bscore = 0, who_idx;
101
char *who_str [3] = { "Red won", "Blue won", "its a tie" };
102
byte *move = ataxx_movegen (pos);
103
for (i=0; i<board_wid * board_heit; i++)
104
if (pos->board[i] == ATAXX_WP)
106
else if (pos->board[i] == ATAXX_BP)
111
if (pos->num_moves > ataxx_max_moves)
113
fprintf (stderr, "max moves reached\n");
114
snprintf (comment, 32, "%s", who_str[2]);
120
snprintf (comment, 32, "%d : %d", wscore, bscore);
122
return RESULT_NOTYET;
126
if (wscore > bscore) who_idx = 0;
127
else if (wscore < bscore) who_idx = 1;
129
snprintf (comment, 32, "%s (%d : %d)", who_str [who_idx], wscore, bscore);
139
ResultType ataxx_eval (Pos *pos, Player to_play, float *eval)
143
for (i=0, wcount=0, bcount=0; i<board_wid*board_heit; i++)
145
if (pos->board[i] == ATAXX_WP) wcount++;
146
if (pos->board[i] == ATAXX_BP) bcount++;
148
*eval = wcount-bcount;
149
if (!wcount || !bcount) *eval *= GAME_EVAL_INFTY;
150
if (!wcount) return RESULT_BLACK;
151
if (!bcount) return RESULT_WHITE;
152
return RESULT_NOTYET;
155
byte *ataxx_movegen (Pos *pos)
156
/* to keep things from getting out of hand, we'll generate only
157
_plausible_ moves: find the max #flips possible and generate
158
only those moves that lead to at least max-1 flips */
160
int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
161
int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
162
int incx2[] = { -2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2};
163
int incy2[] = { -2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2};
164
int x, y, i, j, newx, newy;
165
Player player = pos->player;
166
byte our = (player == WHITE ? ATAXX_WP : ATAXX_BP);
167
byte other = (player == WHITE ? ATAXX_BP : ATAXX_WP);
168
byte *board = pos->board;
169
#ifdef ATAXX_MOVEGEN_PLAUSIBLE
177
nbrs = (byte *) malloc (board_wid * board_heit * sizeof (byte));
179
for (i=0; i<board_wid * board_heit; i++)
181
for (x=0; x<board_wid; x++)
182
for (y=0; y<board_heit; y++)
184
if (board [y * board_wid + x] != other)
190
if (newx >= 0 && newy >= 0
191
&& newx < board_wid && newy < board_heit)
192
nbrs [newy * board_wid + newx] ++;
195
#ifdef ATAXX_MOVEGEN_PLAUSIBLE
197
for (x=0; x<board_wid; x++)
198
for (y=0; y<board_heit; y++)
199
if (board[y * board_wid + x] == ATAXX_EMPTY
200
&& nbrs[y * board_wid + x] > max_nbrs)
207
if (newx >= 0 && newy >= 0
208
&& newx < board_wid && newy < board_heit
209
&& board [newy * board_wid + newx] == our)
211
max_nbrs = nbrs[y * board_wid + x];
216
/*if (found) continue;
217
nbrs [y * board_wid + x]--;
218
if (nbrs[y * board_wid + x] <= max_nbrs) continue;
223
if (newx >= 0 && newy >= 0
224
&& newx < board_wid && newy < board_heit
225
&& board [newy * board_wid + newx] == our)
227
max_nbrs = nbrs[y * board_wid + x];
233
for (x=0; x<board_wid; x++)
234
for (y=0; y<board_heit; y++)
237
if (board [y * board_wid + x] != ATAXX_EMPTY)
239
#ifdef ATAXX_MOVEGEN_PLAUSIBLE
240
if (nbrs [y * board_wid + x] < max_nbrs - 1)
247
if (newx >= 0 && newy >= 0
248
&& newx < board_wid && newy < board_heit)
249
if (board [newy * board_wid + newx] == our)
251
/* found a same col neighbor */
265
if (newx >= 0 && newy >= 0
266
&& newx < board_wid && newy < board_heit)
267
if (board [newy * board_wid + newx] == other)
282
if (!(newx >= 0 && newy >= 0
283
&& newx < board_wid && newy < board_heit))
285
if (board [newy * board_wid + newx] != our)
292
*movp++ = ATAXX_EMPTY;
297
if (newx >= 0 && newy >= 0
298
&& newx < board_wid && newy < board_heit)
299
if (board [newy * board_wid + newx] == other)
311
movlist = (byte *) (malloc (movp - movbuf));
312
memcpy (movlist, movbuf, (movp - movbuf));
318
static int oldx = -1, oldy = -1;
320
void ataxx_reset_uistate ()
322
oldx = -1, oldy = -1;
325
int ataxx_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, byte **movp, int **rmovep)
327
static byte move[32];
333
int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
334
int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
335
if (type != GTKBOARD_BUTTON_RELEASE)
339
if (pos->board [y * board_wid + x] != (to_play == WHITE ? ATAXX_WP : ATAXX_BP))
344
*rp++ = RENDER_HIGHLIGHT1;
350
if (x == oldx && y == oldy)
352
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
353
oldx = -1; oldy = -1; return 0;
355
if (pos->board [y * board_wid + x] != ATAXX_EMPTY)
357
*rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove;
358
return oldx = oldy = -1;
360
diffx = abs (x - oldx); diffy = abs (y - oldy);
361
if (diffx > 2 || diffy > 2) { return oldx = oldy = -1; }
362
if (diffx > 1 || diffy > 1)
363
{ *mptr++ = oldx; *mptr++ = oldy; *mptr++ = ATAXX_EMPTY; }
364
other = (to_play == WHITE ? ATAXX_BP : ATAXX_WP);
367
int newx = x + incx[i], newy = y + incy[i];
368
if (newx < 0 || newy < 0 || newx >= board_wid || newy >= board_heit)
370
if (pos->board[newy * board_wid + newx] == other)
372
*mptr++ = newx; *mptr++ = newy;
373
*mptr++ = (to_play == WHITE ? ATAXX_WP : ATAXX_BP);
376
{ *mptr++ = x; *mptr++ = y; *mptr++ =
377
(to_play == WHITE ? ATAXX_WP : ATAXX_BP); }
386
oldx = -1; oldy = -1;
390
unsigned char * ataxx_get_rgbmap (int idx, int color)
394
static char rgbbuf[3 * ATAXX_CELL_SIZE * ATAXX_CELL_SIZE];
395
colors = ataxx_colors;
396
fg = (idx == ATAXX_WP ? 0xee << 16 : 0xee);
397
if (color == BLACK) colors += 3;
398
for(i=0, bg=0;i<3;i++)
399
{ int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));}
400
rgbmap_ball_shadow_gen(55, rgbbuf, fg, bg, 17.0, 35.0, 3);