This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

cpento.c

Go to the documentation of this file.
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