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 <string.h> 00021 #include <assert.h> 00022 #include <stdlib.h> 00023 #include <math.h> 00024 #include <gdk/gdkkeysyms.h> 00025 00026 00027 #include "game.h" 00028 #include "aaball.h" 00029 00030 #define FIFTEEN_CELL_SIZE 60 00031 #define FIFTEEN_NUM_PIECES 16 00032 00033 #define FIFTEEN_BOARD_WID 4 00034 #define FIFTEEN_BOARD_HEIT 4 00035 00036 char fifteen_colors[6] = {220, 220, 220, 220, 220, 220}; 00037 00038 int * fifteen_init_pos = NULL; 00039 00040 void fifteen_init (); 00041 00042 Game Fifteen = { FIFTEEN_CELL_SIZE, FIFTEEN_BOARD_WID, FIFTEEN_BOARD_HEIT, 00043 FIFTEEN_NUM_PIECES, fifteen_colors, NULL, NULL, "Fifteen Puzzle", fifteen_init}; 00044 00045 static void fifteen_set_init_pos (Pos *pos); 00046 static char ** fifteen_get_pixmap (int idx, int color); 00047 static guchar * fifteen_get_rgbmap (int idx, int color); 00048 int fifteen_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player, byte **, int **); 00049 static int fifteen_getmove_kb (Pos *cur_pos, int key, Player glob_to_play, 00050 byte **move, int **); 00051 void fifteen_free (); 00052 void fifteen_init (); 00053 ResultType fifteen_who_won (Pos *, Player, char **); 00054 00055 int fifteen_done (byte *board) 00056 { 00057 int size = board_wid * board_heit, i; 00058 for (i=0; i<size; i++) 00059 if (board[i] != (i+1) && board[i] != 0) return 0; 00060 return 1; 00061 } 00062 00063 // After fifteen_done returns true user must click on the remaining empty square to complete the game 00064 int fifteen_really_done (byte *board) 00065 { 00066 int size = board_wid * board_heit, i; 00067 for (i=0; i<size; i++) 00068 if (board[i] != (i+1)) return 0; 00069 return 1; 00070 } 00071 00072 void fifteen_init () 00073 { 00074 game_single_player = TRUE; 00075 game_set_init_pos = fifteen_set_init_pos; 00076 game_get_pixmap = fifteen_get_pixmap; 00077 game_get_rgbmap = fifteen_get_rgbmap; 00078 game_getmove = fifteen_getmove; 00079 game_getmove_kb = fifteen_getmove_kb; 00080 game_who_won = fifteen_who_won; 00081 game_scorecmp = game_scorecmp_def_iscore; 00082 game_doc_about = 00083 "Fifteen puzzle\n" 00084 "Single player game\n" 00085 "Status: Fully implemented\n" 00086 "URL: "GAME_DEFAULT_URL ("fifteen"); 00087 game_doc_rules = 00088 "Fifteen puzzle rules\n" 00089 "\n" 00090 "The classic fifteen puzzle (Sam Loyd, c.a. 1870). On each turn you move to the empty square one of the adjacent pieces. The objective is to complete the pattern. In the gtkboard implementation the pattern is a pair of concentric circles.\n"; 00091 } 00092 00093 00094 void fifteen_get_cur (byte *pos, int *x, int *y) 00095 { 00096 int i, j; 00097 for (i=0; i<board_wid; i++) 00098 for (j=0; j<board_heit; j++) 00099 if (pos [j * board_wid + i] == 0) 00100 { *x = i; *y = j; return; 00101 } 00102 } 00103 00104 ResultType fifteen_who_won (Pos *pos, Player to_play, char **commp) 00105 { 00106 static char comment[32]; 00107 int over = fifteen_really_done (pos->board); 00108 char *scorestr = over ? "You won. Moves:" : "Moves:"; 00109 // last move is a dummy 00110 snprintf (comment, 32, "%s %d", scorestr, pos->num_moves - (over ? 1 : 0)); 00111 *commp = comment; 00112 return over ? RESULT_WON : RESULT_NOTYET; 00113 } 00114 00115 00116 int fifteen_getmove_kb (Pos *pos, int key, Player glob_to_play, byte **movp, int **rmovp) 00117 { 00118 static byte move[10]; 00119 byte *mp = move; 00120 int i, j, incx, incy; 00121 switch (key) 00122 { 00123 case GDK_Up: incx = 0; incy = 1; break; 00124 case GDK_Down: incx = 0; incy = -1; break; 00125 case GDK_Right: incx = 1; incy = 0; break; 00126 case GDK_Left: incx = -1; incy = 0; break; 00127 default: return -1; 00128 } 00129 incx *= -1; incy *= -1; 00130 for (i=0; i<board_wid; i++) 00131 for (j=0; j<board_heit; j++) 00132 { 00133 if (pos->board [j * board_wid + i] == 0) 00134 { 00135 int x = i + incx, y = j + incy; 00136 if (x < 0 || y < 0 || x >= board_wid || y >= board_heit) 00137 return -1; 00138 *mp++ = x; *mp++ = y; *mp++ = 0; 00139 *mp++ = i; *mp++ = j; *mp++ = pos->board [y * board_wid + x]; 00140 *mp++ = -1; 00141 *movp = move; 00142 return 1; 00143 } 00144 } 00145 g_assert_not_reached(); 00146 return -1; 00147 } 00148 00149 void fifteen_set_init_pos (Pos *pos) 00150 { 00151 int i, j; 00152 int size = board_wid * board_heit; 00153 int swaps = 0; 00154 byte *board = pos->board; 00155 for (i=0; i<size; i++) 00156 board[i] = i+1; 00157 board[random()%(board_heit*board_wid)] = 0; 00158 for (i=1; i<size; i++) 00159 { 00160 int tmp; 00161 if (!board[i]) continue; 00162 do j = random() % (i + 1); while (!board[j]); 00163 tmp = board[i]; board[i] = board[j]; board[j] = tmp; 00164 swaps += (i%board_wid-j%board_wid+i/board_wid-j/board_wid); 00165 } 00166 // total number of swaps must be even 00167 // FIXME: this is not working 00168 if (swaps % 2 != 0) 00169 { 00170 int tmp; 00171 i=0; if (!board[0] || !board[1]) i=2; j = i+1; 00172 tmp = board[i]; board[i] = board[j]; board[j] = tmp; 00173 } 00174 } 00175 00176 00177 int fifteen_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, 00178 byte **movp, int ** rmovep) 00179 { 00180 int k; 00181 static byte move[16]; 00182 byte *mp = move; 00183 int incx[] = {0, 0, 1, -1}; 00184 int incy[] = {1, -1, 0, 0}; 00185 if (type != GTKBOARD_BUTTON_RELEASE) 00186 return 0; 00187 if (pos->board [y * board_wid + x] == 0 && fifteen_done (pos->board)) 00188 { 00189 *mp++ = x; *mp++ = y; *mp++ = y * board_wid + x + 1; 00190 *mp++ = -1; *movp = move; return 1; 00191 } 00192 for (k=0; k<4; k++) 00193 { 00194 int newx = x + incx[k], newy = y + incy[k]; 00195 if (newx < 0 || newy < 0 || newx >= board_wid || newy >= board_heit) 00196 continue; 00197 if (pos->board [newy * board_wid + newx] == 0) 00198 { 00199 *mp++ = x; *mp++ = y; *mp++ = 0; 00200 *mp++ = newx; *mp++ = newy; *mp++ = pos->board [y * board_wid + x]; 00201 *mp++ = -1; 00202 *movp = move; 00203 return 1; 00204 } 00205 } 00206 return -1; 00207 } 00208 00209 char ** fifteen_pixmap_square_gen (char *col) 00210 { 00211 int i, j; 00212 char **pixmap; 00213 static char line[FIFTEEN_CELL_SIZE]; 00214 memset(line, ' ', FIFTEEN_CELL_SIZE); 00215 pixmap = g_new(char *, FIFTEEN_CELL_SIZE + 2); 00216 pixmap[0] = "60 60 1 1"; // FIXME: dont hard code 00217 // FIXME: not freed 00218 pixmap[1] = g_strdup_printf (" c %s", col); 00219 for (i=0; i<FIFTEEN_CELL_SIZE; i++) pixmap[i+2] = line; return pixmap; 00220 } 00221 00222 char ** fifteen_get_pixmap (int idx, int color) 00223 { 00224 int fg, bg, i; 00225 char *colors = fifteen_colors; 00226 return fifteen_pixmap_square_gen("#e7d7d7"); 00227 } 00228 00229 guchar *fifteen_get_rgbmap (int idx, int color) 00230 { 00231 static guchar buf[3 * FIFTEEN_CELL_SIZE * FIFTEEN_CELL_SIZE]; 00232 int i, j; 00233 int xoff, yoff; 00234 guchar *bp = buf; 00235 idx--; 00236 xoff = (idx % FIFTEEN_BOARD_WID) * FIFTEEN_CELL_SIZE; 00237 yoff = (FIFTEEN_BOARD_HEIT - 1 - (idx / FIFTEEN_BOARD_WID)) * FIFTEEN_CELL_SIZE; 00238 for (j=0; j<FIFTEEN_CELL_SIZE; j++) 00239 for (i=0; i<FIFTEEN_CELL_SIZE; i++) 00240 { 00241 int maxx = FIFTEEN_BOARD_WID * FIFTEEN_CELL_SIZE; 00242 int maxy = FIFTEEN_BOARD_HEIT * FIFTEEN_CELL_SIZE; 00243 float x = 1.0*(xoff + i)/maxx, y = 1.0*(yoff + j)/maxy; 00244 float d = sqrt ((x-0.5) * (x-0.5) + (y-0.5) * (y-0.5)); 00245 d *= 2; 00246 if ((d > 0.9 && d < 0.98)) 00247 { 00248 float frac = fabs ((d - 0.94) / 0.04); 00249 frac = 2 * (frac - 0.5); 00250 if (frac < 0) frac = 0; 00251 *bp++ = sqrt (1 - frac) * 255; 00252 *bp++ = sqrt (frac) * 256 * x; 00253 *bp++ = sqrt (frac) * 256 * y; 00254 } 00255 else if ((d>0.3 && d < 0.36)) 00256 { 00257 float frac = fabs ((d - 0.33) / 0.03); 00258 frac = 2 * (frac - 0.5); 00259 if (frac < 0) frac = 0; 00260 *bp++ = sqrt (1 - frac) * 255; 00261 *bp++ = sqrt (frac) * 256 * x; 00262 *bp++ = sqrt (frac) * 256 * y; 00263 } 00264 else 00265 { 00266 *bp++ = 0; 00267 *bp++ = 256 * x; 00268 *bp++ = 256 * y; 00269 } 00270 } 00271 return buf; 00272 }