This is the doxygen documentation for gtkboard.
.00001 /* This file is a part of gtkboard, a board games system. 00002 Copyright (C) 2003, Arthur J. O'Dwyer <ajo@andrew.cmu.edu> 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 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 00023 #include "game.h" 00024 #include "../pixmaps/alpha.xpm" 00025 #include "../pixmaps/cpento.xpm" 00026 00027 #define CPENTO_CELL_SIZE 36 00028 #define CPENTO_BOARD_WID 15 00029 #define CPENTO_BOARD_HEIT 9 00030 00031 #define CPENTO_NUM_PIECES 32 00032 #define CPENTO_EMPTY 0 00033 #define CPENTO_TILE_F 1 00034 #define CPENTO_TILE_I 2 00035 #define CPENTO_TILE_L 3 00036 #define CPENTO_TILE_N 4 00037 #define CPENTO_TILE_P 5 00038 #define CPENTO_TILE_T 6 00039 #define CPENTO_TILE_U 7 00040 #define CPENTO_TILE_V 8 00041 #define CPENTO_TILE_W 9 00042 #define CPENTO_TILE_X 10 00043 #define CPENTO_TILE_Y 11 00044 #define CPENTO_TILE_Z 12 00045 #define CPENTO_TILE_SIMPLE 13 00046 #define CPENTO_TILE_RARROW 14 00047 #define CPENTO_TILE_LARROW 15 00048 #define CPENTO_TILE_FLIPLR 16 00049 #define CPENTO_PIECE_BALL 17 00050 #define CPENTO_PIECE_LEG_UP 18 00051 #define CPENTO_PIECE_LEG_DOWN 19 00052 #define CPENTO_PIECE_PIPE_VERT 20 00053 #define CPENTO_PIECE_LEG_RIGHT 21 00054 #define CPENTO_PIECE_BEND_UR 22 00055 #define CPENTO_PIECE_BEND_DR 23 00056 #define CPENTO_PIECE_T_LEFT 24 00057 #define CPENTO_PIECE_LEG_LEFT 25 00058 #define CPENTO_PIECE_BEND_UL 26 00059 #define CPENTO_PIECE_BEND_DL 27 00060 #define CPENTO_PIECE_T_RIGHT 28 00061 #define CPENTO_PIECE_PIPE_HORIZ 29 00062 #define CPENTO_PIECE_T_DOWN 30 00063 #define CPENTO_PIECE_T_UP 31 00064 #define CPENTO_PIECE_FOURWAY 32 00065 00066 00067 static char cpento_colors[6]; 00068 static int cpento_initpos[CPENTO_BOARD_WID*CPENTO_BOARD_HEIT]; 00069 static char **cpento_pixmaps[CPENTO_NUM_PIECES]; 00070 static void cpento_init(void); 00071 00072 static int cpento_getmove(Pos *, int, int, 00073 GtkboardEventType, 00074 Player, byte **, int **); 00075 00076 Game CapturePento = { 00077 CPENTO_CELL_SIZE, 00078 CPENTO_BOARD_WID, CPENTO_BOARD_HEIT, 00079 CPENTO_NUM_PIECES, 00080 cpento_colors, cpento_initpos, 00081 cpento_pixmaps, 00082 "Capture Pentominoes", 00083 cpento_init 00084 }; 00085 00086 static char cpento_colors[6] = { 0,120,0, 10,130,10 }; 00087 00088 00089 static int cpento_initpos[CPENTO_BOARD_WID*CPENTO_BOARD_HEIT] = 00090 { 00091 1, 2, 3, 4, 5, 6,13,13,13,13,13,13,13,13,13, 00092 7, 8, 9,10,11,12,13, 0, 0, 0, 0, 0, 0, 0,13, 00093 13,13,13,13,13,13,13, 0, 0, 0, 0, 0, 0, 0,13, 00094 13, 0, 0, 0, 0, 0,13, 0, 0, 0, 0, 0, 0, 0,13, 00095 13, 0, 0, 0, 0, 0,13, 0, 0, 0, 0, 0, 0, 0,13, 00096 15, 0, 0, 0, 0, 0,14, 0, 0, 0, 0, 0, 0, 0,13, 00097 13, 0, 0, 0, 0, 0,13, 0, 0, 0, 0, 0, 0, 0,13, 00098 13, 0, 0, 0, 0, 0,13, 0, 0, 0, 0, 0, 0, 0,13, 00099 13,13,13,16,13,13,13,13,13,13,13,13,13,13,13, 00100 }; 00101 00102 static char *ball_grey_36_36_xpm[] = { 00103 "36 36 2 1", 00104 " c #000000", 00105 "X c #FF00FF", 00106 "....................................", 00107 "....................................", 00108 ".................X..................", 00109 "............XXXXXXXXXXX.............", 00110 "..........XXXXXXXXXXXXXXX...........", 00111 "........XXXXXXXXXXXXXXXXXXX.........", 00112 ".......XXXXXXXXXXXXXXXXXXXXX........", 00113 "......XXXXXXXXXXXXXXXXXXXXXXX.......", 00114 ".....XXXXXXXXXXXXXXXXXXXXXXXXX......", 00115 ".....XXXXXXXXXXXXXXXXXXXXXXXXX......", 00116 "....XXXXXXXXXXXXXXXXXXXXXXXXXXX.....", 00117 "....XXXXXXXXXXXXXXXXXXXXXXXXXXX.....", 00118 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00119 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00120 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00121 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00122 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00123 "..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...", 00124 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00125 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00126 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00127 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00128 "...XXXXXXXXXXXXXXXXXXXXXXXXXXXXX....", 00129 "....XXXXXXXXXXXXXXXXXXXXXXXXXXX.....", 00130 "....XXXXXXXXXXXXXXXXXXXXXXXXXXX.....", 00131 ".....XXXXXXXXXXXXXXXXXXXXXXXXX......", 00132 ".....XXXXXXXXXXXXXXXXXXXXXXXXX......", 00133 "......XXXXXXXXXXXXXXXXXXXXXXX.......", 00134 ".......XXXXXXXXXXXXXXXXXXXXX........", 00135 "........XXXXXXXXXXXXXXXXXXX.........", 00136 "..........XXXXXXXXXXXXXXX...........", 00137 "............XXXXXXXXXXX.............", 00138 ".................X..................", 00139 "....................................", 00140 "....................................", 00141 "....................................", 00142 }; 00143 00144 00145 static char **cpento_pixmaps[CPENTO_NUM_PIECES] = 00146 { 00147 char_F_grey_36_36_xpm, 00148 char_I_grey_36_36_xpm, 00149 char_L_grey_36_36_xpm, 00150 char_N_grey_36_36_xpm, 00151 char_P_grey_36_36_xpm, 00152 char_T_grey_36_36_xpm, 00153 char_U_grey_36_36_xpm, 00154 char_V_grey_36_36_xpm, 00155 char_W_grey_36_36_xpm, 00156 char_X_grey_36_36_xpm, 00157 char_Y_grey_36_36_xpm, 00158 char_Z_grey_36_36_xpm, 00159 cpento_fourway_36_36_xpm, 00160 char_R_grey_36_36_xpm, 00161 char_L_grey_36_36_xpm, 00162 char_F_grey_36_36_xpm, 00163 ball_grey_36_36_xpm, 00164 cpento_leg_u_36_36_xpm, 00165 cpento_leg_d_36_36_xpm, 00166 cpento_pipe_ud_36_36_xpm, 00167 cpento_leg_r_36_36_xpm, 00168 cpento_bend_ur_36_36_xpm, 00169 cpento_bend_dr_36_36_xpm, 00170 cpento_t_closed_l_36_36_xpm, 00171 cpento_leg_l_36_36_xpm, 00172 cpento_bend_ul_36_36_xpm, 00173 cpento_bend_dl_36_36_xpm, 00174 cpento_t_closed_r_36_36_xpm, 00175 cpento_pipe_lr_36_36_xpm, 00176 cpento_t_closed_d_36_36_xpm, 00177 cpento_t_closed_u_36_36_xpm, 00178 cpento_fourway_36_36_xpm, 00179 }; 00180 00181 00182 static void cpento_init(void) 00183 { 00184 game_single_player = 1; 00185 game_getmove = cpento_getmove; 00186 game_who_won = NULL; 00187 game_get_pixmap = NULL; 00188 game_scorecmp = game_scorecmp_def_iscore; 00189 game_doc_about = 00190 "Capture Pentominoes\n" 00191 "Two player game\n" 00192 "Status: Not implemented\n" 00193 "URL: " GAME_DEFAULT_URL("cpento") 00194 ; 00195 game_doc_rules = 00196 "Capture Pentominoes rules\n" 00197 "\n" 00198 "The objective is to be the last player able to move.\n" 00199 "\n" 00200 "Each move consists of selecting a piece from the pool" 00201 " and placing it on some empty region of the board." 00202 " If the newly placed piece touches a second piece on" 00203 " three or more sides, that second piece is captured." 00204 " A captured piece may be removed from the board by" 00205 " its captor at any time.\n" 00206 "\n" 00207 "At the moment, this is just an interface demo. There's" 00208 " no actual game implemented.\n" 00209 ; 00210 game_doc_strategy = 00211 "No strategy yet." 00212 ; 00213 } 00214 00215 00216 static char *cpento_piece_list[][5] = { 00217 { 00218 ".....", 00219 "..XX.", 00220 ".XX..", 00221 "..X..", 00222 ".....", 00223 }, 00224 { 00225 "..X..", 00226 "..X..", 00227 "..X..", 00228 "..X..", 00229 "..X..", 00230 }, 00231 { 00232 "..X..", 00233 "..X..", 00234 "..X..", 00235 "..XX.", 00236 ".....", 00237 }, 00238 { 00239 ".....", 00240 ".X...", 00241 ".XX..", 00242 "..X..", 00243 "..X..", 00244 }, 00245 { 00246 ".....", 00247 "..XX.", 00248 "..XX.", 00249 "..X..", 00250 ".....", 00251 }, 00252 { 00253 ".....", 00254 ".XXX.", 00255 "..X..", 00256 "..X..", 00257 ".....", 00258 }, 00259 { 00260 ".....", 00261 ".X.X.", 00262 ".XXX.", 00263 ".....", 00264 ".....", 00265 }, 00266 { 00267 ".....", 00268 ".X...", 00269 ".X...", 00270 ".XXX.", 00271 ".....", 00272 }, 00273 { 00274 ".....", 00275 ".X...", 00276 ".XX..", 00277 "..XX.", 00278 ".....", 00279 }, 00280 { 00281 ".....", 00282 "..X..", 00283 ".XXX.", 00284 "..X..", 00285 ".....", 00286 }, 00287 { 00288 ".....", 00289 "..X..", 00290 ".XX..", 00291 "..X..", 00292 "..X..", 00293 }, 00294 { 00295 ".....", 00296 ".XX..", 00297 "..X..", 00298 "..XX.", 00299 ".....", 00300 }, 00301 }; 00302 00303 00304 static void cpento_add_move(byte *move, int x, int y, int m) 00305 { 00306 int i; 00307 for (i=0; move[i] != -1; i += 3) 00308 { 00309 if (move[i] == x && move[i+1] == y) { 00310 move[i+2] = m; 00311 return; 00312 } 00313 } 00314 move[i] = x; 00315 move[i+1] = y; 00316 move[i+2] = m; 00317 move[i+3] = -1; 00318 return; 00319 } 00320 00321 00322 static void cpento_clear_left(byte *move) 00323 { 00324 int i, j, m; 00325 00326 /* Clear the left side of the board */ 00327 for (i=1; i < 6; ++i) 00328 for (j=1; j < 6; ++j) 00329 { 00330 cpento_add_move(move, i, j, 0); 00331 } 00332 } 00333 00334 /* From picture coords to display coords */ 00335 static void cpento_orient(int x, int y, int *nx, int *ny, int orient) 00336 { 00337 switch (orient) 00338 { 00339 case 0: *nx = x; *ny = y; return; 00340 case 1: *nx = 4-y; *ny = x; return; 00341 case 2: *nx = 4-x; *ny = 4-y; return; 00342 case 3: *nx = y; *ny = 4-x; return; 00343 case 4: *nx = 4-x; *ny = y; return; 00344 case 5: *nx = y; *ny = x; return; 00345 case 6: *nx = x; *ny = 4-y; return; 00346 case 7: *nx = 4-y; *ny = 4-x; return; 00347 } 00348 } 00349 00350 /* From display coords to picture coords */ 00351 static void cpento_rev_orient(int x, int y, int *nx, int *ny, int orient) 00352 { 00353 switch (orient) 00354 { 00355 case 0: *nx = x; *ny = y; return; 00356 case 1: *nx = y; *ny = 4-x; return; 00357 case 2: *nx = 4-x; *ny = 4-y; return; 00358 case 3: *nx = 4-y; *ny = x; return; 00359 case 4: *nx = 4-x; *ny = y; return; 00360 case 5: *nx = y; *ny = x; return; 00361 case 6: *nx = x; *ny = 4-y; return; 00362 case 7: *nx = 4-y; *ny = 4-x; return; 00363 } 00364 } 00365 00366 static int cpento_tile_orient(int x, int y, int orient, char **pento) 00367 { 00368 int tx, ty; 00369 int top=0, left=0, right=0, bottom=0; 00370 int results[16] = 00371 { 00372 0, 00373 CPENTO_PIECE_LEG_UP, 00374 CPENTO_PIECE_LEG_DOWN, 00375 CPENTO_PIECE_PIPE_VERT, 00376 CPENTO_PIECE_LEG_RIGHT, 00377 CPENTO_PIECE_BEND_UR, 00378 CPENTO_PIECE_BEND_DR, 00379 CPENTO_PIECE_T_LEFT, 00380 CPENTO_PIECE_LEG_LEFT, 00381 CPENTO_PIECE_BEND_UL, 00382 CPENTO_PIECE_BEND_DL, 00383 CPENTO_PIECE_T_RIGHT, 00384 CPENTO_PIECE_PIPE_HORIZ, 00385 CPENTO_PIECE_T_DOWN, 00386 CPENTO_PIECE_T_UP, 00387 CPENTO_PIECE_FOURWAY 00388 }; 00389 00390 cpento_rev_orient(x, y, &tx, &ty, orient); 00391 if (pento[tx][ty] != 'X') 00392 return 0; 00393 cpento_rev_orient(x, y+1, &tx, &ty, orient); 00394 top = (y < 4 && pento[tx][ty] == 'X'); 00395 cpento_rev_orient(x, y-1, &tx, &ty, orient); 00396 bottom = (y > 0 && pento[tx][ty] == 'X'); 00397 cpento_rev_orient(x+1, y, &tx, &ty, orient); 00398 right = (x < 4 && pento[tx][ty] == 'X'); 00399 cpento_rev_orient(x-1, y, &tx, &ty, orient); 00400 left = (x > 0 && pento[tx][ty] == 'X'); 00401 return results[top | bottom<<1 | right<<2 | left<<3]; 00402 } 00403 00404 static void cpento_place_left(byte *move, char *pento[5], 00405 int piece_letter, int orient) 00406 { 00407 int i, j; 00408 cpento_clear_left(move); 00409 for (i=0; i < 5; ++i) { 00410 for (j=0; j < 5; ++j) { 00411 int X, Y; 00412 cpento_orient(i, j, &X, &Y, orient); 00413 if (pento[i][j] == 'X') 00414 cpento_add_move(move, X+1, Y+1, 00415 cpento_tile_orient(X, Y, orient, pento)); 00416 } 00417 } 00418 } 00419 00420 00421 static void cpento_place_right(byte *move, char *pento[5], 00422 int piece_letter, int orient, 00423 int x, int y) 00424 { 00425 int i, j; 00426 for (i=0; i < 5; ++i) { 00427 for (j=0; j < 5; ++j) { 00428 int X, Y; 00429 cpento_orient(i, j, &X, &Y, orient); 00430 if (pento[i][j] == 'X') 00431 cpento_add_move(move, X+x-2, Y+y-2, 00432 cpento_tile_orient(X, Y, orient, pento)); 00433 } 00434 } 00435 } 00436 00437 00438 static int cpento_fits_right(byte *move, char *pento[5], 00439 int orient, int x, int y, Pos *pos) 00440 { 00441 int i, j; 00442 for (i=0; i < 5; ++i) { 00443 for (j=0; j < 5; ++j) { 00444 int X, Y; 00445 cpento_orient(i, j, &X, &Y, orient); 00446 if (pento[i][j] == 'X') { 00447 if (X+x-2 < 1 || X+x-2 > CPENTO_BOARD_WID-2) 00448 return 0; 00449 if (Y+y-2 < 1 || Y+y-2 > CPENTO_BOARD_HEIT-2) 00450 return 0; 00451 if (pos->board[(Y+y-2)*board_wid + (X+x-2)] != CPENTO_EMPTY) 00452 return 0; 00453 } 00454 } 00455 } 00456 return 1; 00457 } 00458 00459 00460 static int cpento_getmove(Pos *pos, int x, int y, 00461 GtkboardEventType type, 00462 Player to_play, byte **movp, 00463 int **renderp) 00464 { 00465 static byte move[2000]; /* theoretical max length: 151 */ 00466 static int state = 0; 00467 static int orient = 0; 00468 static int pento = 0; 00469 int tile; 00470 00471 /* States */ 00472 /* 0 = no pentomino selected */ 00473 /* 1 = pentomino selected */ 00474 /* Orientations */ 00475 /* 0 = neutral */ 00476 /* 1 = rot 90 right */ 00477 /* 2 = rot 180 right */ 00478 /* 5 = flipped, then rot 90 */ 00479 /* 7 = flipped, then rot 270 */ 00480 /* Pentos run 0..11 */ 00481 00482 static const int larrow_effects[] = 00483 { 1, 2, 3, 0, 7, 4, 5, 6 }; 00484 static const int rarrow_effects[] = 00485 { 3, 0, 1, 2, 5, 6, 7, 4 }; 00486 static const int fliplr_effects[] = 00487 { 4, 5, 6, 7, 0, 1, 2, 3 }; 00488 00489 if (type != GTKBOARD_BUTTON_RELEASE) 00490 return 0; 00491 00492 move[0] = -1; 00493 00494 tile = pos->board[y * board_wid + x]; 00495 00496 if (tile >= CPENTO_TILE_F && tile <= CPENTO_TILE_Z) 00497 { 00498 /* Select a new pentomino; get rid of the old one */ 00499 pento = (tile - CPENTO_TILE_F); 00500 orient = 0; 00501 cpento_place_left(move, cpento_piece_list[pento], tile, orient); 00502 state = 1; 00503 if (movp) 00504 *movp = move; 00505 return 1; 00506 } 00507 else if ((tile == CPENTO_TILE_LARROW) && (state == 1)) 00508 { 00509 orient = larrow_effects[orient]; 00510 cpento_place_left(move, cpento_piece_list[pento], pento, orient); 00511 if (movp) 00512 *movp = move; 00513 return 1; 00514 } 00515 else if ((tile == CPENTO_TILE_RARROW) && (state == 1)) 00516 { 00517 orient = rarrow_effects[orient]; 00518 cpento_place_left(move, cpento_piece_list[pento], pento, orient); 00519 if (movp) 00520 *movp = move; 00521 return 1; 00522 } 00523 else if ((tile == CPENTO_TILE_FLIPLR) && (state == 1)) 00524 { 00525 orient = fliplr_effects[orient]; 00526 cpento_place_left(move, cpento_piece_list[pento], pento, orient); 00527 if (movp) 00528 *movp = move; 00529 return 1; 00530 } 00531 else if (tile != CPENTO_EMPTY) 00532 { 00533 return -1; 00534 } 00535 else if ((x > 6) && (state == 1)) 00536 { 00537 cpento_clear_left(move); 00538 if (cpento_fits_right(move, cpento_piece_list[pento], orient, x, y, pos)) 00539 { 00540 cpento_place_right(move, cpento_piece_list[pento], pento, orient, x, y); 00541 state = 0; 00542 if (movp) 00543 *movp = move; 00544 return 1; 00545 } 00546 else { 00547 int possibles = 0; 00548 int fit = 0; 00549 if (cpento_fits_right(move, cpento_piece_list[pento], orient, 00550 x-1, y, pos)) 00551 ++possibles, fit = 0 * 3 + 1; 00552 if (cpento_fits_right(move, cpento_piece_list[pento], orient, 00553 x+1, y, pos)) 00554 ++possibles, fit = 2 * 3 + 1; 00555 if (cpento_fits_right(move, cpento_piece_list[pento], orient, 00556 x, y-1, pos)) 00557 ++possibles, fit = 1 * 3 + 0; 00558 if (cpento_fits_right(move, cpento_piece_list[pento], orient, 00559 x, y+1, pos)) 00560 ++possibles, fit = 1 * 3 + 2; 00561 00562 if (possibles != 1) 00563 return -1; 00564 00565 cpento_place_right(move, cpento_piece_list[pento], pento, orient, 00566 x+(fit/3)-1, y+(fit%3)-1); 00567 state = 0; 00568 if (movp) 00569 *movp = move; 00570 return 1; 00571 } 00572 } 00573 else 00574 { 00575 return -1; 00576 } 00577 } 00578