This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

dotsandboxes.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 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 }