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 <time.h> 00024 00025 #include "game.h" 00026 #include "aaball.h" 00027 #include "../pixmaps/chess.xpm" 00028 #include "../pixmaps/misc.xpm" 00029 00030 #define KTTOUR_CELL_SIZE 54 00031 #define KTTOUR_NUM_PIECES 4 00032 00033 #define KTTOUR_BOARD_WID 8 00034 #define KTTOUR_BOARD_HEIT 8 00035 00036 #define KTTOUR_EMPTY 0 00037 #define KTTOUR_CUR 1 00038 #define KTTOUR_START 2 00039 #define KTTOUR_USED 3 00040 #define KTTOUR_HINT 4 00041 00042 char kttour_colors[6] = {200, 200, 160, 200, 200, 160}; 00043 00044 void kttour_init (); 00045 00046 Game Kttour = { KTTOUR_CELL_SIZE, KTTOUR_BOARD_WID, KTTOUR_BOARD_HEIT, 00047 KTTOUR_NUM_PIECES, 00048 kttour_colors, NULL, /*kttour_pixmaps,*/ NULL, "Knight's tour", 00049 kttour_init}; 00050 00051 SCORE_FIELD kttour_score_fields[] = {SCORE_FIELD_RANK, SCORE_FIELD_USER, SCORE_FIELD_TIME, SCORE_FIELD_DATE, SCORE_FIELD_NONE}; 00052 char *kttour_score_field_names[] = {"Rank", "User", "Time", "Date", NULL}; 00053 00054 static int kttour_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **); 00055 static ResultType kttour_who_won (Pos *, Player, char **); 00056 static char **kttour_get_pixmap (int , int); 00057 00058 void kttour_init () 00059 { 00060 game_single_player = 1; 00061 game_getmove = kttour_getmove; 00062 game_get_pixmap = kttour_get_pixmap; 00063 game_who_won = kttour_who_won; 00064 game_scorecmp = game_scorecmp_def_time; 00065 game_score_fields = kttour_score_fields; 00066 game_score_field_names = kttour_score_field_names; 00067 game_draw_cell_boundaries = TRUE; 00068 game_allow_undo = TRUE; 00069 game_doc_about = 00070 "Kttour\n" 00071 "Single player game\n" 00072 "Status: Partially implemented\n" 00073 "URL: "GAME_DEFAULT_URL("kttour"); 00074 game_doc_rules = 00075 "Kttour rules\n\n" 00076 " Complete the knight's tour of the chessboard.\n" 00077 "\n" 00078 " In the initial position click on any square to start the tour on that square. " 00079 "Next click on the square you want the knight to move to, and so on. " 00080 "The square where you started will be shown in green and the other squares in the tour will be grey. " 00081 "At any point you can click on the green square to make it the current square, in which case the current square will become the \"start\" square. " 00082 "\n\n" 00083 " The objective is to fill all 64 squares in such a way that the last square is one knight-move away from the first, in as little time as possible. " 00084 "In this game, you can undo your moves freely. This won't prevent you from getting a highscore. " 00085 "\n\n" 00086 " The blue balls that you see are hints. They are there to make your life easier, but you don't have to necessarily click on a ball." 00087 ; 00088 } 00089 00090 static char **kttour_get_pixmap (int idx, int color) 00091 { 00092 static char pixbuf[KTTOUR_CELL_SIZE*(KTTOUR_CELL_SIZE+1)]; 00093 int i, bg; 00094 for(i=0, bg=0;i<3;i++) 00095 { int col = kttour_colors[i]; if (col<0) col+=256; bg += col * (1 << (16-8*i));} 00096 switch (idx) 00097 { 00098 case KTTOUR_CUR: 00099 return chess_wn_54_xpm; 00100 00101 // simulate square using ball of large radius 00102 case KTTOUR_START: 00103 return pixmap_ball_gen (KTTOUR_CELL_SIZE, pixbuf, 0x80ff80, bg, 00104 KTTOUR_CELL_SIZE, 1); 00105 case KTTOUR_USED: 00106 return pixmap_ball_gen (KTTOUR_CELL_SIZE, pixbuf, 0x808080, bg, 00107 KTTOUR_CELL_SIZE, 1); 00108 00109 case KTTOUR_HINT: 00110 return pixmap_ball_gen (KTTOUR_CELL_SIZE, pixbuf, 0x8080ff, bg, 00111 KTTOUR_CELL_SIZE/4, 30.0); 00112 default: return NULL; 00113 } 00114 } 00115 00116 #define abs(x) ((x)<0?-(x):(x)) 00117 00118 static gboolean are_nbrs (int x1, int y1, int x2, int y2) 00119 { 00120 return abs ((x1 - x2) * (y1 - y2)) == 2 ? TRUE : FALSE; 00121 } 00122 00123 /* TODO: this should be implemented in game_common.c or something like that so that 00124 all games can access it */ 00125 static void find_xy (byte *board, int *x, int *y, int val) 00126 { 00127 int i, j; 00128 *x = -1; 00129 *y = -1; 00130 for (i=0; i<board_wid; i++) 00131 for (j=0; j<board_wid; j++) 00132 if (board[j * board_wid + i] == val) 00133 { 00134 *x = i; 00135 *y = j; 00136 return; 00137 } 00138 } 00139 00140 ResultType kttour_who_won (Pos *pos, Player to_play, char **commp) 00141 { 00142 int x1, y1, x2, y2; 00143 int i; 00144 gboolean found = FALSE; 00145 for (i=0; i<board_wid*board_heit; i++) 00146 if (pos->board [i] == KTTOUR_EMPTY) 00147 return RESULT_NOTYET; 00148 find_xy (pos->board, &x1, &y1, KTTOUR_CUR); 00149 find_xy (pos->board, &x2, &y2, KTTOUR_START); 00150 return are_nbrs (x1, y1, x2, y2) ? RESULT_WON : RESULT_NOTYET; 00151 } 00152 00153 static int incx[] = {-2, -2, -1, -1, 1, 1, 2, 2}; 00154 static int incy[] = {-1, 1, -2, 2, -2, 2, -1, 1}; 00155 00156 #define IS_FREE(x) ((x) == KTTOUR_EMPTY || (x) == KTTOUR_HINT) 00157 00158 static int get_degree (byte *board, int i, int j) 00159 { 00160 int k, x, y; 00161 int count = 0; 00162 for (k=0; k<8; k++) 00163 { 00164 x = i + incx[k]; 00165 y = j + incy[k]; 00166 if (ISINBOARD (x, y) && IS_FREE(board [y * board_wid + x])) 00167 count++; 00168 } 00169 return count; 00170 } 00171 00172 static int get_min_degree (byte *board, int i, int j) 00173 { 00174 int k, x, y; 00175 int min_deg = 8; 00176 for (k=0; k<8; k++) 00177 { 00178 int deg; 00179 x = i + incx[k]; 00180 y = j + incy[k]; 00181 if (ISINBOARD (x, y) && IS_FREE(board [y * board_wid + x])) 00182 if ((deg = get_degree (board, x, y)) < min_deg) 00183 min_deg = deg; 00184 } 00185 return min_deg; 00186 } 00187 00188 static void add_hints 00189 (byte *board, int new_x, int new_y, byte **mp) 00190 { 00191 int min_deg_new, min_deg_old; 00192 int k, x, y; 00193 min_deg_new = get_min_degree (board, new_x, new_y); 00194 00195 for (k=0; k<8; k++) 00196 { 00197 x = new_x + incx[k]; 00198 y = new_y + incy[k]; 00199 if (!ISINBOARD (x, y) || board [y * board_wid + x] != KTTOUR_EMPTY) 00200 continue; 00201 if (get_degree (board, x, y) == min_deg_new) 00202 { 00203 *(*mp)++ = x; 00204 *(*mp)++ = y; 00205 *(*mp)++ = KTTOUR_HINT; 00206 } 00207 } 00208 00209 for (x=0; x<board_wid; x++) 00210 for (y=0; y<board_heit; y++) 00211 { 00212 if (board [y * board_wid + x] != KTTOUR_HINT) 00213 continue; 00214 if (x == new_x && y == new_y) 00215 continue; 00216 if (are_nbrs (x, y, new_x, new_y) && get_degree (board, x, y) == min_deg_new) 00217 continue; 00218 *(*mp)++ = x; 00219 *(*mp)++ = y; 00220 *(*mp)++ = KTTOUR_EMPTY; 00221 } 00222 } 00223 00224 int kttour_getmove 00225 (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, byte **movp, int ** rmovep) 00226 { 00227 static byte move[7]; 00228 byte *mp = move; 00229 int val; 00230 int cur_x, cur_y; 00231 if (type != GTKBOARD_BUTTON_RELEASE) 00232 return 0; 00233 val = pos->board[y * board_wid + x]; 00234 if (val == KTTOUR_CUR) 00235 return 0; 00236 if (val == KTTOUR_USED) 00237 return -1; 00238 find_xy (pos->board, &cur_x, &cur_y, KTTOUR_CUR); 00239 if (val == KTTOUR_START) 00240 { 00241 *mp++ = x; 00242 *mp++ = y; 00243 *mp++ = KTTOUR_CUR; 00244 *mp++ = cur_x; 00245 *mp++ = cur_y; 00246 *mp++ = KTTOUR_START; 00247 add_hints (pos->board, x, y, &mp); 00248 *mp++ = -1; 00249 *movp = move; 00250 return 1; 00251 } 00252 if (cur_x >= 0 && !are_nbrs (cur_x, cur_y, x, y)) 00253 return -1; 00254 *mp++ = x; 00255 *mp++ = y; 00256 *mp++ = KTTOUR_CUR; 00257 if (cur_x >= 0) 00258 { 00259 *mp++ = cur_x; 00260 *mp++ = cur_y; 00261 *mp++ = pos->num_moves == 1 ? KTTOUR_START : KTTOUR_USED; 00262 } 00263 add_hints (pos->board, x, y, &mp); 00264 *mp++ = -1; 00265 *movp = move; 00266 return 1; 00267 } 00268