This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

ataxx.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 <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