This is the doxygen documentation for gtkboard.
.00001 /* This file is a part of gtkboard, a board games system. 00002 Copyright (C) 2003, Arvind Narayanan <arvindn@users.sourceforge.net> 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA 00017 00018 */ 00019 #include <stdio.h> 00020 #include <string.h> 00021 #include <assert.h> 00022 #include <stdlib.h> 00023 00024 #include "game.h" 00025 #include "aaball.h" 00026 00027 #define ATAXX_CELL_SIZE 55 00028 #define ATAXX_NUM_PIECES 2 00029 00030 #define ATAXX_BOARD_WID 7 00031 #define ATAXX_BOARD_HEIT 7 00032 00033 #define ATAXX_EMPTY 0 00034 #define ATAXX_WP 1 00035 #define ATAXX_BP 2 00036 00037 #define ATAXX_MOVEGEN_PLAUSIBLE 1 00038 00039 static char ataxx_colors[6] = {140, 160, 140, 200, 200, 200}; 00040 00041 static int ataxx_init_pos [ATAXX_BOARD_WID*ATAXX_BOARD_HEIT] = 00042 { 00043 1 , 0 , 0 , 0 , 0 , 0 , 2 , 00044 0 , 0 , 0 , 0 , 0 , 0 , 0 , 00045 0 , 0 , 0 , 0 , 0 , 0 , 0 , 00046 0 , 0 , 0 , 0 , 0 , 0 , 0 , 00047 0 , 0 , 0 , 0 , 0 , 0 , 0 , 00048 0 , 0 , 0 , 0 , 0 , 0 , 0 , 00049 2 , 0 , 0 , 0 , 0 , 0 , 1 , 00050 }; 00051 00052 void ataxx_init (); 00053 00054 Game Ataxx = { ATAXX_CELL_SIZE, ATAXX_BOARD_WID, ATAXX_BOARD_HEIT, 00055 ATAXX_NUM_PIECES, 00056 ataxx_colors, ataxx_init_pos, NULL, "Ataxx", ataxx_init}; 00057 00058 ResultType ataxx_eval (Pos *, Player, float *); 00059 byte *ataxx_movegen (Pos *); 00060 00061 static int ataxx_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **); 00062 static ResultType ataxx_who_won (Pos *, Player , char **); 00063 unsigned char * ataxx_get_rgbmap (int, int); 00064 void ataxx_reset_uistate (); 00065 00066 00067 static int ataxx_max_moves = 200; 00068 00069 void ataxx_init () 00070 { 00071 game_eval = ataxx_eval; 00072 game_movegen = ataxx_movegen; 00073 game_getmove = ataxx_getmove; 00074 game_who_won = ataxx_who_won; 00075 game_get_rgbmap = ataxx_get_rgbmap; 00076 game_white_string = "Red"; 00077 game_black_string = "Blue"; 00078 game_file_label = FILERANK_LABEL_TYPE_ALPHA; 00079 game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC; 00080 game_reset_uistate = ataxx_reset_uistate; 00081 game_allow_flip = TRUE; 00082 game_doc_about = 00083 "Ataxx\n" 00084 "Two player game\n" 00085 "Status: Fully implemented\n" 00086 "URL: "GAME_DEFAULT_URL("ataxx"); 00087 game_doc_rules = 00088 "Ataxx rules\n" 00089 "\n" 00090 " - The objective of the game is to get as many balls of your color as possible.\n" 00091 " - In each move you must click an existing ball of your color followed by an empty square.\n" 00092 " - The new square should be at a distance of at most 2 from the first square (a diagonal counts as one unit).\n" 00093 " - If the distance is two the first square becomes empty, but not if the distance is 1.\n" 00094 " - In either case all balls adjacent to the new square, if they are the opponent's color, get converted to your color.\n" 00095 " - If one player has no moves the player with more balls wins.\n"; 00096 } 00097 00098 ResultType ataxx_who_won (Pos *pos, Player to_play, char **commp) 00099 { 00100 static char comment[32]; 00101 int i, wscore = 0, bscore = 0, who_idx; 00102 char *who_str [3] = { "Red won", "Blue won", "its a tie" }; 00103 byte *move = ataxx_movegen (pos); 00104 for (i=0; i<board_wid * board_heit; i++) 00105 if (pos->board[i] == ATAXX_WP) 00106 wscore++; 00107 else if (pos->board[i] == ATAXX_BP) 00108 bscore++; 00109 if (move[0] != -2) 00110 { 00111 free (move); 00112 if (pos->num_moves > ataxx_max_moves) 00113 { 00114 fprintf (stderr, "max moves reached\n"); 00115 snprintf (comment, 32, "%s", who_str[2]); 00116 *commp = comment; 00117 return RESULT_TIE; 00118 } 00119 else 00120 { 00121 snprintf (comment, 32, "%d : %d", wscore, bscore); 00122 *commp = comment; 00123 return RESULT_NOTYET; 00124 } 00125 } 00126 free (move); 00127 if (wscore > bscore) who_idx = 0; 00128 else if (wscore < bscore) who_idx = 1; 00129 else who_idx = 2; 00130 snprintf (comment, 32, "%s (%d : %d)", who_str [who_idx], wscore, bscore); 00131 *commp = comment; 00132 if (wscore > bscore) 00133 return RESULT_WHITE; 00134 if (wscore < bscore) 00135 return RESULT_BLACK; 00136 return RESULT_TIE; 00137 } 00138 00139 00140 ResultType ataxx_eval (Pos *pos, Player to_play, float *eval) 00141 { 00142 int i; 00143 int wcount, bcount; 00144 for (i=0, wcount=0, bcount=0; i<board_wid*board_heit; i++) 00145 { 00146 if (pos->board[i] == ATAXX_WP) wcount++; 00147 if (pos->board[i] == ATAXX_BP) bcount++; 00148 } 00149 *eval = wcount-bcount; 00150 if (!wcount || !bcount) *eval *= GAME_EVAL_INFTY; 00151 if (!wcount) return RESULT_BLACK; 00152 if (!bcount) return RESULT_WHITE; 00153 return RESULT_NOTYET; 00154 } 00155 00156 byte *ataxx_movegen (Pos *pos) 00157 /* to keep things from getting out of hand, we'll generate only 00158 _plausible_ moves: find the max #flips possible and generate 00159 only those moves that lead to at least max-1 flips */ 00160 { 00161 int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1}; 00162 int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1}; 00163 int incx2[] = { -2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2}; 00164 int incy2[] = { -2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2}; 00165 int x, y, i, j, newx, newy; 00166 Player player = pos->player; 00167 byte our = (player == WHITE ? ATAXX_WP : ATAXX_BP); 00168 byte other = (player == WHITE ? ATAXX_BP : ATAXX_WP); 00169 byte *board = pos->board; 00170 #ifdef ATAXX_MOVEGEN_PLAUSIBLE 00171 int max_nbrs; 00172 #endif 00173 int found = 0; 00174 byte movbuf [4096]; 00175 byte *movp = movbuf; 00176 byte *movlist; 00177 byte *nbrs; 00178 nbrs = (byte *) malloc (board_wid * board_heit * sizeof (byte)); 00179 assert (nbrs); 00180 for (i=0; i<board_wid * board_heit; i++) 00181 nbrs[i] = 0; 00182 for (x=0; x<board_wid; x++) 00183 for (y=0; y<board_heit; y++) 00184 { 00185 if (board [y * board_wid + x] != other) 00186 continue; 00187 for (i=0; i<8; i++) 00188 { 00189 newx = x + incx[i]; 00190 newy = y + incy[i]; 00191 if (newx >= 0 && newy >= 0 00192 && newx < board_wid && newy < board_heit) 00193 nbrs [newy * board_wid + newx] ++; 00194 } 00195 } 00196 #ifdef ATAXX_MOVEGEN_PLAUSIBLE 00197 max_nbrs=0; 00198 for (x=0; x<board_wid; x++) 00199 for (y=0; y<board_heit; y++) 00200 if (board[y * board_wid + x] == ATAXX_EMPTY 00201 && nbrs[y * board_wid + x] > max_nbrs) 00202 { 00203 found=0; 00204 for (j=0; j<8; j++) 00205 { 00206 newx = x + incx[j]; 00207 newy = y + incy[j]; 00208 if (newx >= 0 && newy >= 0 00209 && newx < board_wid && newy < board_heit 00210 && board [newy * board_wid + newx] == our) 00211 { 00212 max_nbrs = nbrs[y * board_wid + x]; 00213 found=1; 00214 break; 00215 } 00216 } 00217 /*if (found) continue; 00218 nbrs [y * board_wid + x]--; 00219 if (nbrs[y * board_wid + x] <= max_nbrs) continue; 00220 for (j=0; j<16; j++) 00221 { 00222 newx = x + incx2[j]; 00223 newy = y + incy2[j]; 00224 if (newx >= 0 && newy >= 0 00225 && newx < board_wid && newy < board_heit 00226 && board [newy * board_wid + newx] == our) 00227 { 00228 max_nbrs = nbrs[y * board_wid + x]; 00229 break; 00230 } 00231 }*/ 00232 } 00233 #endif 00234 for (x=0; x<board_wid; x++) 00235 for (y=0; y<board_heit; y++) 00236 { 00237 found=0; 00238 if (board [y * board_wid + x] != ATAXX_EMPTY) 00239 continue; 00240 #ifdef ATAXX_MOVEGEN_PLAUSIBLE 00241 if (nbrs [y * board_wid + x] < max_nbrs - 1) 00242 continue; 00243 #endif 00244 for (i=0; i<8; i++) 00245 { 00246 newx = x + incx[i]; 00247 newy = y + incy[i]; 00248 if (newx >= 0 && newy >= 0 00249 && newx < board_wid && newy < board_heit) 00250 if (board [newy * board_wid + newx] == our) 00251 { 00252 /* found a same col neighbor */ 00253 found=1; 00254 break; 00255 } 00256 } 00257 if (found) 00258 { 00259 *movp++ = x; 00260 *movp++ = y; 00261 *movp++ = our; 00262 for (i=0; i<8; i++) 00263 { 00264 newx = x + incx[i]; 00265 newy = y + incy[i]; 00266 if (newx >= 0 && newy >= 0 00267 && newx < board_wid && newy < board_heit) 00268 if (board [newy * board_wid + newx] == other) 00269 { 00270 *movp++ = newx; 00271 *movp++ = newy; 00272 *movp++ = our; 00273 } 00274 } 00275 *movp++ = -1; 00276 } 00277 else 00278 { 00279 for (i=0; i<16; i++) 00280 { 00281 newx = x + incx2[i]; 00282 newy = y + incy2[i]; 00283 if (!(newx >= 0 && newy >= 0 00284 && newx < board_wid && newy < board_heit)) 00285 continue; 00286 if (board [newy * board_wid + newx] != our) 00287 continue; 00288 *movp++ = x; 00289 *movp++ = y; 00290 *movp++ = our; 00291 *movp++ = newx; 00292 *movp++ = newy; 00293 *movp++ = ATAXX_EMPTY; 00294 for (j=0; j<8; j++) 00295 { 00296 newx = x + incx[j]; 00297 newy = y + incy[j]; 00298 if (newx >= 0 && newy >= 0 00299 && newx < board_wid && newy < board_heit) 00300 if (board [newy * board_wid + newx] == other) 00301 { 00302 *movp++ = newx; 00303 *movp++ = newy; 00304 *movp++ = our; 00305 } 00306 } 00307 *movp++ = -1; 00308 } 00309 } 00310 } 00311 *movp++ = -2; 00312 movlist = (byte *) (malloc (movp - movbuf)); 00313 memcpy (movlist, movbuf, (movp - movbuf)); 00314 free (nbrs); 00315 return movlist; 00316 00317 } 00318 00319 static int oldx = -1, oldy = -1; 00320 00321 void ataxx_reset_uistate () 00322 { 00323 oldx = -1, oldy = -1; 00324 } 00325 00326 int ataxx_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, byte **movp, int **rmovep) 00327 { 00328 static byte move[32]; 00329 static int rmove[4]; 00330 byte *mptr = move; 00331 int *rp = rmove; 00332 int diffx, diffy; 00333 int other, i; 00334 int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1}; 00335 int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1}; 00336 if (type != GTKBOARD_BUTTON_RELEASE) 00337 return 0; 00338 if (oldx == -1) 00339 { 00340 if (pos->board [y * board_wid + x] != (to_play == WHITE ? ATAXX_WP : ATAXX_BP)) 00341 return -1; 00342 oldx = x; oldy = y; 00343 *rp++ = x; 00344 *rp++ = y; 00345 *rp++ = RENDER_HIGHLIGHT1; 00346 *rp++ = -1; 00347 *rmovep = rmove; 00348 return 0; 00349 } 00350 00351 if (x == oldx && y == oldy) 00352 { 00353 *rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove; 00354 oldx = -1; oldy = -1; return 0; 00355 } 00356 if (pos->board [y * board_wid + x] != ATAXX_EMPTY) 00357 { 00358 *rp++ = oldx; *rp++ = oldy; *rp++ = RENDER_NONE; *rp++ = -1; *rmovep = rmove; 00359 return oldx = oldy = -1; 00360 } 00361 diffx = abs (x - oldx); diffy = abs (y - oldy); 00362 if (diffx > 2 || diffy > 2) { return oldx = oldy = -1; } 00363 if (diffx > 1 || diffy > 1) 00364 { *mptr++ = oldx; *mptr++ = oldy; *mptr++ = ATAXX_EMPTY; } 00365 other = (to_play == WHITE ? ATAXX_BP : ATAXX_WP); 00366 for (i=0; i<8; i++) 00367 { 00368 int newx = x + incx[i], newy = y + incy[i]; 00369 if (newx < 0 || newy < 0 || newx >= board_wid || newy >= board_heit) 00370 continue; 00371 if (pos->board[newy * board_wid + newx] == other) 00372 { 00373 *mptr++ = newx; *mptr++ = newy; 00374 *mptr++ = (to_play == WHITE ? ATAXX_WP : ATAXX_BP); 00375 } 00376 } 00377 { *mptr++ = x; *mptr++ = y; *mptr++ = 00378 (to_play == WHITE ? ATAXX_WP : ATAXX_BP); } 00379 *mptr = -1; 00380 if (movp) 00381 *movp = move; 00382 *rp++ = oldx; 00383 *rp++ = oldy; 00384 *rp++ = RENDER_NONE; 00385 *rp++ = -1; 00386 *rmovep = rmove; 00387 oldx = -1; oldy = -1; 00388 return 1; 00389 } 00390 00391 unsigned char * ataxx_get_rgbmap (int idx, int color) 00392 { 00393 int fg, bg, i; 00394 char *colors; 00395 static char rgbbuf[3 * ATAXX_CELL_SIZE * ATAXX_CELL_SIZE]; 00396 colors = ataxx_colors; 00397 fg = (idx == ATAXX_WP ? 0xee << 16 : 0xee); 00398 if (color == BLACK) colors += 3; 00399 for(i=0, bg=0;i<3;i++) 00400 { int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));} 00401 rgbmap_ball_shadow_gen(55, rgbbuf, fg, bg, 17.0, 35.0, 3); 00402 return rgbbuf; 00403 } 00404