This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

fifteen.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 <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 }