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 DNB_CELL_SIZE 24 00028 #define DNB_NUM_PIECES 5 00029 00030 #define DNB_BOARD_SIZE 10 00031 00032 #define DNB_BOARD_WID (2*DNB_BOARD_SIZE+1) 00033 #define DNB_BOARD_HEIT (2*DNB_BOARD_SIZE+1) 00034 00035 char dnb_colors[6] = {220, 220, 220, 220, 220, 220}; 00036 00037 static char * dnb_red_24_xpm [] = 00038 { 00039 "24 24 1 1", 00040 " c #ee0000", 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 static char * dnb_blue_24_xpm [] = 00068 { 00069 "24 24 1 1", 00070 " c #0000ee", 00071 " ", 00072 " ", 00073 " ", 00074 " ", 00075 " ", 00076 " ", 00077 " ", 00078 " ", 00079 " ", 00080 " ", 00081 " ", 00082 " ", 00083 " ", 00084 " ", 00085 " ", 00086 " ", 00087 " ", 00088 " ", 00089 " ", 00090 " ", 00091 " ", 00092 " ", 00093 " ", 00094 " ", 00095 }; 00096 00097 static char * dnb_vertical_24_xpm [] = 00098 { 00099 "24 24 2 1", 00100 " c none", 00101 ". c #101010", 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 static char * dnb_horizontal_24_xpm [] = 00129 { 00130 "24 24 2 1", 00131 " c none", 00132 ". c #101010", 00133 " ", 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 /*char ** dnb_pixmaps [] = 00161 { 00162 blue_gate_horiz_40_xpm, 00163 blue_gate_south_40_xpm, 00164 blue_gate_east_40_xpm, 00165 blue_gate_west_40_xpm, 00166 };*/ 00167 00168 00169 #define DNB_EMPTY 0 00170 #define DNB_DOT 1 00171 #define DNB_HOR 2 00172 #define DNB_VERT 3 00173 #define DNB_RED 4 00174 #define DNB_BLUE 5 00175 00176 #define abs(x) ((x) < 0 ? -(x) : (x)) 00177 00178 int dnb_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **); 00179 void dnb_search (Pos *pos, byte **movp); 00180 void dnb_init (); 00181 ResultType dnb_who_won (Pos *, Player, char **); 00182 void dnb_set_init_pos (Pos *pos); 00183 char ** dnb_get_pixmap (int idx, int color); 00184 int dnb_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, 00185 byte **movp, int **rmovp); 00186 static void dnb_get_render (Pos *pos, byte *move, int **rmovp); 00187 00188 Game Dnb = { DNB_CELL_SIZE, DNB_BOARD_WID, DNB_BOARD_HEIT, 00189 DNB_NUM_PIECES, dnb_colors, NULL, NULL, "Dots and boxes", dnb_init}; 00190 00191 static int dnb_curx = - 1, dnb_cury = -1; 00192 00193 00194 void dnb_init () 00195 { 00196 // game_getmove = dnb_getmove; 00197 /* game_who_won = dnb_who_won; 00198 game_eval = dnb_eval; 00199 game_movegen = dnb_movegen; 00200 */ 00201 game_set_init_pos = dnb_set_init_pos; 00202 game_get_pixmap = dnb_get_pixmap; 00203 game_get_render = dnb_get_render; 00204 game_white_string = "Red"; 00205 game_black_string = "Blue"; 00206 game_getmove = dnb_getmove; 00207 game_search = dnb_search; 00208 game_allow_flip = TRUE; 00209 game_doc_about = 00210 "Dots and boxes\n" 00211 "Two player game\n" 00212 "Status: partially implemented (the AI is totally dumb)\n" 00213 "URL: "GAME_DEFAULT_URL ("dnb"); 00214 } 00215 00216 char ** dnb_get_pixmap (int idx, int color) 00217 { 00218 int bg, i; 00219 char *colors = dnb_colors; 00220 static char pixbuf[DNB_CELL_SIZE * (DNB_CELL_SIZE+1)]; 00221 if (color == BLACK) colors += 3; 00222 for(i=0, bg=0;i<3;i++) 00223 { int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));} 00224 if (idx == DNB_DOT) 00225 return pixmap_ball_gen (DNB_CELL_SIZE, pixbuf, 0x101010, bg, 8, 30); 00226 if (idx == DNB_VERT) return dnb_vertical_24_xpm; 00227 if (idx == DNB_HOR) return dnb_horizontal_24_xpm; 00228 if (idx == DNB_RED) return dnb_red_24_xpm; 00229 if (idx == DNB_BLUE) return dnb_blue_24_xpm; 00230 return NULL; 00231 } 00232 00233 void dnb_set_init_pos (Pos *pos) 00234 { 00235 int i, j; 00236 for (i=0; i<board_wid; i++) 00237 for (j=0; j<board_heit; j++) 00238 if (i%2 == 0 && j%2 == 0) 00239 pos->board[j * board_wid + i] = DNB_DOT; 00240 else 00241 pos->board[j * board_wid + i] = DNB_EMPTY; 00242 } 00243 00244 /* 00245 ResultType dnb_who_won (Pos *pos, Player player, char ** commp) 00246 { 00247 char *who_str[2] = {"Vertical won", "Horizontal won"}; 00248 int wscore, bscore, i, j; 00249 float eval; 00250 ResultType result; 00251 result = dnb_eval (pos, player, &eval); 00252 if (result == RESULT_WHITE) *commp = who_str[0]; 00253 if (result == RESULT_BLACK) *commp = who_str[1]; 00254 printf ("%f\n", eval); 00255 return result; 00256 } 00257 */ 00258 00259 static int dnb_incx[] = {-1, 0, 0, 1}; 00260 static int dnb_incy[] = {0, -1, 1, 0}; 00261 00262 static int num_nbr_walls (byte *board, int *render, int x, int y) 00263 { 00264 int k, newx, newy; 00265 int count; 00266 if (x % 2 == 0 || y % 2 == 0) 00267 return -1; 00268 for (k=0, count=0; k<4; k++) 00269 { 00270 newx = x + dnb_incx[k]; 00271 newy = y + dnb_incy[k]; 00272 if (board [newy * board_wid + newx] != DNB_EMPTY || 00273 (render && render[newy * board_wid + newx] != RENDER_NONE)) 00274 count++; 00275 } 00276 return count; 00277 } 00278 00279 int dnb_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player player, 00280 byte **movp, int **rmovp) 00281 { 00282 int incx, incy; 00283 int newx, newy; 00284 static byte move[2048]; 00285 static int rmove[16]; 00286 byte *mp = move; 00287 int *rp = rmove; 00288 int i, j, k; 00289 gboolean found; 00290 00291 if (type == GTKBOARD_BUTTON_PRESS) 00292 { 00293 if (pos->board [y * board_wid + x] != DNB_DOT) 00294 return -1; 00295 dnb_curx = x; 00296 dnb_cury = y; 00297 return 0; 00298 } 00299 00300 if (type != GTKBOARD_BUTTON_RELEASE) 00301 return 0; 00302 00303 if (dnb_curx < 0) return -1; 00304 00305 if ((x != dnb_curx && y != dnb_cury) || (x == dnb_curx && y == dnb_cury)) 00306 { dnb_curx = dnb_cury = -1; return -1; } 00307 00308 if (x == dnb_curx) 00309 { 00310 incx = 0; 00311 incy = y > dnb_cury ? 1 : -1; 00312 } 00313 else 00314 { 00315 incy = 0; 00316 incx = x > dnb_curx ? 1 : -1; 00317 } 00318 00319 newx = dnb_curx + incx; 00320 newy = dnb_cury + incy; 00321 if (pos->board [newy * board_wid + newx] != DNB_EMPTY || 00322 pos->render [newy * board_wid + newx] != RENDER_NONE) 00323 { dnb_curx = dnb_cury = -1; return -1; } 00324 00325 *rp++ = newx; 00326 *rp++ = newy; 00327 *rp++ = RENDER_REPLACE | ((dnb_curx == x ? DNB_VERT : DNB_HOR) << 8); 00328 dnb_curx = dnb_cury = -1; 00329 00330 // do we complete a square 00331 found = FALSE; 00332 for (k=0; k<4; k++) 00333 { 00334 x = newx + dnb_incx[k]; 00335 y = newy + dnb_incy[k]; 00336 if (pos->board [y * board_wid + x] == DNB_EMPTY) 00337 if (num_nbr_walls (pos->board, pos->render, x, y) == 3) 00338 { 00339 *rp++ = x; 00340 *rp++ = y; 00341 *rp++ = RENDER_REPLACE | ((player == WHITE ? DNB_RED : DNB_BLUE) << 8); 00342 found = TRUE; 00343 } 00344 } 00345 *rp++ = -1; 00346 if (found) 00347 { 00348 *rmovp = rmove; 00349 return 0; 00350 } 00351 00352 else 00353 { 00354 for (i=0; rmove[3*i] >= 0; i++) 00355 if ((rmove [3*i+2] & 0xff) == RENDER_REPLACE) 00356 { 00357 *mp++ = rmove [3*i]; 00358 *mp++ = rmove [3*i+1]; 00359 *mp++ = rmove [3*i+2] >> 8; 00360 } 00361 for (i=0; i<board_wid; i++) 00362 for (j=0; j<board_heit; j++) 00363 if ((pos->render [j * board_wid + i] & 0xff) == RENDER_REPLACE) 00364 { 00365 *mp++ = i; 00366 *mp++ = j; 00367 *mp++ = pos->render [j * board_wid + i] >> 8; 00368 } 00369 *mp++ = -1; 00370 *movp = move; 00371 return 1; 00372 } 00373 } 00374 00375 static void dnb_get_render (Pos *pos, byte *move, int **rmovp) 00376 { 00377 static int rmove[2048]; 00378 int *rp = rmove; 00379 int i, j; 00380 for (i=0; i<board_wid; i++) 00381 for (j=0; j<board_heit; j++) 00382 if (pos->render [j * board_wid + i] != RENDER_NONE) 00383 { 00384 *rp++ = i; 00385 *rp++ = j; 00386 *rp++ = RENDER_NONE; 00387 } 00388 *rp++ = -1; 00389 *rmovp = rmove; 00390 } 00391 00392 00393 void dnb_search (Pos *pos, byte **movp) 00394 { 00395 /* first greedily close all possible squares, then choose some edge arbitrarily */ 00396 // TODO: this AI needs MAJOR improvement 00397 static byte move[2048]; 00398 byte *mp = move; 00399 int i, j; 00400 gboolean found; 00401 static byte newboard[DNB_BOARD_WID * DNB_BOARD_HEIT]; 00402 Player player = pos->player; 00403 memcpy (newboard, pos->board, board_wid * board_heit); 00404 00405 do // very slow, but speed probably doesn't matter here 00406 { 00407 found = FALSE; 00408 for (i=1; i<board_wid; i+=2) 00409 for (j=1; j<board_heit; j+=2) 00410 if (num_nbr_walls (newboard, NULL, i, j) == 3) 00411 { 00412 int k, newx, newy, newval; 00413 for (k=0; k<4; k++) 00414 { 00415 newx = i + dnb_incx[k]; 00416 newy = j + dnb_incy[k]; 00417 if (newboard [newy * board_wid + newx] == DNB_EMPTY) 00418 { 00419 newval = (newx % 2 == 0 ? DNB_VERT : DNB_HOR); 00420 *mp++ = newx; 00421 *mp++ = newy; 00422 *mp++ = newval; 00423 newboard [newy * board_wid + newx] = newval; 00424 } 00425 } 00426 newval = (player == WHITE ? DNB_RED : DNB_BLUE); 00427 *mp++ = i; 00428 *mp++ = j; 00429 *mp++ = newval; 00430 newboard [j * board_wid + i] = newval; 00431 found = TRUE; 00432 } 00433 } while (found); 00434 00435 while (1) // FIXME: inf. loop when game is over 00436 { 00437 i = random() % board_wid; 00438 j = random() % board_heit; 00439 if ((i+j) % 2 == 0) continue; 00440 if (newboard [j * board_wid + i] != DNB_EMPTY) continue; 00441 *mp++ = i; 00442 *mp++ = j; 00443 *mp++ = (i % 2 == 0 ? DNB_VERT : DNB_HOR); 00444 *mp++ = -1; 00445 *movp = move; 00446 return; 00447 } 00448 }