This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

stopgate.c

Go to the documentation of this file.
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