This is the doxygen documentation for gtkboard.

.
Main Page   Data Structures   File List   Data Fields   Globals  

chess.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 <stdlib.h>
00022 #include <assert.h>
00023 
00024 #include "game.h"
00025 #include "../pixmaps/chess.xpm"
00026 #include "move.h"
00027 
00028 #define CHESS_CELL_SIZE 54
00029 #define CHESS_NUM_PIECES 12
00030 
00031 #define CHESS_BOARD_WID 8
00032 #define CHESS_BOARD_HEIT 8
00033 
00034 #define CHESS_EMPTY 0
00035 #define CHESS_WK 1
00036 #define CHESS_WQ 2
00037 #define CHESS_WR 3
00038 #define CHESS_WB 4
00039 #define CHESS_WN 5
00040 #define CHESS_WP 6
00041 #define CHESS_BK 7
00042 #define CHESS_BQ 8
00043 #define CHESS_BR 9
00044 #define CHESS_BB 10
00045 #define CHESS_BN 11
00046 #define CHESS_BP 12
00047 
00048 #define A_FILE 0
00049 #define B_FILE 1
00050 #define C_FILE 2
00051 #define D_FILE 3
00052 #define E_FILE 4
00053 #define F_FILE 5
00054 #define G_FILE 6
00055 #define H_FILE 7
00056 
00057 #define RANK_1 0
00058 #define RANK_2 1
00059 #define RANK_3 2
00060 #define RANK_4 3
00061 #define RANK_5 4
00062 #define RANK_6 5
00063 #define RANK_7 6
00064 #define RANK_8 7
00065 
00066 #define CHESS_ISWHITE(x) (x >= 1 && x <= 6)
00067 #define CHESS_ISBLACK(x) (x >= 7 && x <= 12)
00068 
00069 #ifndef abs
00070 #define abs(x) ((x) < 0 ? -(x) : (x))
00071 #endif
00072 
00073 char chess_colors[] = 
00074         {200, 200, 130, 
00075         0, 140, 0};
00076 
00077 int     chess_init_pos[] = 
00078 {
00079          9 , 11, 10, 8 , 7 , 10, 11, 9  ,
00080          12, 12, 12, 12, 12, 12, 12, 12 ,
00081          0 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ,
00082          0 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ,
00083          0 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ,
00084          0 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ,
00085          6 , 6 , 6 , 6 , 6 , 6 , 6 , 6  ,
00086          3 , 5 , 4 , 2 , 1 , 4 , 5 , 3  ,
00087 };
00088 static int chess_max_moves = 200;
00089 
00090 char ** chess_pixmaps[] =
00091 
00092 {
00093         chess_wk_54_xpm, 
00094         chess_wq_54_xpm, 
00095         chess_wr_54_xpm, 
00096         chess_wb_54_xpm, 
00097         chess_wn_54_xpm, 
00098         chess_wp_54_xpm, 
00099         chess_bk_54_xpm, 
00100         chess_bq_54_xpm, 
00101         chess_br_54_xpm, 
00102         chess_bb_54_xpm, 
00103         chess_bn_54_xpm, 
00104         chess_bp_54_xpm,
00105 };
00106 
00107 
00108 
00109 void chess_init ();
00110 int chess_getmove (Pos *, int, int, GtkboardEventType, Player, byte **, int **);
00111 ResultType chess_who_won (Pos *, Player, char **);
00112 byte *chess_movegen (Pos *);
00113 ResultType chess_eval (Pos *, Player, float *);
00114 void *chess_newstate (Pos *, byte *);
00115 void chess_reset_uistate ();
00116         
00117 Game Chess = 
00118         { CHESS_CELL_SIZE, CHESS_BOARD_WID, CHESS_BOARD_HEIT, 
00119         CHESS_NUM_PIECES,
00120         chess_colors, chess_init_pos, chess_pixmaps, "Chess",
00121         chess_init};
00122 
00123 typedef struct 
00124 {
00125         int castle_WK:2;
00126         int castle_WQ:2;
00127         int castle_BK:2;
00128         int castle_BQ:2;
00129         int epfile:4;
00130 } Chess_state;
00131 
00132 //Chess_state state;
00133 
00134 void chess_init ()
00135 {
00136         game_getmove = chess_getmove;
00137         game_who_won = chess_who_won;
00138         game_movegen = chess_movegen;
00139         game_eval = chess_eval;
00140         game_stateful = TRUE;
00141         game_state_size = sizeof (Chess_state);
00142         game_newstate = chess_newstate;
00143         game_file_label = FILERANK_LABEL_TYPE_ALPHA;
00144         game_rank_label = FILERANK_LABEL_TYPE_NUM | FILERANK_LABEL_DESC;
00145         game_reset_uistate = chess_reset_uistate;
00146         game_allow_flip = TRUE;
00147         game_doc_about = 
00148                 "Chess\n"
00149                 "Two player game\n"
00150                 "Status: Partially implemented (currently unplayable)\n"
00151                 "URL: "GAME_DEFAULT_URL("chess");
00152 }
00153 
00154 void *chess_newstate (Pos *pos, byte *move)
00155 {
00156         static Chess_state state = {1, 1, 1, 1, -1};
00157         if (!pos->state) return &state;
00158         memcpy (&state, pos->state, sizeof (Chess_state));
00159 
00160         {
00161         int val, to_x, to_y;
00162         // if pawn moves two squares to 4th rank then set epf
00163         if (move[2] != 0) { val = move[2]; to_x = move[0]; to_y = move[1]; }
00164         else if (move[5] != 0) { val = move[5]; to_x = move[3]; to_y = move[4]; }
00165         else assert (0);
00166         if (
00167                 (val == CHESS_WP 
00168                         && ((move[1] == 1 && move[4] == 3) || (move[1] == 3 && move[4] == 1)))
00169                 ||
00170                 (val == CHESS_BP 
00171                         && ((move[1] == 6 && move[3] == 4) || (move[1] == 6 && move[4] == 6)))
00172         )
00173                 state.epfile = move[0];
00174         else state.epfile = -1;
00175 
00176         if (val == CHESS_WK) state.castle_WK = state.castle_WQ = 0;
00177         if (val == CHESS_BK) state.castle_BK = state.castle_BQ = 0;
00178         if (val == CHESS_WR && to_x >= 4) state.castle_WK = 0;
00179         if (val == CHESS_WR && to_x <  4) state.castle_WQ = 0;
00180         if (val == CHESS_BR && to_x >= 4) state.castle_BK = 0;
00181         if (val == CHESS_BR && to_x <  4) state.castle_BQ = 0;
00182         } 
00183         
00184         return &state;
00185 }
00186         
00187 static int isfreeline (byte *pos, int oldx, int oldy, int newx, int newy)
00188 {
00189         int x = oldx, y = oldy, dx, dy, diffx = newx - oldx, diffy = newy - oldy;
00190         if (abs (diffx) != abs(diffy) && diffx != 0 && diffy != 0)
00191                 return 0;
00192         dx = (diffx ? (diffx / abs (diffx)) : 0);
00193         dy = (diffy ? (diffy / abs (diffy)) : 0);
00194         for (x+=dx, y+=dy; x != newx || y != newy; x+=dx, y+=dy)
00195                 if (pos [y * board_wid + x] != 0)
00196                         return 0;
00197         return 1;       
00198 }
00199 
00200 static int islegal (Pos *pos, int oldx, int oldy, int x, int y)
00201 {
00202         int piece = pos->board [oldy * board_wid + oldx];
00203         byte *board = pos->board;
00204         switch (piece)
00205         {
00206                 case CHESS_WK:
00207                 case CHESS_BK:
00208                         {
00209                                 int rank, rook;
00210                                 int diffx = abs (x - oldx), diffy = abs (y - oldy);
00211                                 if (diffx <= 1 && diffy <= 1) return 1;
00212                                 // castling
00213                                 rank = (piece == CHESS_WK ? 0 : 7);
00214                                 rook = (piece == CHESS_WK ? CHESS_WR : CHESS_BR);
00215                                 if (oldx != 4) return 0;
00216                                 if (oldy != rank || y != rank) return 0;
00217                                 // TODO: not yet checking if 
00218                                 //      - the intervening squares are uncontrolled
00219                                 //      - king hasn't moved yet
00220                                 if (x == 6)
00221                                 {
00222                                         if (board [rank * board_wid + 7] != rook) return 0;
00223                                         if (board [rank * board_wid + 6] != 0) return 0;
00224                                         if (board [rank * board_wid + 5] != 0) return 0;
00225                                         return 1;
00226                                 }
00227                                 else if (x == 2)
00228                                 {
00229                                         if (board [rank * board_wid + 0] != rook) return 0;
00230                                         if (board [rank * board_wid + 1] != 0) return 0;
00231                                         if (board [rank * board_wid + 2] != 0) return 0;
00232                                         if (board [rank * board_wid + 3] != 0) return 0;
00233                                         return 1;
00234                                 }
00235                                 return 0;
00236                         }
00237                 case CHESS_WQ:
00238                 case CHESS_BQ:
00239                         return isfreeline (board, oldx, oldy, x, y);
00240                 case CHESS_WR:
00241                 case CHESS_BR:
00242                         if (!isfreeline (board, oldx, oldy, x, y))
00243                                 return 0;
00244                         if (oldx == x || oldy == y)
00245                                 return 1;
00246                         return 0;
00247                 case CHESS_WB:
00248                 case CHESS_BB:
00249                         if (!isfreeline (board, oldx, oldy, x, y))
00250                                 return 0;
00251                         if (oldx == x || oldy == y)
00252                                 return 0;
00253                         return 1;
00254                 case CHESS_WN:
00255                 case CHESS_BN:
00256                         {
00257                                 int diffx = abs (x - oldx), diffy = abs (y - oldy);
00258                                 if (diffx == 2 && diffy == 1)
00259                                         return 1;
00260                                 if (diffx == 1 && diffy == 2)
00261                                         return 1;
00262                                 return 0;
00263                         }
00264                 case CHESS_WP:
00265                         if (board [y * board_wid + x] == 0)
00266                         {
00267                                 // en passant
00268                                 if (y == 5 && oldy == 4 && (x == oldx + 1 || x == oldx - 1)
00269                                                 && board [oldy * board_wid + x] == CHESS_BP)
00270                                         return 1;
00271                                 return (x == oldx && (y == oldy + 1 || 
00272                                                 (y == 3 && oldy == 1 && board [(2*board_wid + x)] == 0)));
00273                         }
00274                         return y == oldy + 1  && (x == oldx + 1 || x == oldx - 1) ;
00275                 case CHESS_BP:
00276                         if (board [y * board_wid + x] == 0)
00277                         {
00278                                 if (y == 4 && oldy == 5 && (x == oldx + 1 || x == oldx - 1)
00279                                                 && board [oldy * board_wid + x] == CHESS_WP)
00280                                         return 1;
00281                                 return (x == oldx && (y == oldy - 1 ||
00282                                                 (y == 4 && oldy == 6 && board [5*board_wid + x] == 0)));
00283                         }
00284                         return y == oldy - 1  && (x == oldx + 1 || x == oldx - 1) ;
00285                 default:
00286                         return 1;
00287         }
00288 }
00289 
00290 static int oppcolor (byte *board, int oldx, int oldy, int x, int y)
00291         /* True if one square is W and the other is B */
00292 {
00293         int oldv = board [oldy * board_wid + oldx], v = board [y * board_wid + x];
00294         if (CHESS_ISWHITE (oldv) && CHESS_ISBLACK (v)) return 1;
00295         if (CHESS_ISBLACK (oldv) && CHESS_ISWHITE (v)) return 1;
00296         return 0;
00297 }
00298 
00299 static gboolean is_in_check (Pos *pos, Player player)
00300 {
00301         int i, j, kingx = -1, kingy = -1;
00302         for (i=0; i<board_wid; i++)
00303         for (j=0; j<board_heit; j++)
00304         {
00305                 int val = pos->board [j * board_wid + i];
00306                 if ((player == WHITE && val == CHESS_WK) || 
00307                                 (player == BLACK && val == CHESS_BK))
00308                 {
00309                         kingx = i;
00310                         kingy = j;
00311                 }
00312         }
00313         
00314         for (i=0; i<board_wid; i++)
00315         for (j=0; j<board_heit; j++)
00316         {
00317                 int val = pos->board [j * board_wid + i];
00318                 if (!((player == WHITE && CHESS_ISBLACK (val)) || 
00319                                 (player == BLACK && CHESS_ISWHITE (val))))
00320                         continue;
00321                 if (islegal (pos, i, j, kingx, kingy))
00322                         return TRUE;
00323         }
00324         return FALSE;
00325 }
00326 
00328 static gboolean leads_to_check (byte *board, byte *move, Player player)
00329 {
00330         static byte newboard [CHESS_BOARD_WID*CHESS_BOARD_HEIT];
00331         Pos pos;
00332         memcpy (newboard, board, board_wid * board_heit);
00333         move_apply (newboard, move);
00334         pos.board = newboard;
00335         pos.state = NULL;
00336         return is_in_check (&pos, player);
00337 
00338 }
00339 
00340 static int oldx = -1, oldy = -1, oldval = -1;
00341 static int prom = 0, prom_x, prom_oldx;
00342         
00343 void chess_reset_uistate ()
00344 {
00345         oldx = -1, oldy = -1, oldval = -1;
00346         prom = 0;
00347 }
00348 
00349 int chess_getmove (Pos *pos, int x, int y, GtkboardEventType type, Player player, 
00350                 byte ** movep, int ** rmovep)
00351         /* Translate mouse clicks into move */
00352 {
00353         static byte move [13];
00354         int val;
00355         if (type != GTKBOARD_BUTTON_RELEASE)
00356                 return 0;
00357 
00358         if (oldx >= 0 && x == oldx && y == oldy)
00359         {
00360                 oldx = -1; oldy = -1; return 0;
00361         }
00362         
00363         /* pawn promotion */ 
00364         if (prom)
00365         {
00366                 int new_p = -1;
00367                 prom = 0;
00368                 switch(x)
00369                 {
00370                         case 0: case 7:
00371                                 new_p = (player == WHITE ? CHESS_WR : CHESS_BR); break;
00372                         case 1: case 6:
00373                                 new_p = (player == WHITE ? CHESS_WN : CHESS_BN); break;
00374                         case 2: case 5:
00375                                 new_p = (player == WHITE ? CHESS_WB : CHESS_BB); break;
00376                         case 3: case 4:
00377                                 new_p = (player == WHITE ? CHESS_WQ : CHESS_BQ); break;
00378                 }
00379                 move[0] = prom_oldx;
00380                 move[1] = (player == WHITE ? 6 : 1);
00381                 move[2] = 0;
00382                 move[3] = prom_x;
00383                 move[4] = (player == WHITE ? 7 : 0);
00384                 move[5] = new_p;
00385                 move[6] = -1;
00386 
00387                 if (leads_to_check (pos->board, move, player)) return -1;
00388                 
00389                 if (movep)
00390                         *movep = move;
00391                 return 1;
00392         }
00393         val = pos->board [y * board_wid + x];
00394         if (oldx == -1)
00395         {
00396                 if (val == 0) return -1;
00397                 if (player == WHITE && !CHESS_ISWHITE (val))
00398                         return -1;
00399                 if (player == BLACK && !CHESS_ISBLACK (val))
00400                         return -1;
00401                 oldx = x; oldy = y, oldval = val;
00402                 return 0;
00403         }
00404         if (player == WHITE && CHESS_ISWHITE (val))
00405         {
00406                 oldx = -1; oldy = -1;
00407                 return -1;
00408         }
00409         if (player == BLACK && CHESS_ISBLACK (val))
00410         {
00411                 oldx = -1; oldy = -1;
00412                 return -1;
00413         }
00414 
00415         if (!islegal (pos, oldx, oldy, x, y))
00416         {
00417                 oldx = -1; oldy = -1;
00418                 return -1;
00419         }
00420 
00421         /* en passant */
00422         if ((oldval == CHESS_WP || oldval == CHESS_BP) && val == 0
00423                         && x != oldx)
00424         {
00425                 move[0] = oldx; move[1] = oldy; move[2] = 0;
00426                 move[3] = x; move[4] = y; move[5] = oldval;
00427                 move[6] = x; move[7] = oldy; move[8] = 0;
00428                 move[9] = -1;
00429                 if (leads_to_check (pos->board, move, player)) return -1;
00430                 if (movep)
00431                         *movep = move;
00432                 return 1;
00433         }
00434 
00435         /* pawn promotion */
00436         if ((oldval == CHESS_WP || oldval == CHESS_BP) &&
00437                         (y == 0 || y == board_heit - 1))
00438         {
00439                 prom = 1;
00440                 prom_oldx = oldx;
00441                 prom_x = x;
00442                 oldx = oldy = -1;
00443                 return 0;
00444         }
00445 
00446         /* castling */
00447         if ((oldval == CHESS_WK || oldval == CHESS_BK)
00448                         && abs (x - oldx) > 1)
00449         {
00450                 int rfile = x == 6 ? 7 : 0;
00451                 int rook = pos->board [y * board_wid + rfile];
00452                 move[0] = oldx; move[1] = oldy; move[2] = 0;
00453                 move[3] = x; move[4] = y; move[5] = oldval;
00454                 move[6] = (oldx + x)/2; move[7] = y; move[8] = rook;
00455                 move[9] = rfile; move[10] = y; move[11] = 0;
00456                 move[12] = -1;
00457                 oldx = -1, oldy = -1;
00458                 if (leads_to_check (pos->board, move, player)) return -1;
00459                 if (movep)
00460                         *movep = move;
00461                 return 1;
00462         }
00463 
00464         move[0] = oldx; move[1] = oldy; move[2] = 0;
00465         move[3] = x; move[4] = y; move[5] = oldval;
00466         move[6] = -1;
00467 
00468         oldx = -1; oldy = -1;
00469         if (leads_to_check (pos->board, move, player)) return -1;
00470         
00471         if (movep)
00472                 *movep = move;
00473         return 1;
00474 }
00475 
00476 static int hasmove (Pos *pos, int player)
00477 {
00478         int x1, y1, x2, y2, val;
00479         for (x1 = 0; x1 < board_wid; x1++)
00480         for (y1 = 0; y1 < board_heit; y1++)
00481         {
00482                 val = pos->board [y1 * board_wid + x1];
00483                 if (player == WHITE && !CHESS_ISWHITE (val)) continue;
00484                 if (player == BLACK && !CHESS_ISBLACK (val)) continue;
00485                 for (x2 = 0; x2 < board_wid; x2++)
00486                 for (y2 = 0; y2 < board_heit; y2++)
00487                         if (islegal (pos, x1, y1, x2, y2)) return 1;
00488         }
00489         return 0;
00490 }
00491 
00492 ResultType chess_who_won (Pos *pos, Player player, char **commp)
00493 {
00494         static char comment[32];
00495         char *who_str [3] = { "White won", "Black won", "Draw" };
00496         byte *move_list;
00497         *commp = NULL;
00498         move_list = chess_movegen (pos);
00499         if (move_list[0] != -2)
00500         {
00501                 if (pos->num_moves > chess_max_moves)
00502                 {
00503                         fprintf (stderr, "max moves reached\n");
00504                         snprintf (comment, 32, "%s", who_str[2]);
00505                         *commp = comment;
00506                         return RESULT_TIE;
00507                 }
00508                 return RESULT_NOTYET;
00509         }
00510         *commp = comment;
00511         if (is_in_check (pos, player))
00512         {
00513                 strncpy (comment, who_str[player == WHITE ? 1 : 0], 31);
00514                 return player == WHITE ? RESULT_BLACK : RESULT_WHITE;
00515         }
00516         else 
00517         {
00518                 strncpy (comment, who_str[2], 31);
00519                 return RESULT_TIE;
00520         }
00521 }
00522 
00523 int chess_movegen_square (byte *board, byte **movp, int player,
00524                 int oldx, int oldy, int x, int y)
00525 {
00526         int val;
00527         if (!ISINBOARD(x, y)) return 0;
00528         val = board [y * board_heit + x];
00529         if ((player == WHITE && CHESS_ISWHITE (val))
00530                 || (player == BLACK && CHESS_ISBLACK (val)))
00531                 return 0;
00532         *(*movp)++ = oldx;
00533         *(*movp)++ = oldy;
00534         *(*movp)++ = 0;
00535         *(*movp)++ = x;
00536         *(*movp)++ = y;
00537         *(*movp)++ = board [oldy * board_heit + oldx];
00538         *(*movp)++ = -1;
00539         if (leads_to_check (board, *movp-7, player))
00540         {
00541                 *movp -= 7;
00542                 return 0;
00543         }
00544         return 1;
00545 }
00546 
00547 int chess_movegen_line (byte *pos, byte **movp, int player,
00548                 int x, int y, int incx, int incy)
00549 {
00550         int oldx = x, oldy = y;
00551         int capture = 0, val;
00552         do
00553         {
00554                 x += incx;
00555                 y += incy;
00556                 val = pos [y * board_heit + x];
00557                 if (ISINBOARD (x, y) && oppcolor (pos, oldx, oldy, x, y))
00558                         capture = 1;
00559         } while (chess_movegen_square (pos, movp, player, oldx, oldy, x, y) && !capture);
00560         return 0;
00561 }
00562 
00563 static void chess_movegen_promote (byte *board, byte **movp, int player,
00564                 int oldx, int oldy, int x, int y)
00565 {
00566         int i, j;
00567         int promote_pieces[2][4] = {
00568                 {CHESS_WQ, CHESS_WR, CHESS_WB, CHESS_WN},
00569                 {CHESS_BQ, CHESS_BR, CHESS_BB, CHESS_BN}
00570         };
00571         i = (player == WHITE ? 0 : 1);
00572         for(j=0; j<4; j++) 
00573         {
00574                 *(*movp)++ = oldx;
00575                 *(*movp)++ = oldy;
00576                 *(*movp)++ = 0;
00577                 *(*movp)++ = x;
00578                 *(*movp)++ = y;
00579                 *(*movp)++ = promote_pieces[i][j];
00580                 *(*movp)++ = -1;
00581                 if (leads_to_check (board, *movp-7, player))
00582                 {
00583                         *movp -= 7;
00584                         return;
00585                 }
00586         }
00587 }
00588 
00589 static void chess_movegen_enpassant (Pos *pos, byte **movp, int player,
00590                 int x, int y)
00591 {
00592         int val = pos->board [y * board_wid + x];
00593         int epfile;
00594         if (!pos->state) epfile = -1;
00595         else epfile = ((Chess_state *)pos->state)->epfile;
00596         if (epfile < 0)
00597                 return;
00598         if ((player == WHITE && val != CHESS_WP) || 
00599                         (player == BLACK && val != CHESS_BP))
00600                 return;
00601         if ((player == WHITE && y != 4) ||  
00602                         (player == BLACK && y != 3))
00603                 return;
00604         if (abs (x - epfile) != 1)
00605                 return;
00606         *(*movp)++ = x;
00607         *(*movp)++ = y;
00608         *(*movp)++ = 0;
00609         *(*movp)++ = epfile;
00610         *(*movp)++ = y + (player == WHITE ? 1 : -1);
00611         *(*movp)++ = val;
00612         *(*movp)++ = epfile;
00613         *(*movp)++ = y;
00614         *(*movp)++ = 0;
00615         *(*movp)++ = -1;
00616         if (leads_to_check (pos->board, *movp-10, player))
00617                 *movp -= 10;
00618 }
00619 
00620 static void chess_movegen_castle (Pos *pos, byte **movp, int player)
00621 {
00622         int rank = player == WHITE ? RANK_1 : RANK_8;
00623         int king = player == WHITE ? CHESS_WK : CHESS_BK;
00624         int rook = player == WHITE ? CHESS_WR : CHESS_BR;
00625         int castle_k, castle_q;
00626         byte *board = pos->board;
00627         if (!pos->state) return;
00628         castle_k = player == WHITE ? 
00629                 ((Chess_state *)pos->state)->castle_WK : ((Chess_state *)pos->state)->castle_BK;
00630         castle_q = player == WHITE ? 
00631                 ((Chess_state *)pos->state)->castle_WQ : ((Chess_state *)pos->state)->castle_BQ;
00632         if (board [rank * board_wid + E_FILE] != king)
00633                 return;
00634         if (is_in_check (pos, player)) return;
00635 
00636         if (board [rank * board_wid + H_FILE] == rook && castle_k)
00637         {
00638                 gboolean allowed = TRUE;
00639                 *(*movp)++ = E_FILE;
00640                 *(*movp)++ = rank;
00641                 *(*movp)++ = 0;
00642                 *(*movp)++ = F_FILE;
00643                 *(*movp)++ = rank;
00644                 *(*movp)++ = king;
00645                 *(*movp)++ = -1;
00646                 if (leads_to_check (pos->board, *movp-7, player))
00647                         allowed = FALSE;
00648                 *movp -= 7;
00649                 
00650                 *(*movp)++ = E_FILE;
00651                 *(*movp)++ = rank;
00652                 *(*movp)++ = 0;
00653                 *(*movp)++ = G_FILE;
00654                 *(*movp)++ = rank;
00655                 *(*movp)++ = king;
00656                 *(*movp)++ = -1;
00657                 if (leads_to_check (pos->board, *movp-7, player))
00658                         allowed = FALSE;
00659                 *movp -= 7;
00660 
00661                 if (allowed)
00662                 {
00663                         *(*movp)++ = E_FILE;
00664                         *(*movp)++ = rank;
00665                         *(*movp)++ = 0;
00666                         *(*movp)++ = G_FILE;
00667                         *(*movp)++ = rank;
00668                         *(*movp)++ = king;
00669                         *(*movp)++ = H_FILE;
00670                         *(*movp)++ = rank;
00671                         *(*movp)++ = 0;
00672                         *(*movp)++ = F_FILE;
00673                         *(*movp)++ = rank;
00674                         *(*movp)++ = rook;
00675                         *(*movp)++ = -1;
00676                 }
00677         }
00678         
00679         if (board [rank * board_wid + A_FILE] == rook && castle_q)
00680         {
00681                 gboolean allowed = TRUE;
00682                 *(*movp)++ = E_FILE;
00683                 *(*movp)++ = rank;
00684                 *(*movp)++ = 0;
00685                 *(*movp)++ = D_FILE;
00686                 *(*movp)++ = rank;
00687                 *(*movp)++ = king;
00688                 *(*movp)++ = -1;
00689                 if (leads_to_check (pos->board, *movp-7, player))
00690                         allowed = FALSE;
00691                 *movp -= 7;
00692                 
00693                 *(*movp)++ = E_FILE;
00694                 *(*movp)++ = rank;
00695                 *(*movp)++ = 0;
00696                 *(*movp)++ = C_FILE;
00697                 *(*movp)++ = rank;
00698                 *(*movp)++ = king;
00699                 *(*movp)++ = -1;
00700                 if (leads_to_check (pos->board, *movp-7, player))
00701                         allowed = FALSE;
00702                 *movp -= 7;
00703 
00704                 if (allowed)
00705                 {
00706                         *(*movp)++ = E_FILE;
00707                         *(*movp)++ = rank;
00708                         *(*movp)++ = 0;
00709                         *(*movp)++ = C_FILE;
00710                         *(*movp)++ = rank;
00711                         *(*movp)++ = king;
00712                         *(*movp)++ = A_FILE;
00713                         *(*movp)++ = rank;
00714                         *(*movp)++ = 0;
00715                         *(*movp)++ = D_FILE;
00716                         *(*movp)++ = rank;
00717                         *(*movp)++ = rook;
00718                         *(*movp)++ = -1;
00719                 }
00720         }
00721 }
00722 
00723 byte *chess_movegen (Pos *pos)
00724 {
00725         byte realbuf[4096];
00726         byte *realp = realbuf;
00727         byte movbuf[4096], *movp = movbuf;
00728         byte *movlist;
00729         int i, j, k, x, y;
00730         int incxr[] = {0, 0, 1, -1};
00731         int incyr[] = {1, -1, 0, 0};
00732         int incxb[] = {1, 1, -1, -1};
00733         int incyb[] = {1, -1, 1, -1};
00734         int incxn[] = {2, 2, -2, -2, 1, 1, -1, -1};
00735         int incyn[] = {1, -1, 1, -1, 2, -2, 2, -2};
00736         byte *board = pos->board;
00737         Player player = pos->player;
00738         for (i=0; i<board_wid; i++)
00739         for (j=0; j<board_heit; j++)
00740         {
00741                 int val = board[j * board_heit + i];
00742                 if ((player == WHITE && CHESS_ISWHITE (val))
00743                         || (player == BLACK && CHESS_ISBLACK (val)))
00744                 {
00745                         switch (val)
00746                         {
00747                                 case CHESS_WP:
00748                                         chess_movegen_enpassant (pos, &movp, player, i, j);
00749                                         if (ISINBOARD (i, j+1) && board [(j+1) * board_heit + i] == 0)
00750                                         {
00751                                                 if (j == board_heit - 2)
00752                                                         chess_movegen_promote(board, &movp, player,
00753                                                                 i, j, i, j+1);
00754                                                 else
00755                                                         chess_movegen_square (board, &movp, player,
00756                                                                 i, j, i, j+1);
00757                                         }
00758                                         if (ISINBOARD (i+1, j+1) && 
00759                                                         CHESS_ISBLACK (board [(j+1) * board_heit + i+1]))
00760                                         {
00761                                                 if (j == board_heit - 2)
00762                                                         chess_movegen_promote (board, &movp, player,
00763                                                                 i, j, i+1, j+1);
00764                                                 else
00765                                                         chess_movegen_square (board, &movp, player,
00766                                                                 i, j, i+1, j+1);
00767                                         }
00768                                         if (ISINBOARD (i-1, j+1) && 
00769                                                         CHESS_ISBLACK (board [(j+1) * board_heit + i-1]))
00770                                         {
00771                                                 if (j == board_heit - 2)
00772                                                         chess_movegen_promote (board, &movp, player,
00773                                                                 i, j, i-1, j+1);
00774                                                 else
00775                                                         chess_movegen_square (board, &movp, player,
00776                                                                 i, j, i-1, j+1);
00777                                         }
00778                                         if (j == 1 && board [2 * board_heit + i] == 0
00779                                                         && board [3 * board_heit + i] == 0)
00780                                                 chess_movegen_square (board, &movp, player,
00781                                                                 i, j, i, j+2);
00782                                         break;
00783                                 case CHESS_BP:
00784                                         chess_movegen_enpassant (pos, &movp, player, i, j);
00785                                         if (ISINBOARD (i, j-1) && board [(j-1) * board_heit + i] == 0)
00786                                         {
00787                                                 if (j == 1)
00788                                                         chess_movegen_promote (board, &movp, player,
00789                                                                 i, j, i, j-1);
00790                                                 else
00791                                                         chess_movegen_square (board, &movp, player,
00792                                                                 i, j, i, j-1);
00793                                         }
00794                                         if (ISINBOARD (i+1, j-1) && 
00795                                                         CHESS_ISWHITE (board [(j-1) * board_heit + i+1]))
00796                                         {
00797                                                 if (j == 1)
00798                                                         chess_movegen_promote (board, &movp, player,
00799                                                                 i, j, i+1, j-1);
00800                                                 else
00801                                                         chess_movegen_square (board, &movp, player,
00802                                                                 i, j, i+1, j-1);
00803                                         }
00804                                         if (ISINBOARD (i-1, j-1) && 
00805                                                         CHESS_ISWHITE (board [(j-1) * board_heit + i-1]))
00806                                         {
00807                                                 if (j == 1)
00808                                                         chess_movegen_promote (board, &movp, player,
00809                                                                 i, j, i-1, j-1);
00810                                                 else
00811                                                         chess_movegen_square (board, &movp, player,
00812                                                                 i, j, i-1, j-1);
00813                                         }
00814                                         if (j == 6 && board [5 * board_heit + i] == 0
00815                                                         && board [4 * board_heit + i] == 0)
00816                                                 chess_movegen_square (board, &movp, player,
00817                                                                 i, j, i, j-2);
00818                                         break;
00819                                 case CHESS_WK:
00820                                 case CHESS_BK:
00821                                         chess_movegen_castle (pos, &movp, player);
00822                                         for (k=0; k<4; k++)
00823                                                 chess_movegen_square(board, &movp, player, 
00824                                                                 i, j, i + incxr[k], j + incyr[k]);
00825                                         for (k=0; k<4; k++)
00826                                                 chess_movegen_square(board, &movp, player, 
00827                                                                 i, j, i + incxb[k], j + incyb[k]);
00828                                         break;
00829                                 case CHESS_WB:
00830                                 case CHESS_BB:
00831                                         for (k=0; k<4; k++)
00832                                                 chess_movegen_line (board, &movp, player, 
00833                                                                 i, j, incxb[k], incyb[k]);
00834                                         break;
00835                                 case CHESS_WR:
00836                                 case CHESS_BR:
00837                                         for (k=0; k<4; k++)
00838                                                 chess_movegen_line (board, &movp, player, 
00839                                                                 i, j, incxr[k], incyr[k]);
00840                                         break;
00841                                 case CHESS_WQ:
00842                                 case CHESS_BQ:
00843                                         for (k=0; k<4; k++)
00844                                                 chess_movegen_line (board, &movp, player, 
00845                                                                 i, j, incxb[k], incyb[k]);
00846                                         for (k=0; k<4; k++)
00847                                                 chess_movegen_line (board, &movp, player, 
00848                                                                 i, j, incxr[k], incyr[k]);
00849                                         break;
00850                                 case CHESS_WN:
00851                                 case CHESS_BN:
00852                                         for (k=0; k<8; k++)
00853                                                 chess_movegen_square(board, &movp, player, 
00854                                                                 i, j, i + incxn[k], j + incyn[k]);
00855                                         break;
00856                         }
00857                 }
00858         }
00859         *movp++ = -2;
00860         
00861         movlist = (byte *) malloc (movp - movbuf);
00862         memcpy (movlist, movbuf, movp - movbuf);
00863         return movlist;
00864 }
00865 
00866 float getweight (byte val)
00867 {
00868         if (val == 0)
00869                 return 0;
00870         switch (val)
00871         {
00872                 case CHESS_WK: return 100;
00873                 case CHESS_WQ: return 9;
00874                 case CHESS_WR: return 5;
00875                 case CHESS_WB: return 3;
00876                 case CHESS_WN: return 3;
00877                 case CHESS_WP: return 1;
00878                 case CHESS_BK: return -100;
00879                 case CHESS_BQ: return -9;
00880                 case CHESS_BR: return -5;
00881                 case CHESS_BB: return -3;
00882                 case CHESS_BN: return -3;
00883                 case CHESS_BP: return -1;
00884                 default: return 0;
00885         }
00886 }
00887 
00888 ResultType chess_eval (Pos * pos, Player player, float *eval)
00889 {
00890         float sum = 0;
00891         int i;
00892         for (i=0; i<board_wid * board_heit; i++)
00893                 sum += getweight (pos->board [i]);
00894         *eval = sum;
00895         return RESULT_NOTYET;
00896 }