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 00022 #include <stdio.h> 00023 #include <string.h> 00024 #include <assert.h> 00025 #include <stdlib.h> 00026 00027 #include "game.h" 00028 #include "aaball.h" 00029 00030 #define PLOT4_CELL_SIZE 55 00031 #define PLOT4_NUM_PIECES 3 00032 00033 #define PLOT4_BOARD_WID 7 00034 #define PLOT4_BOARD_HEIT 6 00035 00036 char plot4_colors[6] = {160, 140, 100, 160, 140, 100}; 00037 00038 int * plot4_init_pos = NULL; 00039 00040 #define PLOT4_WP 1 00041 #define PLOT4_BP 2 00042 #define PLOT4_EMPTY 3 00043 00044 00045 void plot4_init (); 00046 00047 Game Plot4 = { PLOT4_CELL_SIZE, PLOT4_BOARD_WID, PLOT4_BOARD_HEIT, 00048 PLOT4_NUM_PIECES, 00049 plot4_colors, NULL, NULL, "Plot4", plot4_init}; 00050 00051 00052 00053 static int eval_runs (Pos *, int); 00054 static int find_runs (byte *, int, int, int , int, int, int); 00055 static int plot4_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **); 00056 static ResultType plot4_who_won (Pos *, Player , char **); 00057 static void plot4_set_init_pos (Pos *pos); 00058 static char ** plot4_get_pixmap (int, int); 00059 static byte * plot4_movegen (Pos *); 00060 static ResultType plot4_eval (Pos *, Player, float *); 00061 00062 00063 static const int RUN_WT = 20; 00064 00065 00066 void plot4_init () 00067 { 00068 game_eval = plot4_eval; 00069 game_movegen = plot4_movegen; 00070 game_getmove = plot4_getmove; 00071 game_who_won = plot4_who_won; 00072 game_set_init_pos = plot4_set_init_pos; 00073 game_get_pixmap = plot4_get_pixmap; 00074 game_white_string = "Green"; 00075 game_black_string = "Yellow"; 00076 game_doc_about = 00077 "Plot4\n" 00078 "Two player game\n" 00079 "Status: Fully implemented\n" 00080 "URL: "GAME_DEFAULT_URL ("plot4"); 00081 game_doc_rules = 00082 "Plot4 rules\n" 00083 "\n" 00084 "Two players alternate in placing balls of either color on a 7x6 board. Not exactly placing, because the balls have gravity and fall down to the lowest unoccupied square on the column. The goal is to get as many 4-in-a-row's as possible. A 5-in-a-row counts as two, 6 as 3, and 7 as 4.\n"; 00085 } 00086 00087 void plot4_set_init_pos (Pos *pos) 00088 { 00089 int i; 00090 for (i=0; i<board_wid * board_heit; i++) 00091 pos->board [i] = PLOT4_EMPTY; 00092 } 00093 00094 ResultType plot4_who_won (Pos *pos, Player to_play, char **commp) 00095 { 00096 static char comment[32]; 00097 char *who_str [3] = { "Green won", "Yellow won", "Its a tie" }; 00098 int i, wscore, bscore, who_idx; 00099 wscore = eval_runs (pos, WHITE) / RUN_WT; 00100 bscore = eval_runs (pos, BLACK) / RUN_WT * -1; 00101 *commp = comment; 00102 for (i=0; i<board_wid * board_heit; i++) 00103 if (pos->board[i] == PLOT4_EMPTY) 00104 { 00105 snprintf (comment, 32, "%d : %d", wscore, bscore); 00106 return RESULT_NOTYET; 00107 } 00108 if (wscore > bscore) who_idx = 0; 00109 else if (wscore < bscore) who_idx = 1; 00110 else who_idx = 2; 00111 snprintf (comment, 32, "%s (%d : %d)", who_str[who_idx], wscore, bscore); 00112 if (wscore > bscore) 00113 return RESULT_WHITE; 00114 if (wscore < bscore) 00115 return RESULT_BLACK; 00116 return RESULT_TIE; 00117 } 00118 00119 int plot4_islegal (byte *board, int x, int y) 00120 /* check bounds 00121 check if (x,y) is empty 00122 check if (x, y-1) is not empty */ 00123 { 00124 return (x >= 0 && x < board_wid && y >= 0 && y < board_heit 00125 && (board[y * board_wid + x] == PLOT4_EMPTY) && 00126 ((y == 0) || (board [(y-1) * board_wid + x] != PLOT4_EMPTY))); 00127 } 00128 00129 int plot4_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, byte **movp, int ** rmovep) 00130 /* translate a sequence of mouse clicks into a cbgf move. 00131 pos is the current position, x and y are the square which was 00132 clicked, type is the event type: MOUSE_PRESSED, MOUSE_RELEASED 00133 to_play is who has the move, movp is used to return the move 00134 00135 the return value is 1 if the clicks were successfully translated 00136 into a move; -1 if the move is illegal, and 0 if further clicks 00137 are required to determine the move. In the latter case, this 00138 function is responsible for keeping track of the current state. 00139 */ 00140 { 00141 static byte move[4]; 00142 if (type != GTKBOARD_BUTTON_RELEASE) 00143 return 0; 00144 /* OK to click anywhere in the column */ 00145 for (y = 0; y < board_heit; y++) 00146 if (pos->board[y * board_wid + x] == PLOT4_EMPTY) 00147 break; 00148 if (y == board_heit) 00149 return -1; 00150 move[0] = x; 00151 move[1] = y; 00152 move[2] = to_play == WHITE ? PLOT4_WP : PLOT4_BP; 00153 move[3] = -1; 00154 if (movp) 00155 *movp = move; 00156 return 1; 00157 } 00158 00159 ResultType plot4_eval (Pos *pos, Player to_play, float *eval) 00160 /* always eval from POV of white */ 00161 { 00162 /* TODO : add some weights */ 00163 *eval = eval_runs (pos, -1); 00164 return RESULT_NOTYET; 00165 } 00166 00167 00168 00169 static int eval_runs (Pos *pos, int forwhom) 00170 /* sum of all the runs of forwhom (both if -1) from POV of WHITE */ 00171 { 00172 int sum = 0; 00173 int i, board_min, min; 00174 byte *board = pos->board; 00175 board_min = board_wid < board_heit ? board_wid : board_heit; 00176 for (i=0; i<board_wid; i++) 00177 sum += find_runs (board, i, 0, 0, 1, board_heit, forwhom); 00178 for (i=0; i<board_heit; i++) 00179 sum += find_runs (board, 0, i, 1, 0, board_wid, forwhom); 00180 for (i=0; i<board_wid; i++) 00181 { 00182 min = (board_wid - i) < board_min ? (board_wid - i) : board_min; 00183 sum += find_runs (board, i, 0, 1, 1, min, forwhom); 00184 sum += find_runs (board, board_wid - i - 1, 0, -1, 1, min, forwhom); 00185 } 00186 for (i=1; i<board_heit; i++) 00187 { 00188 min = (board_heit - i) < board_min ? (board_heit - i) : board_min; 00189 sum += find_runs (board, 0, i, 1, 1, min, forwhom); 00190 sum += find_runs (board, board_wid - 1, i, -1, 1, min, forwhom); 00191 } 00192 return sum; 00193 } 00194 00195 static int find_runs (byte *board, int x0, int y0, int dx, int dy, int len, 00196 int forwhom) 00197 /* OK this function is very ugly. if forwhom is -1 it returns an 00198 * eval of the given line. If not it returns a count forwhom's 00199 * score on that line, multiplied by RUN_WT */ 00200 { 00201 int sum = 0, i, cur = 0; /* cur = current run length */ 00202 int x = x0, y = y0; 00203 char prev = -1, cell; 00204 int lopen = 0, ropen = 0; /* can we extend this run in either direction*/ 00205 for (i=0; i<len; i++, x += dx, y += dy, prev = cell) 00206 { 00207 cell = board[y * board_wid + x]; 00208 if (cell == PLOT4_EMPTY) 00209 { 00210 cur=0; 00211 lopen = 1; 00212 continue; 00213 } 00214 if (cell != prev) 00215 cur = 0; 00216 cur ++; 00217 if (i < len - 1 && 00218 board [(y + dy) * board_wid + (x + dx)] == PLOT4_EMPTY) 00219 ropen = 1; 00220 else ropen = 0; 00221 if (cell == PLOT4_WP) 00222 { 00223 if (forwhom == -1) 00224 sum += ((ropen + lopen) * (cur * cur)); 00225 if (forwhom != BLACK && cur >= 4) 00226 sum += RUN_WT; 00227 } 00228 if (cell == PLOT4_BP) 00229 { 00230 if (forwhom == -1) 00231 sum -= ((ropen + lopen) * (cur * cur)); 00232 if (forwhom != WHITE && cur >= 4) 00233 sum -= RUN_WT; 00234 } 00235 lopen = 0; 00236 } 00237 return sum; 00238 } 00239 00240 byte * plot4_movegen_single (char *pos, int player, int reset) 00241 /* return a move terminated by -1 */ 00242 /* NULL ==> no more moves */ 00243 { 00244 static int row; 00245 static byte movbuf[4]; 00246 if (reset) 00247 row = 0; 00248 while (row < board_wid) 00249 { 00250 int j; 00251 for (j=board_heit-1; j>=0; j--) 00252 if (pos[j * board_wid + row] == PLOT4_EMPTY) 00253 { 00254 movbuf[0] = row; 00255 movbuf[1] = j; 00256 movbuf[2] = (player == WHITE ? PLOT4_WP : PLOT4_BP); 00257 movbuf[3] = -1; 00258 row++; 00259 return movbuf; 00260 } 00261 row++; 00262 } 00263 /*movbuf[0] = -1;*/ 00264 row = 0; 00265 return NULL; 00266 } 00267 00269 byte *plot4_movegen (Pos *pos) 00270 { 00271 byte movbuf[256]; 00272 byte *movp = movbuf; 00273 byte *movlist; 00274 int i, j; 00275 for (i=0; i<board_wid; i++) 00276 { 00277 for (j=0; j<board_heit; j++) 00278 if (pos->board[j * board_wid + i] == PLOT4_EMPTY) 00279 { 00280 *movp++ = i; 00281 *movp++ = j; 00282 *movp++ = (pos->player == WHITE ? PLOT4_WP : PLOT4_BP); 00283 *movp++ = -1; 00284 break; 00285 } 00286 } 00287 *movp++ = -2; 00288 movlist = (byte *) (malloc (movp - movbuf)); 00289 memcpy (movlist, movbuf, (movp - movbuf)); 00290 return movlist; 00291 } 00292 00293 char ** plot4_get_pixmap (int idx, int color) 00294 { 00295 int fg, bg, i; 00296 char *colors = plot4_colors; 00297 static char pixbuf[PLOT4_CELL_SIZE*(PLOT4_CELL_SIZE)+1]; 00298 if (idx == PLOT4_WP) fg = 0xee << 8; 00299 else if (idx == PLOT4_BP) fg = (0xee << 16) + (0xee << 8); 00300 else fg = 0xd7d7d7; 00301 for(i=0, bg=0;i<3;i++) 00302 { int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));} 00303 return pixmap_ball_gen(55, pixbuf, fg, bg, 17.0, 30.0); 00304 } 00305