This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

kttour.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 #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