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 <stdlib.h> 00021 #include <string.h> 00022 #include <assert.h> 00023 00024 #include "game.h" 00025 #include "aaball.h" 00026 00027 #define STOPGATE_CELL_SIZE 40 00028 #define STOPGATE_NUM_PIECES 4 00029 00030 #define STOPGATE_BOARD_WID 9 00031 #define STOPGATE_BOARD_HEIT 9 00032 00033 char stopgate_colors[6] = {180, 200, 180, 200, 140, 140}; 00034 00035 static char * blue_gate_north_40_xpm [] = 00036 { 00037 "40 40 2 1", 00038 " c none", 00039 ". c #0000ff", 00040 " ............ ", 00041 " ............ ", 00042 " ............ ", 00043 " ............ ", 00044 " ............ ", 00045 " ............ ", 00046 " ............ ", 00047 " ............ ", 00048 " ............ ", 00049 " ............ ", 00050 " ............ ", 00051 " ............ ", 00052 " ............ ", 00053 " ............ ", 00054 " ............ ", 00055 " ............ ", 00056 " ............ ", 00057 " ............ ", 00058 " ............ ", 00059 " ............ ", 00060 " ............ ", 00061 " ............ ", 00062 " ............ ", 00063 " ............ ", 00064 " ............ ", 00065 " ............ ", 00066 " ", 00067 " ", 00068 " ", 00069 " ", 00070 " ", 00071 " ", 00072 " ", 00073 " ", 00074 " ", 00075 " ", 00076 " ", 00077 " ", 00078 " ", 00079 " ", 00080 }; 00081 00082 static char * blue_gate_south_40_xpm [] = 00083 { 00084 "40 40 2 1", 00085 " c none", 00086 ". c #0000ff", 00087 " ", 00088 " ", 00089 " ", 00090 " ", 00091 " ", 00092 " ", 00093 " ", 00094 " ", 00095 " ", 00096 " ", 00097 " ", 00098 " ", 00099 " ", 00100 " ", 00101 " ............ ", 00102 " ............ ", 00103 " ............ ", 00104 " ............ ", 00105 " ............ ", 00106 " ............ ", 00107 " ............ ", 00108 " ............ ", 00109 " ............ ", 00110 " ............ ", 00111 " ............ ", 00112 " ............ ", 00113 " ............ ", 00114 " ............ ", 00115 " ............ ", 00116 " ............ ", 00117 " ............ ", 00118 " ............ ", 00119 " ............ ", 00120 " ............ ", 00121 " ............ ", 00122 " ............ ", 00123 " ............ ", 00124 " ............ ", 00125 " ............ ", 00126 " ............ ", 00127 }; 00128 00129 static char * blue_gate_east_40_xpm [] = 00130 { 00131 "40 40 2 1", 00132 " c none", 00133 ". c #0000ff", 00134 " ", 00135 " ", 00136 " ", 00137 " ", 00138 " ", 00139 " ", 00140 " ", 00141 " ", 00142 " ", 00143 " ", 00144 " ", 00145 " ", 00146 " ", 00147 " ", 00148 " ..........................", 00149 " ..........................", 00150 " ..........................", 00151 " ..........................", 00152 " ..........................", 00153 " ..........................", 00154 " ..........................", 00155 " ..........................", 00156 " ..........................", 00157 " ..........................", 00158 " ..........................", 00159 " ..........................", 00160 " ", 00161 " ", 00162 " ", 00163 " ", 00164 " ", 00165 " ", 00166 " ", 00167 " ", 00168 " ", 00169 " ", 00170 " ", 00171 " ", 00172 " ", 00173 " ", 00174 }; 00175 00176 static char * blue_gate_west_40_xpm [] = 00177 { 00178 "40 40 2 1", 00179 " c none", 00180 ". c #0000ff", 00181 " ", 00182 " ", 00183 " ", 00184 " ", 00185 " ", 00186 " ", 00187 " ", 00188 " ", 00189 " ", 00190 " ", 00191 " ", 00192 " ", 00193 " ", 00194 " ", 00195 ".......................... ", 00196 ".......................... ", 00197 ".......................... ", 00198 ".......................... ", 00199 ".......................... ", 00200 ".......................... ", 00201 ".......................... ", 00202 ".......................... ", 00203 ".......................... ", 00204 ".......................... ", 00205 ".......................... ", 00206 ".......................... ", 00207 " ", 00208 " ", 00209 " ", 00210 " ", 00211 " ", 00212 " ", 00213 " ", 00214 " ", 00215 " ", 00216 " ", 00217 " ", 00218 " ", 00219 " ", 00220 " ", 00221 }; 00222 00223 00224 char ** stopgate_pixmaps [] = 00225 { 00226 blue_gate_north_40_xpm, 00227 blue_gate_south_40_xpm, 00228 blue_gate_east_40_xpm, 00229 blue_gate_west_40_xpm, 00230 }; 00231 00232 00233 #define STOPGATE_NORTH 1 00234 #define STOPGATE_SOUTH 2 00235 #define STOPGATE_EAST 3 00236 #define STOPGATE_WEST 4 00237 #define STOPGATE_EMPTY 0 00238 00239 #define abs(x) ((x) < 0 ? -(x) : (x)) 00240 00241 int stopgate_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **); 00242 void stopgate_init (); 00243 ResultType stopgate_who_won (Pos *, Player, char **); 00244 ResultType stopgate_eval (Pos *, Player, float *eval); 00245 byte * stopgate_movegen (Pos *); 00246 00247 Game Stopgate = { STOPGATE_CELL_SIZE, STOPGATE_BOARD_WID, STOPGATE_BOARD_HEIT, 00248 STOPGATE_NUM_PIECES, 00249 stopgate_colors, NULL, stopgate_pixmaps, "Stopgate", stopgate_init}; 00250 00251 static int stopgate_curx = - 1, stopgate_cury = -1; 00252 00253 00254 void stopgate_init () 00255 { 00256 game_getmove = stopgate_getmove; 00257 game_who_won = stopgate_who_won; 00258 game_eval = stopgate_eval; 00259 game_movegen = stopgate_movegen; 00260 game_white_string = "White"; 00261 game_black_string = "Black"; 00262 game_doc_about = 00263 "Stopgate\n" 00264 "Two player game\n" 00265 "Status: Fully implemented\n" 00266 "URL: "GAME_DEFAULT_URL ("stopgate"); 00267 } 00268 00269 static int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1}; 00270 static int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1}; 00271 00272 ResultType stopgate_who_won (Pos *pos, Player player, char ** commp) 00273 { 00274 char *who_str[2] = {"Vertical won", "Horizontal won"}; 00275 int wscore, bscore, i, j; 00276 float eval; 00277 ResultType result; 00278 result = stopgate_eval (pos, player, &eval); 00279 if (result == RESULT_WHITE) *commp = who_str[0]; 00280 if (result == RESULT_BLACK) *commp = who_str[1]; 00281 printf ("%f\n", eval); 00282 return result; 00283 /* if (abs (eval) < GAME_EVAL_INFTY) 00284 return RESULT_NOTYET; 00285 if (eval > 0) 00286 { 00287 *commp = who_str[0]; 00288 return RESULT_WHITE; 00289 } 00290 else 00291 { 00292 *commp = who_str[1]; 00293 return RESULT_BLACK; 00294 } 00295 */ 00296 } 00297 00298 #define EVAL_ISEMPTY(x, y) ((ISINBOARD((x), (y))) && (board[(y) * board_wid + (x)] == STOPGATE_EMPTY)) 00299 00300 #define EVAL_OPENSQUARE(x, y) (EVAL_ISEMPTY ((x), (y)) && (EVAL_ISEMPTY ((x)-1,(y)) || EVAL_ISEMPTY ((x)+1, (y))) && (EVAL_ISEMPTY ((x),(y)-1) || EVAL_ISEMPTY ((x), (y)+1))) 00301 00302 enum { 00303 REGION_WHITE = STOPGATE_NUM_PIECES + 1, 00304 REGION_BLACK, 00305 REGION_OPEN_X = 1 << 4, 00306 REGION_OPEN_Y = 1 << 5, 00307 }; 00308 00309 00310 00311 static int regions[STOPGATE_BOARD_WID * STOPGATE_BOARD_HEIT]; 00312 00313 /* Find which regions are open, which are vertical (REGION_WHITE) and which 00314 are horizontal (REGION_BLACK) 00315 clever algo that avoids a queue: every square in an open region must 00316 be on a straight line from a square which has unfilled nbrs in both directions 00317 */ 00318 static void find_regions (byte *board) 00319 { 00320 int i, j; 00321 static int count = 0; 00322 for (i=0; i<board_wid*board_heit; i++) 00323 regions[i] = 0; 00324 for (i=0; i < board_wid; i++) 00325 for (j=0; j < board_heit; j++) 00326 { 00327 int x; 00328 if (regions [j * board_wid + i] & REGION_OPEN_X) 00329 continue; 00330 if (EVAL_OPENSQUARE (i, j)) 00331 { 00332 for (x=i; EVAL_ISEMPTY (x, j); x++) 00333 regions [j * board_wid + x] |= REGION_OPEN_X; 00334 for (x=i; EVAL_ISEMPTY (x, j); x--) 00335 regions [j * board_wid + x] |= REGION_OPEN_X; 00336 } 00337 } 00338 for (i=0; i < board_wid; i++) 00339 for (j=0; j < board_heit; j++) 00340 { 00341 int y; 00342 if (regions [j * board_wid + i] & REGION_OPEN_Y) 00343 continue; 00344 if (EVAL_OPENSQUARE (i, j)) 00345 { 00346 for (y=j; EVAL_ISEMPTY (i, y); y++) 00347 regions [y * board_wid + i] |= REGION_OPEN_Y; 00348 for (y=j; EVAL_ISEMPTY (i, y); y--) 00349 regions [y * board_wid + i] |= REGION_OPEN_Y; 00350 } 00351 } 00352 for (i=0; i < board_wid; i++) 00353 for (j=0; j < board_heit; j++) 00354 if (board [j * board_wid + i] == 0 && regions[j * board_wid + i] == 0) 00355 { 00356 if (EVAL_ISEMPTY (i,j+1) || EVAL_ISEMPTY (i,j-1)) 00357 regions[j * board_wid + i] = REGION_WHITE; 00358 else if (EVAL_ISEMPTY (i+1,j) || EVAL_ISEMPTY (i-1,j)) 00359 regions[j * board_wid + i] = REGION_BLACK; 00360 } 00361 // TODO: find the lengths of the runs also 00362 } 00363 00364 00365 byte * stopgate_movegen (Pos *pos) 00366 { 00367 int i, j; 00368 byte movbuf [512], *movp = movbuf, *movlist; 00369 byte *board = pos->board; 00370 Player player = pos->player; 00371 for (i=0; i<board_wid; i++) 00372 for (j=0; j<board_heit; j++) 00373 { 00374 int incx = (player == WHITE ? 0 : 1), incy = (player == WHITE ? 1 : 0); 00375 if (board [j * board_wid + i] != STOPGATE_EMPTY) continue; 00376 if (!ISINBOARD (i + incx, j + incy)) continue; 00377 if (pos->board [(j + incy) * board_wid + (i + incx)] != STOPGATE_EMPTY) continue; 00378 if (!EVAL_OPENSQUARE (i, j) && !EVAL_OPENSQUARE (i + incx, j + incy)) 00379 continue; 00380 *movp++ = i; 00381 *movp++ = j; 00382 *movp++ = (player == WHITE ? STOPGATE_NORTH : STOPGATE_EAST); 00383 *movp++ = i + incx; 00384 *movp++ = j + incy; 00385 *movp++ = (player == WHITE ? STOPGATE_SOUTH : STOPGATE_WEST); 00386 *movp++ = -1; 00387 } 00388 *movp++ = -2; 00389 movlist = (byte *) (malloc (movp - movbuf)); 00390 memcpy (movlist, movbuf, (movp - movbuf)); 00391 return movlist; 00392 } 00393 00394 00395 ResultType stopgate_eval (Pos *pos, Player player, float *eval) 00396 { 00397 int i, j; 00398 float val = 0; 00399 gboolean wfound = FALSE, bfound = FALSE, openfound = FALSE; 00400 int run_len=0; 00401 int run_eval_w = 0, run_eval_b = 0; 00402 byte *board = pos->board; 00403 find_regions (board); 00404 for (i=0; i<board_wid; i++) 00405 { 00406 for (j=0; j<board_heit; j++) 00407 if (regions[j * board_wid + i] == REGION_WHITE) 00408 run_len++; 00409 else 00410 { 00411 run_eval_w += 2 * (run_len / 2); 00412 run_len = 0; 00413 } 00414 run_eval_w += 2 * (run_len / 2); 00415 run_len = 0; 00416 } 00417 for (j=0; j<board_heit; j++) 00418 { 00419 for (i=0; i<board_wid; i++) 00420 if (regions[j * board_wid + i] == REGION_BLACK) 00421 run_len++; 00422 else 00423 { 00424 run_eval_b += 2 * (run_len / 2); 00425 run_len = 0; 00426 } 00427 run_eval_b += 2 * (run_len / 2); 00428 run_len = 0; 00429 } 00430 val = run_eval_w - run_eval_b; 00431 /* if (++count == 5000) 00432 { 00433 count = 0; 00434 val = run_eval_w - run_eval_b; 00435 printf ("%d, %d\n", run_eval_w, run_eval_b); 00436 for (j=board_heit-1; j>=0; j--) 00437 { 00438 for (i=0; i<board_wid; i++) 00439 { 00440 if (board [j * board_wid + i]) 00441 printf (" #"); 00442 else if (regions[j * board_wid + i] == REGION_WHITE) 00443 printf (" W"); 00444 else if (regions[j * board_wid + i] == REGION_BLACK) 00445 printf (" B"); 00446 else printf (" _"); 00447 } 00448 printf ("\n"); 00449 } 00450 printf ("\n"); 00451 } 00452 */ 00453 for (i=0; i<board_wid; i++) 00454 for (j=0; j<board_heit; j++) 00455 { 00456 if (board [j * board_wid + i] != STOPGATE_EMPTY) continue; 00457 if (regions[j * board_wid + i] == REGION_WHITE) 00458 wfound = TRUE; 00459 else if (regions[j * board_wid + i] == REGION_BLACK) 00460 bfound = TRUE; 00461 else 00462 { 00463 if (EVAL_ISEMPTY (i, j+1) || EVAL_ISEMPTY (i, j-1)) 00464 { 00465 val++; 00466 wfound = TRUE; 00467 openfound = TRUE; 00468 } 00469 if (EVAL_ISEMPTY (i+1, j) || EVAL_ISEMPTY (i-1, j)) 00470 { 00471 val--; 00472 bfound = TRUE; 00473 openfound = TRUE; 00474 } 00475 } 00476 } 00477 if (!openfound) 00478 { 00479 val += (player == WHITE ? -1 : 1); 00480 *eval = val; 00481 return val > 0 ? RESULT_WHITE : RESULT_BLACK; 00482 } 00483 if (player == WHITE && !wfound) 00484 { 00485 *eval = (val-1); 00486 return RESULT_BLACK; 00487 } 00488 if (player == BLACK && !bfound) 00489 { 00490 *eval = (val+1); 00491 return RESULT_WHITE; 00492 } 00493 *eval = val + 0.01 * random () / RAND_MAX; 00494 return RESULT_NOTYET; 00495 } 00496 00497 int stopgate_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, 00498 byte **movp, int **rmovp) 00499 { 00500 int i, j, sw_len, found=0; 00501 static byte move[128]; 00502 byte *mp = move; 00503 int diffx, diffy, dir1 = -1, dir2 = -1; 00504 if (type == GTKBOARD_BUTTON_PRESS) 00505 { 00506 if (pos->board [y * board_wid + x] != STOPGATE_EMPTY) 00507 return -1; 00508 stopgate_curx = x; 00509 stopgate_cury = y; 00510 return 0; 00511 } 00512 if (type != GTKBOARD_BUTTON_RELEASE) 00513 return 0; 00514 if (stopgate_curx < 0) return -1; 00515 diffx = x - stopgate_curx; 00516 diffy = y - stopgate_cury; 00517 if (to_play == WHITE && diffx == 0 && diffy == 1) 00518 dir1 = STOPGATE_NORTH, dir2 = STOPGATE_SOUTH; 00519 else if (to_play == WHITE && diffx == 0 && diffy == -1) 00520 dir1 = STOPGATE_SOUTH, dir2 = STOPGATE_NORTH; 00521 else if (to_play == BLACK && diffx == 1 && diffy == 0) 00522 dir1 = STOPGATE_EAST, dir2 = STOPGATE_WEST; 00523 else if (to_play == BLACK && diffx == -1 && diffy == 0) 00524 dir1 = STOPGATE_WEST, dir2 = STOPGATE_EAST; 00525 else 00526 { 00527 stopgate_curx = stopgate_cury = -1; 00528 return -1; 00529 } 00530 if (pos->board [y * board_wid + x] != STOPGATE_EMPTY) 00531 { 00532 stopgate_curx = stopgate_cury = -1; 00533 return -1; 00534 } 00535 *mp++ = stopgate_curx; 00536 *mp++ = stopgate_cury; 00537 *mp++ = dir1; 00538 *mp++ = x; 00539 *mp++ = y; 00540 *mp++ = dir2; 00541 *mp++ = -1; 00542 *movp = move; 00543 return 1; 00544 } 00545 00546 00547