This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

mastermind.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 
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <assert.h>
00025 #include <stdlib.h>
00026 #include <gdk/gdkkeysyms.h>
00027 
00028 #include "game.h"
00029 #include "aaball.h"
00030 #include "../pixmaps/misc.xpm"
00031 
00032 #define MASTERMIND_CELL_SIZE 40
00033 #define MASTERMIND_NUM_PIECES 28
00034 
00035 #define MASTERMIND_BOARD_WID 8
00036 #define MASTERMIND_BOARD_HEIT 11
00037 
00038 #define MASTERMIND_EMPTY 0
00039 #define MASTERMIND_MAIN_COL_START 2
00040 #define MASTERMIND_MAIN_COL_END 5
00041 
00042 #define MASTERMIND_ARROW 27
00043 #define MASTERMIND_RETURN 28
00044 
00045 #define MASTERMIND_RIGHT_ROW_START 2
00046 #define MASTERMIND_RIGHT_ROW_END   7
00047 #define MASTERMIND_GET_SELECTION(x,y) (((x)==7&&(y)>=MASTERMIND_RIGHT_ROW_START&&(y)<(MASTERMIND_RIGHT_ROW_START+6))?(y):-1)
00048 #define MASTERMIND_IS_MAIN_COL(x) ((x)>1&&(x)<6)
00049 
00050 char mastermind_colors[9] = {200, 200, 200, 200, 200, 200, 0, 0, 0};
00051 char mastermind_highlight_colors[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
00052 
00053 static char * arrow_blue_return_40_xpm[]=
00054 {
00055 "40 40 2 1",
00056 ". c blue",
00057 "  c none",
00058 "                                        ",
00059 "                                        ",
00060 "                                        ",
00061 "                                        ",
00062 "                                        ",
00063 "                                        ",
00064 "                                        ",
00065 "                                        ",
00066 "                            ....        ",
00067 "                            ....        ",
00068 "                            ....        ",
00069 "                            ....        ",
00070 "                            ....        ",
00071 "                            ....        ",
00072 "                            ....        ",
00073 "               .            ....        ",
00074 "              ..            ....        ",
00075 "             ...            ....        ",
00076 "            ....            ....        ",
00077 "           .....            ....        ",
00078 "          ......            ....        ",
00079 "         .......................        ",
00080 "        ........................        ",
00081 "        ........................        ",
00082 "         .......................        ",
00083 "          ......                        ",
00084 "           .....                        ",
00085 "            ....                        ",
00086 "             ...                        ",
00087 "              ..                        ",
00088 "               .                        ",
00089 "                                        ",
00090 "                                        ",
00091 "                                        ",
00092 "                                        ",
00093 "                                        ",
00094 "                                        ",
00095 "                                        ",
00096 "                                        ",
00097 "                                        ",
00098 };
00099 
00100 static char * arrow_blue_left_40_xpm[]=
00101 {
00102 "40 40 2 1",
00103 ". c blue",
00104 "  c none",
00105 "                                        ",
00106 "                                        ",
00107 "                                        ",
00108 "                                        ",
00109 "                                        ",
00110 "                                        ",
00111 "                                        ",
00112 "                                        ",
00113 "                                        ",
00114 "               .                        ",
00115 "              ..                        ",
00116 "             ...                        ",
00117 "            ....                        ",
00118 "           .....                        ",
00119 "          ......                        ",
00120 "         .......                        ",
00121 "        ........                        ",
00122 "       .........                        ",
00123 "      ............................      ",
00124 "     .............................      ",
00125 "     .............................      ",
00126 "      ............................      ",
00127 "       .........                        ",
00128 "        ........                        ",
00129 "         .......                        ",
00130 "          ......                        ",
00131 "           .....                        ",
00132 "            ....                        ",
00133 "             ...                        ",
00134 "              ..                        ",
00135 "               .                        ",
00136 "                                        ",
00137 "                                        ",
00138 "                                        ",
00139 "                                        ",
00140 "                                        ",
00141 "                                        ",
00142 "                                        ",
00143 "                                        ",
00144 "                                        ",
00145 };
00146 
00147 
00148 int mastermind_init_pos [MASTERMIND_BOARD_WID*MASTERMIND_BOARD_HEIT] = 
00149 {
00150         0, 0, 9, 9, 9, 9, 0, 0,
00151         0, 0, 0, 0, 0, 0, 0, 0,
00152         0, 0, 0, 0, 0, 0, 0, 0,
00153         0, 0, 0, 0, 0, 0, 0, 6,
00154         0, 0, 0, 0, 0, 0, 0, 5,
00155         0, 0, 0, 0, 0, 0, 0, 4,
00156         0, 0, 0, 0, 0, 0, 0, 3,
00157         0, 0, 0, 0, 0, 0, 0, 2,
00158         0, 0, 0, 0, 0, 0, 0, 1,
00159         0, 0, 0, 0, 0, 0, 0, 0,
00160         0, 0, 0, 0, 0, 0,27, 0,
00161 };
00162 
00163 
00164 SCORE_FIELD mastermind_score_fields[] = {SCORE_FIELD_USER, SCORE_FIELD_SCORE, SCORE_FIELD_TIME, SCORE_FIELD_DATE, SCORE_FIELD_NONE};
00165 char *mastermind_score_field_names[] = {"User", "Tries", "Time", "Date", NULL};
00166 
00167 void mastermind_init ();
00168 char ** mastermind_get_pixmap (int idx, int color);
00169 
00170 Game Mastermind = { MASTERMIND_CELL_SIZE, 
00171         MASTERMIND_BOARD_WID, MASTERMIND_BOARD_HEIT, 
00172         MASTERMIND_NUM_PIECES,  mastermind_colors,  
00173         NULL,   NULL, "Mastermind", mastermind_init};
00174 
00175 
00176 static ResultType mastermind_who_won (Pos *, Player, char **);
00177 static void mastermind_set_init_pos (Pos *pos);
00178 int mastermind_getmove (Pos *, int, int, GtkboardEventType, Player, byte**, int **);
00179 int mastermind_getmove_kb (Pos *, int , Player, byte **, int **);
00180 void mastermind_reset_uistate ();
00181 int mastermind_get_cur_row (byte *);
00182 void mastermind_set_init_render (Pos *);
00183 void mastermind_free ();
00184 
00185 
00186 
00187 void mastermind_init ()
00188 {
00189         game_getmove = mastermind_getmove;
00190         game_getmove_kb = mastermind_getmove_kb;
00191         game_who_won = mastermind_who_won;
00192         game_set_init_pos = mastermind_set_init_pos;
00193         game_get_pixmap = mastermind_get_pixmap;
00194         game_single_player = TRUE;
00195         game_reset_uistate = mastermind_reset_uistate;
00196         game_draw_cell_boundaries = TRUE;
00197         game_scorecmp = game_scorecmp_def_iscore;
00198         game_score_fields = mastermind_score_fields;
00199         game_score_field_names = mastermind_score_field_names;
00200         game_highlight_colors = mastermind_highlight_colors;
00201         game_set_init_render = mastermind_set_init_render;
00202         game_free = mastermind_free;
00203         game_doc_about = 
00204                 "Mastermind\n"
00205                 "Single player game\n"
00206                 "Status: Completely implemented\n"
00207                 "URL: "GAME_DEFAULT_URL ("mastermind");
00208         game_doc_rules = 
00209                 "Mastermind rules\n"
00210                 "\n"
00211                 "The objective is to find the colors of 4 hidden squares in as few tries as possible.\n\n"
00212                 "Select a color by clicking on one of the balls on the extreme right. Place any 4 colors of your choice on the middle 4 squares of the bottom row and hit enter. You will get two numbers on the left. The number of black balls indicates how many balls you've got in the correct position. The number of white balls indicates how many balls you've got n the wrong position. Now try again on the second row. Repeat until you get all four black balls.";
00213         
00214         // TODO: complete this
00215 }
00216 
00217 void mastermind_set_init_render (Pos *pos)
00218 {
00219         pos->render [MASTERMIND_RIGHT_ROW_START * board_wid + board_wid - 1] = RENDER_HIGHLIGHT1;
00220 }
00221 
00222 ResultType mastermind_who_won (Pos *pos, Player to_play, char **commp)
00223 {
00224         static char comment[32];
00225         int j;
00226         gboolean over = FALSE;
00227         char *scorestr;
00228 /*              pos->board [(board_heit - 1) * board_wid+ MASTERMIND_MAIN_COL_START] 
00229                         <= 8 ? TRUE : FALSE;
00230 */
00231         for (j=0; j<board_heit-1; j++)
00232                 if (pos->board[j * board_wid] == 20) // FIXME: don't hard code
00233                         over = TRUE;
00234         scorestr = over ? "You won! Tries:" : "Tries:";
00235         if (!over && mastermind_get_cur_row (pos->board) == board_heit - 1)
00236         {
00237                 snprintf (comment, 32, "You lost. Tries: %d", board_heit - 1);
00238                 *commp = comment;
00239                 return RESULT_LOST;
00240         }
00241         for (j=0; j<board_heit-1; j++)
00242                 if (!pos->board[j * board_wid])
00243                         break;
00244         snprintf (comment, 32, "%s %d", scorestr, j);
00245         *commp = comment;
00246         return over ? RESULT_WON : RESULT_NOTYET;
00247 
00248 }
00249 
00250 int mastermind_get_cur_row (byte *board)
00251 {
00252         int j;
00253         for (j=board_heit-2; j>=0; j--)
00254         {
00255                 if (board [j * board_wid + 0] || board [j * board_wid + 1])
00256                         return j+1;
00257         }
00258         return 0;
00259 }
00260 
00261 void mastermind_set_init_pos (Pos *pos)
00262 {
00263         int i, j;
00264         for (i=0; i<board_wid; i++)
00265         for (j=0; j<board_heit; j++)
00266                 pos->board [j * board_wid + i] = 
00267                         mastermind_init_pos [(board_heit - 1 - j) * board_wid + i];
00268         for (i=MASTERMIND_MAIN_COL_START; i<=MASTERMIND_MAIN_COL_END; i++)
00269                 pos->board [(board_heit - 1) * board_wid + i] = 9 + random() % 6;
00270 }
00271 
00272 char ** mastermind_get_pixmap (int idx, int color)
00273 {
00274         int fg = 0, bg = 0, i;
00275         char *colors;
00276         static char pixbuf[MASTERMIND_CELL_SIZE*(MASTERMIND_CELL_SIZE)+1];
00277         static char dice_pixbuf[MASTERMIND_CELL_SIZE*(MASTERMIND_CELL_SIZE)+1];
00278         static gboolean first = TRUE;
00279         colors = mastermind_colors;
00280         if (idx == MASTERMIND_ARROW)
00281                 return arrow_blue_left_40_xpm;
00282         else if (idx == MASTERMIND_RETURN)
00283                 return arrow_blue_return_40_xpm;
00284         if (idx < 16)
00285         {
00286                 fg += (idx & 1);
00287                 fg += (idx & 2 ? 256 : 0);
00288                 fg += (idx & 4 ? 65536 : 0);
00289                 fg *= 255;
00290                 if (idx >= 9 && idx <= 14) fg = 100 * 0x10101;
00291                 if (color == BLACK) colors += 3;
00292                 for(i=0, bg=0;i<3;i++) 
00293                 { int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));}
00294                 if (first)
00295                 {
00296                         first = FALSE;
00297                         return pixmap_ball_gen
00298                                 (MASTERMIND_CELL_SIZE, pixbuf, fg, bg, 10.0, 30.0);
00299                 }
00300                 return  pixmap_header_gen 
00301                         (MASTERMIND_CELL_SIZE, pixbuf, fg, bg);
00302         }
00303         else if (idx < 25)
00304         {
00305                 int num = (idx <= 20 ? idx - 16 : idx - 20);
00306                 for(i=0, bg=0;i<3;i++) 
00307                 { int col = colors[i]; if (col<0) col += 256; bg += col * (1 << (16-8*i));}
00308                 fg = (idx <= 20 ? 0 : 0xffffff);
00309                 return pixmap_die_gen(MASTERMIND_CELL_SIZE, dice_pixbuf, fg, bg, 3.0, 30.0, num);
00310         }
00311         else return red_X_40_xpm;
00312         return NULL;
00313 }
00314 
00315 static int active = MASTERMIND_RIGHT_ROW_START;
00316 
00317 void mastermind_free ()
00318 {
00319         active = MASTERMIND_RIGHT_ROW_START;
00320 }
00321 
00322 void mastermind_reset_uistate ()
00323 {
00324 }
00325 
00326 int mastermind_getmove 
00327   (Pos *pos, int x, int y, GtkboardEventType type, Player to_play, byte **movp, int ** rmovep)
00328 {
00329         static int rmove[7];
00330         int *rp = rmove;
00331         int tmp;
00332         int i, found;
00333         static byte move[7];
00334         byte *mp = move;
00335         if (type != GTKBOARD_BUTTON_RELEASE)
00336                 return 0;
00337         tmp = MASTERMIND_GET_SELECTION(x,y);
00338         if (tmp > 0) 
00339         { 
00340                 int j;
00341                 active = tmp;
00342                 for (j=0; j<board_heit; j++)
00343                         if (pos->render [j * board_wid + (board_wid - 1)] == RENDER_HIGHLIGHT1)
00344                         {
00345                                 if (j == y) break;
00346                                 *rp++ = board_wid - 1;
00347                                 *rp++ = j;
00348                                 *rp++ = 0;
00349                                 break;
00350                         }
00351                 *rp++ = board_wid - 1;
00352                 *rp++ = y;
00353                 *rp++ = RENDER_HIGHLIGHT1;
00354                 *rp++ = -1;
00355                 *rmovep = rmove;
00356                 return 0;
00357         }
00358         if (active < 1) return -1;
00359         if (!MASTERMIND_IS_MAIN_COL(x)) return -1;
00360         if (y == board_heit -1) return -1;
00361         if (y != mastermind_get_cur_row (pos->board)) return -1;
00362         *mp++ = x;
00363         *mp++ = y;
00364         *mp++ = active - MASTERMIND_RIGHT_ROW_START + 1;
00365         if (movp)
00366                 *movp = move;   
00367         for (found = 0, i=MASTERMIND_MAIN_COL_START;i<=MASTERMIND_MAIN_COL_END;i++)
00368         {
00369                 if (pos->board [y * board_wid + i] == MASTERMIND_EMPTY && i != x)
00370                 {
00371                         found = 1;
00372                         break;
00373                 }
00374         }
00375         if (!found)
00376         {
00377                 *mp++ = MASTERMIND_MAIN_COL_END + 1;
00378                 *mp++ = y;
00379                 *mp++ = MASTERMIND_RETURN;
00380         }
00381         *mp++ = -1;
00382         return 1;
00383 }
00384 
00385 
00386 int mastermind_getmove_kb (Pos *pos, int key, Player glob_to_play, byte **movp, int **rmovp)
00387 {
00388         static byte move[32];
00389         static int rmove[7];
00390         byte *mp = move;
00391         int *rp = rmove;
00392         int i, j, nblack = 0, nwhite = 0, seen[4] = { 0 };
00393         byte *board = pos->board;
00394         int cur_row;
00395         if (key == GDK_Up)
00396         {
00397                 *rp++ = board_wid - 1;
00398                 *rp++ = active;
00399                 *rp++ = 0;
00400                 if (++active > MASTERMIND_RIGHT_ROW_END)
00401                         active = MASTERMIND_RIGHT_ROW_START;
00402                 *rp++ = board_wid - 1;
00403                 *rp++ = active;
00404                 *rp++ = RENDER_HIGHLIGHT1;
00405                 *rp++ = -1;
00406                 *rmovp = rmove;
00407                 return 0;
00408         }
00409         if (key == GDK_Down)
00410         {
00411                 *rp++ = board_wid - 1;
00412                 *rp++ = active;
00413                 *rp++ = 0;
00414                 if (--active < MASTERMIND_RIGHT_ROW_START)
00415                         active = MASTERMIND_RIGHT_ROW_END;
00416                 *rp++ = board_wid - 1;
00417                 *rp++ = active;
00418                 *rp++ = RENDER_HIGHLIGHT1;
00419                 *rp++ = -1;
00420                 *rmovp = rmove;
00421                 return 0;
00422         }
00423         if (key != GDK_Return) return 0;
00424         if (active < 0) return 0;
00425         cur_row = mastermind_get_cur_row (board);
00426         if (cur_row == board_heit - 1) return -1;
00427         for (i=MASTERMIND_MAIN_COL_START;i<=MASTERMIND_MAIN_COL_END;i++)
00428         {
00429                 if (board [cur_row * board_wid + i] == MASTERMIND_EMPTY)
00430                         return 0;
00431         }
00432         *mp++ = MASTERMIND_MAIN_COL_END + 1;
00433         *mp++ = cur_row;
00434         *mp++ = MASTERMIND_EMPTY;
00435         if (cur_row < board_heit - 2)
00436         {
00437                 *mp++ = MASTERMIND_MAIN_COL_END + 1;
00438                 *mp++ = cur_row+1;
00439                 *mp++ = MASTERMIND_ARROW;
00440         }
00441         nblack = 0;
00442         for (i=MASTERMIND_MAIN_COL_START;i<=MASTERMIND_MAIN_COL_END;i++)
00443                 if (board [cur_row * board_wid + i] == 
00444                                 (board [(board_heit - 1) * board_wid + i] & 7))
00445                         nblack++;
00446         for (i=MASTERMIND_MAIN_COL_START;i<=MASTERMIND_MAIN_COL_END;i++)
00447         {
00448                 for (j=MASTERMIND_MAIN_COL_START;j<=MASTERMIND_MAIN_COL_END;j++)
00449                         if (board [cur_row * board_wid + i] == 
00450                                         (board [(board_heit - 1) * board_wid + j] & 7)
00451                                         && !seen[j - MASTERMIND_MAIN_COL_START])
00452                         {
00453                                 nwhite++;
00454                                 seen[j - MASTERMIND_MAIN_COL_START] = 1;
00455                                 break;
00456                         }
00457         }
00458         assert (nwhite >= nblack);
00459         nwhite -= nblack;
00460         *mp++ = 0; *mp++ = cur_row; *mp++ = (nblack ? nblack + 16 : 25);
00461         *mp++ = 1; *mp++ = cur_row; *mp++ = (nwhite ? nwhite + 20 : 25);
00462         if (nblack == 4 || cur_row == board_heit - 2)
00463                 for (i=MASTERMIND_MAIN_COL_START;i<=MASTERMIND_MAIN_COL_END;i++)
00464                 {
00465                         *mp++ = i; *mp++ = board_heit - 1; 
00466                         *mp++ = board [(board_heit - 1) * board_wid + i] & 7;
00467                 }
00468         *mp++ = -1;
00469         if (movp) *movp = move;
00470         cur_row++;
00471         return 1;
00472 }
00473