├── .gitignore ├── Makefile ├── README.txt ├── chart_functions.png ├── logoDusan.jpg ├── logoGrahamBanks.png ├── secondchess ├── secondchess.c └── secondchessW32.exe /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-O3 -funroll-loops 3 | 4 | seondchessmake: secondchess.c 5 | $(CC) -o secondchess *.c $(CFLAGS) 6 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | -secondchess is a derivative of firstchess 2 | 3 | -Its main aim is to add the neccesary code to firstchess in order 4 | to make it play real chess, especially adding the rules for castle and en 5 | passant capture, focusing in an easy to read code. 6 | 7 | -To compile under linux just "gcc secondchess.c -o secondchess -Ofast" 8 | 9 | -To compile under windows try tcc, geany+gcc, lcc. More info on the topic on http://www.chess2u.com/t5750-secondchess 10 | 11 | -Acknowledgments: 12 | -Pham Hong Nguyen, author of firstchess 13 | -Pedro Castro, author of danasah 14 | -The authors of http://chessprogramming.wikispaces.com/ 15 | -Tony Mokonen for his windows compilations 16 | -Tom Kerrigan for TSCP 17 | -Bruce Moreland for his site 18 | -The people who post on talkchess 19 | -Jonatan Pettersson, author of mediocre chess 20 | -Graham Banks and Dusan Stamenkovic for their logos 21 | -Many more... 22 | 23 | -------------------------------------------------------------------------------- /chart_functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/chart_functions.png -------------------------------------------------------------------------------- /logoDusan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/logoDusan.jpg -------------------------------------------------------------------------------- /logoGrahamBanks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/logoGrahamBanks.png -------------------------------------------------------------------------------- /secondchess: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/secondchess -------------------------------------------------------------------------------- /secondchess.c: -------------------------------------------------------------------------------- 1 | /* 2 | secondchess - gpl, by Emilio D�az, based on firstchess by Pham Hong Nguyen 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see 16 | 17 | * BASIC PARTS: * 18 | * Some definitions * 19 | * Board representation and main varians * 20 | * Move generator * 21 | * Evaluation for current position * 22 | * Make and Take back a move * 23 | * IsInCheck * 24 | * IsAttacked * 25 | * Search function - a typical alphabeta * 26 | * Quiescent search 27 | * Utilities * 28 | * Main program * 29 | */ 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | //#define NDEBUG 38 | #include 39 | 40 | /* 41 | **************************************************************************** 42 | * Some definitions * 43 | **************************************************************************** 44 | */ 45 | #define PAWN 0 46 | #define KNIGHT 1 47 | #define BISHOP 2 48 | #define ROOK 3 49 | #define QUEEN 4 50 | #define KING 5 51 | #define EPS_SQUARE 6 52 | #define EMPTY 7 53 | #define WHITE 0 54 | #define BLACK 1 55 | #define false 0 56 | 57 | /* The values of the pieces */ 58 | #define VALUE_PAWN 100 59 | #define VALUE_KNIGHT 310 60 | #define VALUE_BISHOP 320 61 | #define VALUE_ROOK 500 62 | #define VALUE_QUEEN 900 63 | #define VALUE_KING 10000 64 | 65 | #define MATE 10000 /* equal value of King, losing King==mate */ 66 | 67 | #define COL(pos) ((pos)&7) 68 | #define ROW(pos) (((unsigned)pos)>>3) 69 | 70 | /* For move generation */ 71 | #define MOVE_TYPE_NONE 0 72 | #define MOVE_TYPE_NORMAL 1 73 | #define MOVE_TYPE_CASTLE 2 74 | #define MOVE_TYPE_PAWN_TWO 3 75 | #define MOVE_TYPE_EPS 4 76 | #define MOVE_TYPE_PROMOTION_TO_QUEEN 5 77 | #define MOVE_TYPE_PROMOTION_TO_ROOK 6 78 | #define MOVE_TYPE_PROMOTION_TO_BISHOP 7 79 | #define MOVE_TYPE_PROMOTION_TO_KNIGHT 8 80 | 81 | /* Some useful squares */ 82 | #define A1 56 83 | #define B1 57 84 | #define C1 58 85 | #define D1 59 86 | #define E1 60 87 | #define F1 61 88 | #define G1 62 89 | #define H1 63 90 | #define A8 0 91 | #define B8 1 92 | #define C8 2 93 | #define D8 3 94 | #define E8 4 95 | #define F8 5 96 | #define G8 6 97 | #define H8 7 98 | 99 | /* 100 | **************************************************************************** 101 | * Board representation and main variants * 102 | **************************************************************************** 103 | */ 104 | /* Board representation */ 105 | int piece[64]; 106 | int color[64]; 107 | 108 | /* Piece in each square */ 109 | int init_piece[64] = { 110 | ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 111 | PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 112 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 113 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 114 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 115 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 116 | PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 117 | ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK 118 | }; 119 | 120 | /* Color of each square */ 121 | int init_color[64] = { 122 | BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, 123 | BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, 124 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 125 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 126 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 127 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 128 | WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, 129 | WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE 130 | }; 131 | 132 | //int piece[64] = { 133 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 134 | // EMPTY, EMPTY, EMPTY, EMPTY, ROOK, PAWN, EMPTY, EMPTY, 135 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 136 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 137 | // EMPTY, EMPTY, EMPTY, EMPTY, PAWN, KING, EMPTY, EMPTY, 138 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 139 | // EMPTY, EMPTY, EMPTY, PAWN, EMPTY, EMPTY, PAWN, PAWN, 140 | // EMPTY, EMPTY, EMPTY, EMPTY, KING, EMPTY, EMPTY, ROOK }; 141 | ///* Color of each square */ 142 | //int color[64] = { 143 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 144 | // EMPTY, EMPTY, EMPTY, EMPTY, BLACK, WHITE, EMPTY, EMPTY, 145 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 146 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 147 | // EMPTY, EMPTY, EMPTY, EMPTY, BLACK, BLACK, EMPTY, EMPTY, 148 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, 149 | // EMPTY, EMPTY, EMPTY, WHITE, EMPTY, EMPTY, WHITE, WHITE, 150 | // EMPTY, EMPTY, EMPTY, EMPTY, WHITE, EMPTY, EMPTY, WHITE }; 151 | 152 | 153 | int side; /* Side to move, value = BLACK or WHITE */ 154 | int computer_side; 155 | int max_depth; /* max depth to search */ 156 | 157 | /* A move is defined by its origin and final squares, the castle rights and the kind of 158 | * move it's: normal, enpasant... */ 159 | typedef struct tag_MOVE 160 | { 161 | int from; 162 | int dest; 163 | // int castle; 164 | int type; 165 | } MOVE; 166 | 167 | /* For storing all moves of game */ 168 | typedef struct tag_HIST 169 | { 170 | MOVE m; 171 | int castle; 172 | int cap; 173 | } HIST; 174 | 175 | HIST hist[6000]; /* Game length < 6000 */ 176 | 177 | /* For castle rights we use a bitfield, like in TSCP 178 | * 179 | * 0001 -> White can short castle 180 | * 0010 -> White can long castle 181 | * 0100 -> Black can short castle 182 | * 1000 -> Black can long castle 183 | * 184 | * 15 = 1111 = 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0 185 | * 186 | */ 187 | int castle_rights = 15; /* At start position all castle types ar available */ 188 | 189 | 190 | /* This mask is applied like this 191 | * 192 | * castle &= castle_mask[from] & castle_mask[dest] 193 | * 194 | * When from and dest are whatever pieces, then nothing happens, otherwise 195 | * the values are chosen in such a way that if vg the white king moves 196 | * to F1 then 197 | * 198 | * castle = castle & (12 & 15) 199 | * 1111 & (1100 & 1111) == 1111 & 1100 == 1100 200 | * 201 | * and white's lost all its castle rights 202 | * 203 | * */ 204 | int castle_mask[64] = { 205 | 7, 15, 15, 15, 3, 15, 15, 11, 206 | 15, 15, 15, 15, 15, 15, 15, 15, 207 | 15, 15, 15, 15, 15, 15, 15, 15, 208 | 15, 15, 15, 15, 15, 15, 15, 15, 209 | 15, 15, 15, 15, 15, 15, 15, 15, 210 | 15, 15, 15, 15, 15, 15, 15, 15, 211 | 15, 15, 15, 15, 15, 15, 15, 15, 212 | 13, 15, 15, 15, 12, 15, 15, 14 213 | }; 214 | 215 | int hdp; /* Current move order */ 216 | //int allmoves = 0; 217 | 218 | /* For searching */ 219 | int nodes; /* Count all visited nodes when searching */ 220 | int ply; /* ply of search */ 221 | int count_evaluations; 222 | int count_checks; 223 | int count_MakeMove; 224 | int count_quies_calls; 225 | int count_cap_calls; 226 | 227 | /* The values of the pieces in centipawns */ 228 | int value_piece[6] = 229 | { VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, 230 | VALUE_KING }; 231 | 232 | /* * * * * * * * * * * * * 233 | * Piece Square Tables 234 | * * * * * * * * * * * * */ 235 | /* When evaluating the position we'll add a bonus (or malus) to each piece 236 | * depending on the very square where it's placed. Vg, a knight in d4 will 237 | * be given an extra +15, whilst a knight in a1 will be penalized with -40. 238 | * This simple idea allows the engine to make more sensible moves */ 239 | int pst_pawn[64] = { 240 | 0, 0, 0, 0, 0, 0, 0, 0, 241 | 0, 0, 0, 0, 0, 0, 0, 0, 242 | 0, 0, 0, 0, 0, 0, 0, 0, 243 | 0, 0, 0, 15, 15, 0, 0, 0, 244 | 0, 0, 0, 10, 10, 0, 0, 0, 245 | 0, 0, 0, 5, 5, 0, 0, 0, 246 | 0, 0, 0, -25, -25, 0, 0, 0, 247 | 0, 0, 0, 0, 0, 0, 0, 0 248 | }; 249 | 250 | int pst_knight[64] = { 251 | -40, -25, -25, -25, -25, -25, -25, -40, 252 | -30, 0, 0, 0, 0, 0, 0, -30, 253 | -30, 0, 0, 0, 0, 0, 0, -30, 254 | -30, 0, 0, 15, 15, 0, 0, -30, 255 | -30, 0, 0, 15, 15, 0, 0, -30, 256 | -30, 0, 10, 0, 0, 10, 0, -30, 257 | -30, 0, 0, 5, 5, 0, 0, -30, 258 | -40, -30, -25, -25, -25, -25, -30, -40 259 | }; 260 | 261 | int pst_bishop[64] = { 262 | -10, 0, 0, 0, 0, 0, 0, -10, 263 | -10, 5, 0, 0, 0, 0, 5, -10, 264 | -10, 0, 5, 0, 0, 5, 0, -10, 265 | -10, 0, 0, 10, 10, 0, 0, -10, 266 | -10, 0, 5, 10, 10, 5, 0, -10, 267 | -10, 0, 5, 0, 0, 5, 0, -10, 268 | -10, 5, 0, 0, 0, 0, 5, -10, 269 | -10, -20, -20, -20, -20, -20, -20, -10 270 | }; 271 | 272 | int pst_rook[64] = { 273 | 0, 0, 0, 0, 0, 0, 0, 0, 274 | 10, 10, 10, 10, 10, 10, 10, 10, 275 | 0, 0, 0, 0, 0, 0, 0, 0, 276 | 0, 0, 0, 0, 0, 0, 0, 0, 277 | 0, 0, 0, 0, 0, 0, 0, 0, 278 | 0, 0, 0, 0, 0, 0, 0, 0, 279 | 0, 0, 0, 0, 0, 0, 0, 0, 280 | 0, 0, 0, 5, 5, 0, 0, 0 281 | }; 282 | 283 | int pst_king[64] = { 284 | -25, -25, -25, -25, -25, -25, -25, -25, 285 | -25, -25, -25, -25, -25, -25, -25, -25, 286 | -25, -25, -25, -25, -25, -25, -25, -25, 287 | -25, -25, -25, -25, -25, -25, -25, -25, 288 | -25, -25, -25, -25, -25, -25, -25, -25, 289 | -25, -25, -25, -25, -25, -25, -25, -25, 290 | -25, -25, -25, -25, -25, -25, -25, -25, 291 | 10, 15, -15, -15, -15, -15, 15, 10 292 | }; 293 | 294 | /* The flip array is used to calculate the piece/square 295 | values for BLACKS pieces, without needing to write the 296 | arrays for them (idea taken from TSCP). 297 | The piece/square value of a white pawn is pst_pawn[sq] 298 | and the value of a black pawn is pst_pawn[flip[sq]] */ 299 | int flip[64] = { 300 | 56, 57, 58, 59, 60, 61, 62, 63, 301 | 48, 49, 50, 51, 52, 53, 54, 55, 302 | 40, 41, 42, 43, 44, 45, 46, 47, 303 | 32, 33, 34, 35, 36, 37, 38, 39, 304 | 24, 25, 26, 27, 28, 29, 30, 31, 305 | 16, 17, 18, 19, 20, 21, 22, 23, 306 | 8, 9, 10, 11, 12, 13, 14, 15, 307 | 0, 1, 2, 3, 4, 5, 6, 7 308 | }; 309 | 310 | /* 311 | **************************************************************************** 312 | * Move generator * 313 | **************************************************************************** 314 | */ 315 | void 316 | Gen_Push (int from, int dest, int type, MOVE * pBuf, int *pMCount) 317 | { 318 | MOVE move; 319 | move.from = from; 320 | move.dest = dest; 321 | move.type = type; 322 | // move.castle = castle; 323 | pBuf[*pMCount] = move; 324 | *pMCount = *pMCount + 1; 325 | } 326 | 327 | void 328 | Gen_PushNormal (int from, int dest, MOVE * pBuf, int *pMCount) 329 | { 330 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount); 331 | } 332 | 333 | /* Especial cases for Pawn */ 334 | 335 | /* Pawn can promote */ 336 | void 337 | Gen_PushPawn (int from, int dest, MOVE * pBuf, int *pMCount) 338 | { 339 | /* The 7 and 56 are to limit pawns to the 2nd through 7th ranks, which 340 | * means this isn't a promotion, i.e., a normal pawn move */ 341 | if (piece[dest] == EPS_SQUARE) 342 | { 343 | Gen_Push (from, dest, MOVE_TYPE_EPS, pBuf, pMCount); 344 | } 345 | else if (dest > 7 && dest < 56) /* this is just a normal move */ 346 | { 347 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount); 348 | } 349 | else /* otherwise it's a promotion */ 350 | { 351 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount); 352 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount); 353 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount); 354 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount); 355 | } 356 | } 357 | 358 | /* When a pawn moves two squares then appears the possibility of the en passanta capture*/ 359 | void 360 | Gen_PushPawnTwo (int from, int dest, MOVE * pBuf, int *pMCount) 361 | { 362 | Gen_Push (from, dest, MOVE_TYPE_PAWN_TWO, pBuf, pMCount); 363 | } 364 | 365 | /* Especial cases for King */ 366 | void 367 | Gen_PushKing (int from, int dest, MOVE * pBuf, int *pMCount) 368 | { 369 | /* Is it a castle? */ 370 | if (from == E1 && (dest == G1 || dest == C1)) /* this is a white castle */ 371 | { 372 | Gen_Push (from, dest, MOVE_TYPE_CASTLE, pBuf, pMCount); 373 | } 374 | else if (from == E8 && (dest == G8 || dest == C8)) /* this is a black castle */ 375 | { 376 | Gen_Push (from, dest, MOVE_TYPE_CASTLE, pBuf, pMCount); 377 | } 378 | else /* otherwise it's a normal king's move */ 379 | { 380 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount); 381 | } 382 | } 383 | 384 | /* Gen all moves of current_side to move and push them to pBuf, and return number of moves */ 385 | int 386 | GenMoves (int current_side, MOVE * pBuf) 387 | { 388 | int i; /* Counter for the board squares */ 389 | int k; /* Counter for cols */ 390 | int y; 391 | int row; 392 | int col; 393 | int movecount; 394 | movecount = 0; 395 | 396 | for (i = 0; i < 64; i++) /* Scan all board */ 397 | if (color[i] == current_side) 398 | { 399 | switch (piece[i]) 400 | { 401 | 402 | case PAWN: 403 | col = COL (i); 404 | row = ROW (i); 405 | if (current_side == BLACK) 406 | { 407 | if (color[i + 8] == EMPTY) 408 | /* Pawn advances one square. 409 | * We use Gen_PushPawn because it can be a promotion */ 410 | Gen_PushPawn (i, i + 8, pBuf, &movecount); 411 | if (row == 1 && color[i + 8] == EMPTY 412 | && color[i + 16] == EMPTY) 413 | /* Pawn advances two squares */ 414 | Gen_PushPawnTwo (i, i + 16, pBuf, &movecount); 415 | if (col && color[i + 7] == WHITE) 416 | /* Pawn captures and it can be a promotion */ 417 | Gen_PushPawn (i, i + 7, pBuf, &movecount); 418 | if (col < 7 && color[i + 9] == WHITE) 419 | /* Pawn captures and can be a promotion */ 420 | Gen_PushPawn (i, i + 9, pBuf, &movecount); 421 | /* For en passant capture */ 422 | if (col && piece[i + 7] == EPS_SQUARE) 423 | /* Pawn captures and it can be a promotion */ 424 | Gen_PushPawn (i, i + 7, pBuf, &movecount); 425 | if (col < 7 && piece[i + 9] == EPS_SQUARE) 426 | /* Pawn captures and can be a promotion */ 427 | Gen_PushPawn (i, i + 9, pBuf, &movecount); 428 | } 429 | else 430 | { 431 | if (color[i - 8] == EMPTY) 432 | Gen_PushPawn (i, i - 8, pBuf, &movecount); 433 | /* Pawn moves 2 squares */ 434 | if (row == 6 && color[i - 8] == EMPTY 435 | && color[i - 16] == EMPTY) 436 | Gen_PushPawnTwo (i, i - 16, pBuf, &movecount); 437 | /* For captures */ 438 | if (col && color[i - 9] == BLACK) 439 | Gen_PushPawn (i, i - 9, pBuf, &movecount); 440 | if (col < 7 && color[i - 7] == BLACK) 441 | Gen_PushPawn (i, i - 7, pBuf, &movecount); 442 | /* For en passant capture */ 443 | if (col && piece[i - 9] == EPS_SQUARE) 444 | Gen_PushPawn (i, i - 9, pBuf, &movecount); 445 | if (col < 7 && piece[i - 7] == EPS_SQUARE) 446 | Gen_PushPawn (i, i - 7, pBuf, &movecount); 447 | } 448 | break; 449 | 450 | case QUEEN: /* == BISHOP+ROOK */ 451 | 452 | case BISHOP: 453 | for (y = i - 9; y >= 0 && COL (y) != 7; y -= 9) 454 | { /* go left up */ 455 | if (color[y] != current_side) 456 | Gen_PushNormal (i, y, pBuf, &movecount); 457 | if (color[y] != EMPTY) 458 | break; 459 | } 460 | for (y = i - 7; y >= 0 && COL (y) != 0; y -= 7) 461 | { /* go right up */ 462 | if (color[y] != current_side) 463 | Gen_PushNormal (i, y, pBuf, &movecount); 464 | if (color[y] != EMPTY) 465 | break; 466 | } 467 | for (y = i + 9; y < 64 && COL (y) != 0; y += 9) 468 | { /* go right down */ 469 | if (color[y] != current_side) 470 | Gen_PushNormal (i, y, pBuf, &movecount); 471 | if (color[y] != EMPTY) 472 | break; 473 | } 474 | for (y = i + 7; y < 64 && COL (y) != 7; y += 7) 475 | { /* go left down */ 476 | if (color[y] != current_side) 477 | Gen_PushNormal (i, y, pBuf, &movecount); 478 | if (color[y] != EMPTY) 479 | break; 480 | } 481 | if (piece[i] == BISHOP) /* In the case of the bishop we're done */ 482 | break; 483 | 484 | /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */ 485 | case ROOK: 486 | col = COL (i); 487 | for (k = i - col, y = i - 1; y >= k; y--) 488 | { /* go left */ 489 | if (color[y] != current_side) 490 | Gen_PushNormal (i, y, pBuf, &movecount); 491 | if (color[y] != EMPTY) 492 | break; 493 | } 494 | for (k = i - col + 7, y = i + 1; y <= k; y++) 495 | { /* go right */ 496 | if (color[y] != current_side) 497 | Gen_PushNormal (i, y, pBuf, &movecount); 498 | if (color[y] != EMPTY) 499 | break; 500 | } 501 | for (y = i - 8; y >= 0; y -= 8) 502 | { /* go up */ 503 | if (color[y] != current_side) 504 | Gen_PushNormal (i, y, pBuf, &movecount); 505 | if (color[y] != EMPTY) 506 | break; 507 | } 508 | for (y = i + 8; y < 64; y += 8) 509 | { /* go down */ 510 | if (color[y] != current_side) 511 | Gen_PushNormal (i, y, pBuf, &movecount); 512 | if (color[y] != EMPTY) 513 | break; 514 | } 515 | break; 516 | 517 | case KNIGHT: 518 | col = COL (i); 519 | y = i - 6; 520 | if (y >= 0 && col < 6 && color[y] != current_side) 521 | Gen_PushNormal (i, y, pBuf, &movecount); 522 | y = i - 10; 523 | if (y >= 0 && col > 1 && color[y] != current_side) 524 | Gen_PushNormal (i, y, pBuf, &movecount); 525 | y = i - 15; 526 | if (y >= 0 && col < 7 && color[y] != current_side) 527 | Gen_PushNormal (i, y, pBuf, &movecount); 528 | y = i - 17; 529 | if (y >= 0 && col > 0 && color[y] != current_side) 530 | Gen_PushNormal (i, y, pBuf, &movecount); 531 | y = i + 6; 532 | if (y < 64 && col > 1 && color[y] != current_side) 533 | Gen_PushNormal (i, y, pBuf, &movecount); 534 | y = i + 10; 535 | if (y < 64 && col < 6 && color[y] != current_side) 536 | Gen_PushNormal (i, y, pBuf, &movecount); 537 | y = i + 15; 538 | if (y < 64 && col > 0 && color[y] != current_side) 539 | Gen_PushNormal (i, y, pBuf, &movecount); 540 | y = i + 17; 541 | if (y < 64 && col < 7 && color[y] != current_side) 542 | Gen_PushNormal (i, y, pBuf, &movecount); 543 | break; 544 | 545 | case KING: 546 | /* the column and rank checks are to make sure it is on the board */ 547 | /* The 'normal' moves */ 548 | col = COL (i); 549 | if (col && color[i - 1] != current_side) 550 | Gen_PushKing (i, i - 1, pBuf, &movecount); /* left */ 551 | if (col < 7 && color[i + 1] != current_side) 552 | Gen_PushKing (i, i + 1, pBuf, &movecount); /* right */ 553 | if (i > 7 && color[i - 8] != current_side) 554 | Gen_PushKing (i, i - 8, pBuf, &movecount); /* up */ 555 | if (i < 56 && color[i + 8] != current_side) 556 | Gen_PushKing (i, i + 8, pBuf, &movecount); /* down */ 557 | if (col && i > 7 && color[i - 9] != current_side) 558 | Gen_PushKing (i, i - 9, pBuf, &movecount); /* left up */ 559 | if (col < 7 && i > 7 && color[i - 7] != current_side) 560 | Gen_PushKing (i, i - 7, pBuf, &movecount); /* right up */ 561 | if (col && i < 56 && color[i + 7] != current_side) 562 | Gen_PushKing (i, i + 7, pBuf, &movecount); /* left down */ 563 | if (col < 7 && i < 56 && color[i + 9] != current_side) 564 | Gen_PushKing (i, i + 9, pBuf, &movecount); /* right down */ 565 | 566 | /* The castle moves */ 567 | if (current_side == WHITE) 568 | { 569 | /* Can white short castle? */ 570 | if (castle_rights & 1) 571 | { 572 | /* If white can castle the white king has to be in square 60 */ 573 | if (col && 574 | color[i + 1] == EMPTY && 575 | color[i + 2] == EMPTY && 576 | !IsInCheck (current_side) && 577 | !IsAttacked (current_side, i + 1)) 578 | { 579 | /* The king goes 2 sq to the left */ 580 | Gen_PushKing (i, i + 2, pBuf, &movecount); 581 | } 582 | } 583 | 584 | /* Can white long castle? */ 585 | if (castle_rights & 2) 586 | { 587 | if (col && 588 | color[i - 1] == EMPTY && 589 | color[i - 2] == EMPTY && 590 | color[i - 3] == EMPTY && 591 | !IsInCheck (current_side) && 592 | !IsAttacked (current_side, i - 1)) 593 | { 594 | /* The king goes 2 sq to the left */ 595 | Gen_PushKing (i, i - 2, pBuf, &movecount); 596 | } 597 | } 598 | } 599 | else if (current_side == BLACK) 600 | { 601 | /* Can black short castle? */ 602 | if (castle_rights & 4) 603 | { 604 | /* If white can castle the white king has to be in square 60 */ 605 | if (col && 606 | color[i + 1] == EMPTY && 607 | color[i + 2] == EMPTY && 608 | piece[i + 3] == ROOK && 609 | !IsInCheck (current_side) && 610 | !IsAttacked (current_side, i + 1)) 611 | { 612 | /* The king goes 2 sq to the left */ 613 | Gen_PushKing (i, i + 2, pBuf, &movecount); 614 | } 615 | } 616 | /* Can black long castle? */ 617 | if (castle_rights & 8) 618 | { 619 | if (col && 620 | color[i - 1] == EMPTY && 621 | color[i - 2] == EMPTY && 622 | color[i - 3] == EMPTY && 623 | piece[i - 4] == ROOK && 624 | !IsInCheck (current_side) && 625 | !IsAttacked (current_side, i - 1)) 626 | { 627 | /* The king goes 2 sq to the left */ 628 | Gen_PushKing (i, i - 2, pBuf, &movecount); 629 | } 630 | } 631 | } 632 | 633 | break; 634 | // default: 635 | // printf("Piece type unknown, %d", piece[i]); 636 | // assert(false); 637 | } 638 | } 639 | return movecount; 640 | } 641 | 642 | /* Gen all captures of current_side to move and push them to pBuf, return number of moves 643 | * It's necesary at least ir order to use quiescent in the search */ 644 | int 645 | GenCaps (int current_side, MOVE * pBuf) 646 | { 647 | int i; /* Counter for the board squares */ 648 | int k; /* Counter for cols */ 649 | int y; 650 | int row; 651 | int col; 652 | int capscount; /* Counter for the posible captures */ 653 | int xside; 654 | xside = (WHITE + BLACK) - current_side; 655 | capscount = 0; 656 | 657 | for (i = 0; i < 64; i++) /* Scan all board */ 658 | if (color[i] == current_side) 659 | { 660 | switch (piece[i]) 661 | { 662 | 663 | case PAWN: 664 | col = COL (i); 665 | row = ROW (i); 666 | if (current_side == BLACK) 667 | { 668 | /* This isn't a capture, but it's necesary in order to 669 | * not oversee promotions */ 670 | if (row > 7 && color[i + 8] == EMPTY) 671 | /* Pawn advances one square. 672 | * We use Gen_PushPawn because it can be a promotion */ 673 | Gen_PushPawn (i, i + 8, pBuf, &capscount); 674 | if (col && color[i + 7] == WHITE) 675 | /* Pawn captures and it can be a promotion */ 676 | Gen_PushPawn (i, i + 7, pBuf, &capscount); 677 | if (col < 7 && color[i + 9] == WHITE) 678 | /* Pawn captures and can be a promotion */ 679 | Gen_PushPawn (i, i + 9, pBuf, &capscount); 680 | /* For en passant capture */ 681 | if (col && piece[i + 7] == EPS_SQUARE) 682 | /* Pawn captures and it can be a promotion */ 683 | Gen_PushPawn (i, i + 7, pBuf, &capscount); 684 | if (col < 7 && piece[i + 9] == EPS_SQUARE) 685 | /* Pawn captures and can be a promotion */ 686 | Gen_PushPawn (i, i + 9, pBuf, &capscount); 687 | } 688 | else if (current_side == WHITE) 689 | { 690 | if (row < 2 && color[i - 8] == EMPTY) 691 | /* This isn't a capture, but it's necesary in order to 692 | * not oversee promotions */ 693 | Gen_PushPawn (i, i - 8, pBuf, &capscount); 694 | /* For captures */ 695 | if (col && color[i - 9] == BLACK) 696 | Gen_PushPawn (i, i - 9, pBuf, &capscount); 697 | if (col < 7 && color[i - 7] == BLACK) 698 | Gen_PushPawn (i, i - 7, pBuf, &capscount); 699 | /* For en passant capture */ 700 | if (col && piece[i - 9] == EPS_SQUARE) 701 | Gen_PushPawn (i, i - 9, pBuf, &capscount); 702 | if (col < 7 && piece[i - 7] == EPS_SQUARE) 703 | Gen_PushPawn (i, i - 7, pBuf, &capscount); 704 | } 705 | break; 706 | 707 | case KNIGHT: 708 | col = COL (i); 709 | y = i - 6; 710 | if (y >= 0 && col < 6 && color[y] == xside) 711 | Gen_PushNormal (i, y, pBuf, &capscount); 712 | y = i - 10; 713 | if (y >= 0 && col > 1 && color[y] == xside) 714 | Gen_PushNormal (i, y, pBuf, &capscount); 715 | y = i - 15; 716 | if (y >= 0 && col < 7 && color[y] == xside) 717 | Gen_PushNormal (i, y, pBuf, &capscount); 718 | y = i - 17; 719 | if (y >= 0 && col > 0 && color[y] == xside) 720 | Gen_PushNormal (i, y, pBuf, &capscount); 721 | y = i + 6; 722 | if (y < 64 && col > 1 && color[y] == xside) 723 | Gen_PushNormal (i, y, pBuf, &capscount); 724 | y = i + 10; 725 | if (y < 64 && col < 6 && color[y] == xside) 726 | Gen_PushNormal (i, y, pBuf, &capscount); 727 | y = i + 15; 728 | if (y < 64 && col > 0 && color[y] == xside) 729 | Gen_PushNormal (i, y, pBuf, &capscount); 730 | y = i + 17; 731 | if (y < 64 && col < 7 && color[y] == xside) 732 | Gen_PushNormal (i, y, pBuf, &capscount); 733 | break; 734 | 735 | case QUEEN: /* == BISHOP+ROOK */ 736 | 737 | case BISHOP: 738 | for (y = i - 9; y >= 0 && COL (y) != 7; y -= 9) 739 | { /* go left up */ 740 | if (color[y] != EMPTY) 741 | { 742 | if (color[y] != current_side) 743 | Gen_PushNormal (i, y, pBuf, &capscount); 744 | break; 745 | } 746 | } 747 | for (y = i - 7; y >= 0 && COL (y) != 0; y -= 7) 748 | { /* go right up */ 749 | if (color[y] != EMPTY) 750 | { 751 | if (color[y] != current_side) 752 | Gen_PushNormal (i, y, pBuf, &capscount); 753 | break; 754 | } 755 | } 756 | for (y = i + 9; y < 64 && COL (y) != 0; y += 9) 757 | { /* go right down */ 758 | if (color[y] != EMPTY) 759 | { 760 | if (color[y] != current_side) 761 | Gen_PushNormal (i, y, pBuf, &capscount); 762 | break; 763 | } 764 | } 765 | for (y = i + 7; y < 64 && COL (y) != 7; y += 7) 766 | { /* go left down */ 767 | if (color[y] != EMPTY) 768 | { 769 | if (color[y] != current_side) 770 | Gen_PushNormal (i, y, pBuf, &capscount); 771 | break; 772 | } 773 | } 774 | if (piece[i] == BISHOP) /* In the case of the bishop we're done */ 775 | break; 776 | 777 | /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */ 778 | case ROOK: 779 | col = COL (i); 780 | for (k = i - col, y = i - 1; y >= k; y--) 781 | { /* go left */ 782 | if (color[y] != EMPTY) 783 | { 784 | if (color[y] != current_side) 785 | Gen_PushNormal (i, y, pBuf, &capscount); 786 | break; 787 | } 788 | } 789 | for (k = i - col + 7, y = i + 1; y <= k; y++) 790 | { /* go right */ 791 | if (color[y] != EMPTY) 792 | { 793 | if (color[y] != current_side) 794 | Gen_PushNormal (i, y, pBuf, &capscount); 795 | break; 796 | } 797 | } 798 | for (y = i - 8; y >= 0; y -= 8) 799 | { /* go up */ 800 | if (color[y] != EMPTY) 801 | { 802 | if (color[y] != current_side) 803 | Gen_PushNormal (i, y, pBuf, &capscount); 804 | break; 805 | } 806 | } 807 | for (y = i + 8; y < 64; y += 8) 808 | { /* go down */ 809 | if (color[y] != EMPTY) 810 | { 811 | if (color[y] != current_side) 812 | Gen_PushNormal (i, y, pBuf, &capscount); 813 | break; 814 | } 815 | } 816 | break; 817 | 818 | case KING: 819 | ///* the column and rank checks are to make sure it is on the board*/ 820 | col = COL (i); 821 | if (col && color[i - 1] == xside) 822 | Gen_PushKing (i, i - 1, pBuf, &capscount); /* left */ 823 | if (col < 7 && color[i + 1] == xside) 824 | Gen_PushKing (i, i + 1, pBuf, &capscount); /* right */ 825 | if (i > 7 && color[i - 8] == xside) 826 | Gen_PushKing (i, i - 8, pBuf, &capscount); /* up */ 827 | if (i < 56 && color[i + 8] == xside) 828 | Gen_PushKing (i, i + 8, pBuf, &capscount); /* down */ 829 | if (col && i > 7 && color[i - 9] == xside) 830 | Gen_PushKing (i, i - 9, pBuf, &capscount); /* left up */ 831 | if (col < 7 && i > 7 && color[i - 7] == xside) 832 | Gen_PushKing (i, i - 7, pBuf, &capscount); /* right up */ 833 | if (col && i < 56 && color[i + 7] == xside) 834 | Gen_PushKing (i, i + 7, pBuf, &capscount); /* left down */ 835 | if (col < 7 && i < 56 && color[i + 9] == xside) 836 | Gen_PushKing (i, i + 9, pBuf, &capscount); /* right down */ 837 | break; 838 | // default: 839 | // printf("Piece type unknown"); 840 | // assert(false); 841 | } 842 | } 843 | return capscount; 844 | } 845 | 846 | /* 847 | **************************************************************************** 848 | * Evaluation for current position - main "brain" function * 849 | * Lack: almost no knowlegde; material value + piece square tables * 850 | **************************************************************************** 851 | */ 852 | int 853 | Eval () 854 | { 855 | 856 | count_evaluations++; 857 | 858 | /* A counter for the board squares */ 859 | int i; 860 | 861 | /* The score of the position */ 862 | int score = 0; 863 | 864 | /* Check all the squares searching for the pieces */ 865 | for (i = 0; i < 64; i++) 866 | { 867 | if (color[i] == WHITE) 868 | { 869 | /* In the current square, add the material 870 | * value of the piece */ 871 | score += value_piece[piece[i]]; 872 | 873 | /* Now we add to the evaluation the value of the 874 | * piece square tables */ 875 | switch (piece[i]) 876 | { 877 | case PAWN: 878 | score += pst_pawn[i]; 879 | break; 880 | case KNIGHT: 881 | score += pst_knight[i]; 882 | break; 883 | case BISHOP: 884 | score += pst_bishop[i]; 885 | break; 886 | case ROOK: 887 | score += pst_rook[i]; 888 | break; 889 | case KING: 890 | score += pst_king[i]; 891 | break; 892 | } 893 | } 894 | /* Now the evaluation for black: note the change of 895 | the sign in the score */ 896 | else if (color[i] == BLACK) 897 | { 898 | score -= value_piece[piece[i]]; 899 | 900 | switch (piece[i]) 901 | { 902 | case PAWN: 903 | score -= pst_pawn[flip[i]]; 904 | break; 905 | case KNIGHT: 906 | score -= pst_knight[flip[i]]; 907 | break; 908 | case BISHOP: 909 | score -= pst_bishop[flip[i]]; 910 | break; 911 | case ROOK: 912 | score -= pst_rook[flip[i]]; 913 | break; 914 | case KING: 915 | score -= pst_king[flip[i]]; 916 | break; 917 | } 918 | } 919 | } 920 | 921 | /* Finally we return the score, taking into account the side to move */ 922 | if (side == WHITE) 923 | return score; 924 | return -score; 925 | } 926 | 927 | /* 928 | **************************************************************************** 929 | * Make and Take back a move, IsInCheck * 930 | **************************************************************************** 931 | */ 932 | 933 | /* Check if current side is in check. Necesary in order to check legality of moves 934 | and check if castle is allowed */ 935 | int 936 | IsInCheck (int current_side) 937 | { 938 | int k; /* The square where the king is placed */ 939 | 940 | /* Find the King of the side to move */ 941 | for (k = 0; k < 64; k++) 942 | if ((piece[k] == KING) && color[k] == current_side) 943 | break; 944 | 945 | /* Use IsAttacked in order to know if current_side is under check */ 946 | return IsAttacked (current_side, k); 947 | } 948 | 949 | /* Returns 1 if square k is attacked by current_side, 0 otherwise. Necesary, v.g., to check 950 | * castle rules (if king goes from e1 to g1, f1 can't be attacked by an enemy piece) */ 951 | int 952 | IsAttacked (int current_side, int k) 953 | { 954 | int h; 955 | int y; 956 | int row; /* Row where the square k is placed */ 957 | int col; /* Col where the square k is placed */ 958 | int xside; 959 | xside = (WHITE + BLACK) - current_side; /* opposite current_side, who may be attacking */ 960 | 961 | /* Situation of the square */ 962 | row = ROW (k); 963 | col = COL (k); 964 | 965 | /* Check Knight attack */ 966 | if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT) 967 | return 1; 968 | if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT) 969 | return 1; 970 | if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT) 971 | return 1; 972 | if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT) 973 | return 1; 974 | if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT) 975 | return 1; 976 | if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT) 977 | return 1; 978 | if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT) 979 | return 1; 980 | if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT) 981 | return 1; 982 | 983 | /* Check horizontal and vertical lines for attacking of Queen, Rook, King */ 984 | /* go down */ 985 | y = k + 8; 986 | if (y < 64) 987 | { 988 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN 989 | || piece[y] == ROOK)) 990 | return 1; 991 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 992 | for (y += 8; y < 64; y += 8) 993 | { 994 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) 995 | return 1; 996 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 997 | break; 998 | } 999 | } 1000 | /* go left */ 1001 | y = k - 1; 1002 | h = k - col; 1003 | if (y >= h) 1004 | { 1005 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN 1006 | || piece[y] == ROOK)) 1007 | return 1; 1008 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1009 | for (y--; y >= h; y--) 1010 | { 1011 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) 1012 | return 1; 1013 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1014 | break; 1015 | } 1016 | } 1017 | /* go right */ 1018 | y = k + 1; 1019 | h = k - col + 7; 1020 | if (y <= h) 1021 | { 1022 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN 1023 | || piece[y] == ROOK)) 1024 | return 1; 1025 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1026 | for (y++; y <= h; y++) 1027 | { 1028 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) 1029 | return 1; 1030 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1031 | break; 1032 | } 1033 | } 1034 | /* go up */ 1035 | y = k - 8; 1036 | if (y >= 0) 1037 | { 1038 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN 1039 | || piece[y] == ROOK)) 1040 | return 1; 1041 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1042 | for (y -= 8; y >= 0; y -= 8) 1043 | { 1044 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) 1045 | return 1; 1046 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1047 | break; 1048 | } 1049 | } 1050 | /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */ 1051 | /* go right down */ 1052 | y = k + 9; 1053 | if (y < 64 && COL (y) != 0) 1054 | { 1055 | if (color[y] == xside) 1056 | { 1057 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) 1058 | return 1; 1059 | if (current_side == BLACK && piece[y] == PAWN) 1060 | return 1; 1061 | } 1062 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1063 | for (y += 9; y < 64 && COL (y) != 0; y += 9) 1064 | { 1065 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] 1066 | == BISHOP)) 1067 | return 1; 1068 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1069 | break; 1070 | } 1071 | } 1072 | /* go left down */ 1073 | y = k + 7; 1074 | if (y < 64 && COL (y) != 7) 1075 | { 1076 | if (color[y] == xside) 1077 | { 1078 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) 1079 | return 1; 1080 | if (current_side == BLACK && piece[y] == PAWN) 1081 | return 1; 1082 | } 1083 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1084 | for (y += 7; y < 64 && COL (y) != 7; y += 7) 1085 | { 1086 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] 1087 | == BISHOP)) 1088 | return 1; 1089 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1090 | break; 1091 | 1092 | } 1093 | } 1094 | /* go left up */ 1095 | y = k - 9; 1096 | if (y >= 0 && COL (y) != 7) 1097 | { 1098 | if (color[y] == xside) 1099 | { 1100 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) 1101 | return 1; 1102 | if (current_side == WHITE && piece[y] == PAWN) 1103 | return 1; 1104 | } 1105 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1106 | for (y -= 9; y >= 0 && COL (y) != 7; y -= 9) 1107 | { 1108 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] 1109 | == BISHOP)) 1110 | return 1; 1111 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1112 | break; 1113 | 1114 | } 1115 | } 1116 | /* go right up */ 1117 | y = k - 7; 1118 | if (y >= 0 && COL (y) != 0) 1119 | { 1120 | if (color[y] == xside) 1121 | { 1122 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) 1123 | return 1; 1124 | if (current_side == WHITE && piece[y] == PAWN) 1125 | return 1; 1126 | } 1127 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE) 1128 | for (y -= 7; y >= 0 && COL (y) != 0; y -= 7) 1129 | { 1130 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] 1131 | == BISHOP)) 1132 | return 1; 1133 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE) 1134 | break; 1135 | } 1136 | } 1137 | return 0; 1138 | } 1139 | 1140 | int 1141 | MakeMove (MOVE m) 1142 | { 1143 | int r; 1144 | int i; 1145 | 1146 | count_MakeMove++; 1147 | 1148 | hist[hdp].m = m; 1149 | hist[hdp].cap = piece[m.dest]; /* store in history the piece of the dest square */ 1150 | hist[hdp].castle = castle_rights; 1151 | 1152 | piece[m.dest] = piece[m.from]; /* dest piece is the one in the original square */ 1153 | color[m.dest] = color[m.from]; /* The dest square color is the one of the origin piece */ 1154 | piece[m.from] = EMPTY; /* The original square becomes empty */ 1155 | color[m.from] = EMPTY; /* The original color becomes empty */ 1156 | 1157 | /* en pasant capture */ 1158 | if (m.type == MOVE_TYPE_EPS) 1159 | { 1160 | if (side == WHITE) 1161 | { 1162 | piece[m.dest + 8] = EMPTY; 1163 | color[m.dest + 8] = EMPTY; 1164 | } 1165 | else 1166 | { 1167 | piece[m.dest - 8] = EMPTY; 1168 | color[m.dest - 8] = EMPTY; 1169 | } 1170 | } 1171 | 1172 | /* Remove possible eps piece, remaining from former move */ 1173 | if (hist[hdp - 1].m.type == MOVE_TYPE_PAWN_TWO) 1174 | { 1175 | for (i = 16; i <= 23; i++) 1176 | { 1177 | if (piece[i] == EPS_SQUARE) 1178 | { 1179 | piece[i] = EMPTY; 1180 | /* this seems unnecesary, but otherwise a bug occurs: 1181 | * after: a3 Nc6 d4 e6, white isn't allowed to play e4 */ 1182 | // color[i] = EMPTY; 1183 | break; 1184 | } 1185 | } 1186 | for (i = 40; i <= 47; i++) 1187 | { 1188 | if (piece[i] == EPS_SQUARE) 1189 | { 1190 | piece[i] = EMPTY; 1191 | // color[i] = EMPTY; 1192 | break; 1193 | } 1194 | } 1195 | } 1196 | 1197 | /* Add the eps square when a pawn moves two squares */ 1198 | if (m.type == MOVE_TYPE_PAWN_TWO) 1199 | { 1200 | if (side == BLACK) 1201 | { 1202 | piece[m.from + 8] = EPS_SQUARE; 1203 | color[m.from + 8] = EMPTY; 1204 | } 1205 | else if (side == WHITE) 1206 | { 1207 | piece[m.from - 8] = EPS_SQUARE; 1208 | color[m.from - 8] = EMPTY; 1209 | } 1210 | } 1211 | 1212 | /* Once the move is done we check either this is a promotion */ 1213 | if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) 1214 | { 1215 | /* In this case we put in the destiny sq the chosen piece */ 1216 | switch (m.type) 1217 | { 1218 | case MOVE_TYPE_PROMOTION_TO_QUEEN: 1219 | piece[m.dest] = QUEEN; 1220 | break; 1221 | 1222 | case MOVE_TYPE_PROMOTION_TO_ROOK: 1223 | piece[m.dest] = ROOK; 1224 | break; 1225 | 1226 | case MOVE_TYPE_PROMOTION_TO_BISHOP: 1227 | piece[m.dest] = BISHOP; 1228 | break; 1229 | 1230 | case MOVE_TYPE_PROMOTION_TO_KNIGHT: 1231 | piece[m.dest] = KNIGHT; 1232 | break; 1233 | 1234 | default: 1235 | puts ("Impossible to get here..."); 1236 | assert (false); 1237 | } 1238 | } 1239 | 1240 | if (m.type == MOVE_TYPE_CASTLE) 1241 | { 1242 | if (m.dest == G1) 1243 | { 1244 | /* h1-h8 becomes empty */ 1245 | piece[m.from + 3] = EMPTY; 1246 | color[m.from + 3] = EMPTY; 1247 | /* rook to f1-f8 */ 1248 | piece[m.from + 1] = ROOK; 1249 | color[m.from + 1] = WHITE; 1250 | } 1251 | else if (m.dest == C1) 1252 | { 1253 | /* h1-h8 becomes empty */ 1254 | piece[m.from - 4] = EMPTY; 1255 | color[m.from - 4] = EMPTY; 1256 | /* rook to f1-f8 */ 1257 | piece[m.from - 1] = ROOK; 1258 | color[m.from - 1] = WHITE; 1259 | } 1260 | else if (m.dest == G8) 1261 | { 1262 | /* h1-h8 becomes empty */ 1263 | piece[m.from + 3] = EMPTY; 1264 | color[m.from + 3] = EMPTY; 1265 | /* rook to f1-f8 */ 1266 | piece[m.from + 1] = ROOK; 1267 | color[m.from + 1] = BLACK; 1268 | } 1269 | else if (m.dest == C8) 1270 | { 1271 | /* h1-h8 becomes empty */ 1272 | piece[m.from - 4] = EMPTY; 1273 | color[m.from - 4] = EMPTY; 1274 | /* rook to f1-f8 */ 1275 | piece[m.from - 1] = ROOK; 1276 | color[m.from - 1] = BLACK; 1277 | } 1278 | } 1279 | 1280 | /* Update ply and hdp */ 1281 | ply++; 1282 | hdp++; 1283 | 1284 | /* Update the castle rights */ 1285 | castle_rights &= castle_mask[m.from] & castle_mask[m.dest]; 1286 | 1287 | /* Checking if after making the move we're in check */ 1288 | r = !IsInCheck (side); 1289 | 1290 | /* After making move, give turn to opponent */ 1291 | side = (WHITE + BLACK) - side; 1292 | 1293 | return r; 1294 | } 1295 | 1296 | /* Undo what MakeMove did */ 1297 | void 1298 | TakeBack () 1299 | { 1300 | 1301 | int i; 1302 | 1303 | side = (WHITE + BLACK) - side; 1304 | hdp--; 1305 | ply--; 1306 | piece[hist[hdp].m.from] = piece[hist[hdp].m.dest]; 1307 | piece[hist[hdp].m.dest] = hist[hdp].cap; 1308 | color[hist[hdp].m.from] = side; 1309 | 1310 | /* Update castle rights */ 1311 | castle_rights = hist[hdp].castle; 1312 | 1313 | /* Return the captured material */ 1314 | if (hist[hdp].cap != EMPTY && hist[hdp].cap != EPS_SQUARE) 1315 | { 1316 | color[hist[hdp].m.dest] = (WHITE + BLACK) - side; 1317 | } 1318 | else 1319 | { 1320 | color[hist[hdp].m.dest] = EMPTY; 1321 | } 1322 | 1323 | /* Promotion */ 1324 | if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) 1325 | { 1326 | piece[hist[hdp].m.from] = PAWN; 1327 | } 1328 | 1329 | /* If pawn moved two squares in the former move, we have to restore 1330 | * the eps square */ 1331 | if (hist[hdp - 1].m.type == MOVE_TYPE_PAWN_TWO) 1332 | { 1333 | if (side == WHITE) 1334 | { 1335 | piece[hist[hdp - 1].m.dest - 8] = EPS_SQUARE; 1336 | // color[hist[hdp-1].m.dest - 8] = EMPTY; 1337 | } 1338 | else if (side == BLACK) 1339 | { 1340 | piece[hist[hdp - 1].m.dest + 8] = EPS_SQUARE; 1341 | // color[hist[hdp-1].m.dest + 8] = EMPTY; 1342 | } 1343 | } 1344 | 1345 | /* To remove the eps square after unmaking a pawn 1346 | * moving two squares*/ 1347 | if (hist[hdp].m.type == MOVE_TYPE_PAWN_TWO) 1348 | { 1349 | if (side == WHITE) 1350 | { 1351 | piece[hist[hdp].m.from - 8] = EMPTY; 1352 | color[hist[hdp].m.from - 8] = EMPTY; 1353 | } 1354 | else 1355 | { 1356 | piece[hist[hdp].m.from + 8] = EMPTY; 1357 | color[hist[hdp].m.from + 8] = EMPTY; 1358 | } 1359 | } 1360 | 1361 | /* Unmaking an en pasant capture */ 1362 | if (hist[hdp].m.type == MOVE_TYPE_EPS) 1363 | { 1364 | if (side == WHITE) 1365 | { 1366 | /* The pawn */ 1367 | piece[hist[hdp].m.dest + 8] = PAWN; 1368 | color[hist[hdp].m.dest + 8] = BLACK; 1369 | /* The eps square */ 1370 | piece[hist[hdp].m.dest] = EPS_SQUARE; 1371 | // color[hist[hdp].m.dest] = EMPTY; 1372 | } 1373 | else 1374 | { 1375 | /* The pawn */ 1376 | piece[hist[hdp].m.dest - 8] = PAWN; 1377 | color[hist[hdp].m.dest - 8] = WHITE; 1378 | /* The eps square */ 1379 | piece[hist[hdp].m.dest] = EPS_SQUARE; 1380 | // color[hist[hdp].m.dest] = EMPTY; 1381 | } 1382 | } 1383 | 1384 | /* Undo Castle: return rook to its original square */ 1385 | if (hist[hdp].m.type == MOVE_TYPE_CASTLE) 1386 | { 1387 | /* Take the tower to its poriginal place */ 1388 | if (hist[hdp].m.dest == G1 && side == WHITE) 1389 | { 1390 | piece[H1] = ROOK; 1391 | color[H1] = WHITE; 1392 | piece[F1] = EMPTY; 1393 | color[F1] = EMPTY; 1394 | } 1395 | else if (hist[hdp].m.dest == C1 && side == WHITE) 1396 | { 1397 | piece[A1] = ROOK; 1398 | color[A1] = WHITE; 1399 | piece[D1] = EMPTY; 1400 | color[D1] = EMPTY; 1401 | } 1402 | else if (hist[hdp].m.dest == G8 && side == BLACK) 1403 | { 1404 | piece[H8] = ROOK; 1405 | color[H8] = BLACK; 1406 | piece[F8] = EMPTY; 1407 | color[F8] = EMPTY; 1408 | } 1409 | else if (hist[hdp].m.dest == C8 && side == BLACK) 1410 | { 1411 | piece[A8] = ROOK; 1412 | color[A8] = BLACK; 1413 | piece[D8] = EMPTY; 1414 | color[D8] = EMPTY; 1415 | } 1416 | } 1417 | } 1418 | 1419 | /* 1420 | **************************************************************************** 1421 | * Search function - a typical alphabeta, main search function * 1422 | * Lack: no move ordering * 1423 | **************************************************************************** 1424 | */ 1425 | 1426 | int 1427 | Search (int alpha, int beta, int depth, MOVE * pBestMove) 1428 | { 1429 | int i; 1430 | int value; /* To store the evaluation */ 1431 | int havemove; /* Either we have or not a legal move available */ 1432 | int movecnt; /* The number of available moves */ 1433 | 1434 | MOVE moveBuf[200]; /* List of movements */ 1435 | MOVE tmpMove; 1436 | 1437 | // nodes++; /* visiting a node, count it */ 1438 | havemove = 0; /* is there a move available? */ 1439 | pBestMove->type = MOVE_TYPE_NONE; 1440 | 1441 | /* Generate and count all moves for current position */ 1442 | movecnt = GenMoves (side, moveBuf); 1443 | assert (movecnt < 201); 1444 | 1445 | /* Once we have all the moves available, we loop through the posible 1446 | * moves and apply an alpha-beta search */ 1447 | for (i = 0; i < movecnt; ++i) 1448 | { 1449 | 1450 | if (!MakeMove (moveBuf[i])) 1451 | { 1452 | /* If the current move isn't legal, we take it back 1453 | * and take the next move in the list */ 1454 | TakeBack (); 1455 | continue; 1456 | } 1457 | 1458 | /* If we've reached this far, then we have a move available */ 1459 | havemove = 1; 1460 | 1461 | /* This 'if' takes us to the deep of the position, the leaf nodes */ 1462 | if (depth - 1 > 0) 1463 | { 1464 | value = -Search (-beta, -alpha, depth - 1, &tmpMove); 1465 | } 1466 | /* If no depth left (leaf node), we evalute the position 1467 | and apply the alpha-beta search. 1468 | In the case of existing a quiescent function, it should be 1469 | called here instead of Eval() */ 1470 | else 1471 | { 1472 | value = -Quiescent (-beta, -alpha); 1473 | // value = -Eval(); 1474 | } 1475 | 1476 | /* We've evaluated the position, so we return to the previous position in such a way 1477 | that when we take the next move from moveBuf everything is in order */ 1478 | TakeBack (); 1479 | 1480 | /* Once we have an evaluation, we use it in in an alpha-beta search */ 1481 | if (value > alpha) 1482 | { 1483 | /* This move is so good and caused a cutoff */ 1484 | if (value >= beta) 1485 | { 1486 | return beta; 1487 | } 1488 | alpha = value; 1489 | /* So far, current move is the best reaction for current position */ 1490 | *pBestMove = moveBuf[i]; 1491 | } 1492 | } 1493 | 1494 | /* Once we've checked all the moves, if we have no legal moves, 1495 | * then that's checkmate or stalemate */ 1496 | if (!havemove) 1497 | { 1498 | if (IsInCheck (side)) 1499 | return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */ 1500 | else 1501 | return 0; 1502 | } 1503 | 1504 | /* Finally we return alpha, the score value */ 1505 | return alpha; 1506 | } 1507 | 1508 | int 1509 | Quiescent (int alpha, int beta) 1510 | { 1511 | int i; 1512 | int capscnt; 1513 | int stand_pat; 1514 | int score; 1515 | MOVE cBuf[200]; 1516 | 1517 | count_quies_calls++; 1518 | 1519 | /* First we just try the evaluation function */ 1520 | stand_pat = Eval (); 1521 | if (stand_pat >= beta) 1522 | return beta; 1523 | if (alpha < stand_pat) 1524 | alpha = stand_pat; 1525 | 1526 | /* If we haven't got a cut off we generate the captures and 1527 | * store them in cBuf */ 1528 | capscnt = GenCaps (side, cBuf); 1529 | 1530 | count_cap_calls++; 1531 | 1532 | for (i = 0; i < capscnt; ++i) 1533 | { 1534 | if (!MakeMove (cBuf[i])) 1535 | { 1536 | /* If the current move isn't legal, we take it back 1537 | * and take the next move in the list */ 1538 | TakeBack (); 1539 | continue; 1540 | } 1541 | score = -Quiescent (-beta, -alpha); 1542 | TakeBack (); 1543 | if (score >= beta) 1544 | return beta; 1545 | if (score > alpha) 1546 | alpha = score; 1547 | } 1548 | return alpha; 1549 | } 1550 | 1551 | 1552 | 1553 | MOVE 1554 | ComputerThink (int depth) 1555 | { 1556 | /* It returns the move the computer makes */ 1557 | MOVE m; 1558 | int score; 1559 | double knps; 1560 | 1561 | /* Reset some values before searching */ 1562 | ply = 0; 1563 | nodes = 0; 1564 | count_evaluations = 0; 1565 | count_MakeMove = 0; 1566 | count_quies_calls = 0; 1567 | count_cap_calls = 0; 1568 | 1569 | clock_t start; 1570 | clock_t stop; 1571 | double t = 0.0; 1572 | 1573 | /* Start timer */ 1574 | start = clock (); 1575 | assert (start != -1); 1576 | 1577 | /* Search now */ 1578 | score = Search (-MATE, MATE, depth, &m); 1579 | 1580 | /* Stop timer */ 1581 | stop = clock (); 1582 | t = (double) (stop - start) / CLOCKS_PER_SEC; 1583 | knps = ((double) count_quies_calls / t) / 1000.; 1584 | 1585 | double ratio_Qsearc_Capcalls = 1586 | (double) count_quies_calls / (double) count_cap_calls; 1587 | 1588 | double decimal_score = ((double) score) / 100.; 1589 | if (side == BLACK) 1590 | { 1591 | decimal_score = -decimal_score; 1592 | } 1593 | 1594 | /* After searching, print results */ 1595 | printf 1596 | ("Search result: move = %c%d%c%d; depth = %d, score = %.2f, time = %.2fs knps = %.2f\n countCapCalls = %d\n countQSearch = %d\n moves made = %d\n ratio_Qsearc_Capcalls = %.2f\n", 1597 | 'a' + COL (m.from), 8 - ROW (m.from), 'a' + COL (m.dest), 1598 | 8 - ROW (m.dest), depth, decimal_score, t, knps, count_cap_calls, 1599 | count_quies_calls, count_MakeMove, ratio_Qsearc_Capcalls); 1600 | return m; 1601 | } 1602 | 1603 | /* 1604 | **************************************************************************** 1605 | * Utilities * 1606 | **************************************************************************** 1607 | */ 1608 | 1609 | void 1610 | PrintBoard () 1611 | { 1612 | char pieceName[] = "PNBRQKpnbrqk"; 1613 | int i; 1614 | for (i = 0; i < 64; i++) 1615 | { 1616 | if ((i & 7) == 0) 1617 | { 1618 | printf (" +---+---+---+---+---+---+---+---+\n"); 1619 | if (i <= 56) 1620 | { 1621 | printf (" %d |", 8 - (((unsigned) i) >> 3)); 1622 | } 1623 | } 1624 | 1625 | if (piece[i] == EMPTY && ((((unsigned) i) >> 3) % 2 == 0 && i % 2 == 0)) 1626 | printf (" |"); 1627 | else if (piece[i] == EMPTY 1628 | && ((((unsigned) i) >> 3) % 2 != 0 && i % 2 != 0)) 1629 | printf (" |"); 1630 | else if (piece[i] == EMPTY) 1631 | printf (" |"); 1632 | else if (piece[i] == EPS_SQUARE) 1633 | printf (" * |"); 1634 | else 1635 | { 1636 | if (color[i] == WHITE) 1637 | printf (" %c |", pieceName[piece[i]]); 1638 | else 1639 | printf ("<%c>|", pieceName[piece[i] + 6]); 1640 | } 1641 | if ((i & 7) == 7) 1642 | printf ("\n"); 1643 | } 1644 | printf 1645 | (" +---+---+---+---+---+---+---+---+\n a b c d e f g h\n"); 1646 | } 1647 | 1648 | 1649 | /* Returns the number of posible positions to a given depth. Based on the 1650 | perft function on Danasah */ 1651 | unsigned long long 1652 | perft (int depth) 1653 | { 1654 | int i; 1655 | int movecnt; /* The number of available moves */ 1656 | unsigned long long nodes = 0; 1657 | 1658 | if (!depth) 1659 | return 1; 1660 | 1661 | MOVE moveBuf[200]; /* List of movements */ 1662 | 1663 | /* Generate and count all moves for current position */ 1664 | movecnt = GenMoves (side, moveBuf); 1665 | 1666 | /* Once we have all the moves available, we loop through them */ 1667 | for (i = 0; i < movecnt; ++i) 1668 | { 1669 | /* Not a legal move? Then we unmake it and continue to the next one in the list */ 1670 | if (!MakeMove (moveBuf[i])) 1671 | { 1672 | TakeBack (); 1673 | continue; 1674 | } 1675 | 1676 | /* Just in case we want to count for checks */ 1677 | // if (IsInCheck(side)) 1678 | // { 1679 | // count_checks++; 1680 | // } 1681 | 1682 | /* This 'if' takes us to the deep of the position */ 1683 | nodes += perft (depth - 1); 1684 | TakeBack (); 1685 | } 1686 | 1687 | return nodes; 1688 | } 1689 | 1690 | 1691 | /* 1692 | **************************************************************************** 1693 | * Main program * 1694 | **************************************************************************** 1695 | */ 1696 | 1697 | void 1698 | startgame () 1699 | { 1700 | int i; 1701 | for (i = 0; i < 64; ++i) 1702 | { 1703 | piece[i] = init_piece[i]; 1704 | color[i] = init_color[i]; 1705 | } 1706 | 1707 | side = WHITE; 1708 | computer_side = BLACK; /* Human is white side */ 1709 | hdp = 0; 1710 | castle_rights = 15; 1711 | } 1712 | 1713 | void 1714 | xboard () 1715 | { 1716 | char line[256], command[256], c; 1717 | int from, dest, i; 1718 | MOVE moveBuf[200], bestMove; 1719 | int movecnt; 1720 | //int illegal_king = 0; 1721 | 1722 | printf ("\n"); 1723 | 1724 | startgame (); 1725 | 1726 | for (;;) 1727 | { 1728 | fflush (stdout); 1729 | if (side == computer_side) 1730 | { /* computer's turn */ 1731 | /* Find out the best move to react the current position */ 1732 | bestMove = ComputerThink (max_depth); 1733 | MakeMove (bestMove); 1734 | /* send move */ 1735 | switch (bestMove.type) 1736 | { 1737 | case MOVE_TYPE_PROMOTION_TO_QUEEN: 1738 | c = 'q'; 1739 | break; 1740 | case MOVE_TYPE_PROMOTION_TO_ROOK: 1741 | c = 'r'; 1742 | break; 1743 | case MOVE_TYPE_PROMOTION_TO_BISHOP: 1744 | c = 'b'; 1745 | break; 1746 | case MOVE_TYPE_PROMOTION_TO_KNIGHT: 1747 | c = 'n'; 1748 | break; 1749 | default: 1750 | c = ' '; 1751 | } 1752 | printf ("move %c%d%c%d%c\n", 'a' + COL (bestMove.from), 8 1753 | - ROW (bestMove.from), 'a' + COL (bestMove.dest), 8 1754 | - ROW (bestMove.dest), c); 1755 | continue; 1756 | } 1757 | 1758 | if (!fgets (line, 256, stdin)) 1759 | return; 1760 | if (line[0] == '\n') 1761 | continue; 1762 | sscanf (line, "%s", command); 1763 | if (!strcmp (command, "xboard")) 1764 | { 1765 | continue; 1766 | } 1767 | if (!strcmp (command, "new")) 1768 | { 1769 | startgame (); 1770 | continue; 1771 | } 1772 | if (!strcmp (command, "quit")) 1773 | { 1774 | return; 1775 | } 1776 | if (!strcmp (command, "force")) 1777 | { 1778 | computer_side = EMPTY; 1779 | continue; 1780 | } 1781 | if (!strcmp (command, "white")) 1782 | { 1783 | side = WHITE; 1784 | computer_side = BLACK; 1785 | continue; 1786 | } 1787 | if (!strcmp (command, "black")) 1788 | { 1789 | side = BLACK; 1790 | computer_side = WHITE; 1791 | continue; 1792 | } 1793 | if (!strcmp (command, "sd")) 1794 | { 1795 | sscanf (line, "sd %d", &max_depth); 1796 | continue; 1797 | } 1798 | if (!strcmp (command, "go")) 1799 | { 1800 | computer_side = side; 1801 | continue; 1802 | } 1803 | if (!strcmp (command, "undo")) 1804 | { 1805 | if (hdp == 0) 1806 | continue; 1807 | TakeBack (); 1808 | continue; 1809 | } 1810 | if (!strcmp (command, "remove")) 1811 | { 1812 | if (hdp <= 1) 1813 | continue; 1814 | TakeBack (); 1815 | TakeBack (); 1816 | continue; 1817 | } 1818 | 1819 | /* maybe the user entered a move? */ 1820 | 1821 | /* is a move? */ 1822 | if (command[0] < 'a' || command[0] > 'h' || 1823 | command[1] < '0' || command[1] > '9' || 1824 | command[2] < 'a' || command[2] > 'h' || 1825 | command[3] < '0' || command[3] > '9') 1826 | { 1827 | printf("Error (unknown command): %s\n", command); /*no move, unknown command */ 1828 | continue; 1829 | } 1830 | 1831 | from = command[0] - 'a'; 1832 | from += 8 * (8 - (command[1] - '0')); 1833 | dest = command[2] - 'a'; 1834 | dest += 8 * (8 - (command[3] - '0')); 1835 | ply = 0; 1836 | movecnt = GenMoves (side, moveBuf); 1837 | 1838 | /* loop through the moves to see if it's legal */ 1839 | for (i = 0; i < movecnt; ++i) { 1840 | if (moveBuf[i].from == from && moveBuf[i].dest == dest) 1841 | { 1842 | if (piece[from] == PAWN && (dest < 8 || dest > 55)) 1843 | { 1844 | if (command[4] != 'q' && command[4] != 'r' && command[4] != 'b' && command[4] != 'n') 1845 | { 1846 | printf ("Illegal move. Bad letter for promo\n"); 1847 | goto goon; 1848 | } 1849 | switch (command[4]) 1850 | { 1851 | case 'q': 1852 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN; 1853 | break; 1854 | case 'r': 1855 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK; 1856 | break; 1857 | case 'b': 1858 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP; 1859 | break; 1860 | case 'n': 1861 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT; 1862 | break; 1863 | } 1864 | } 1865 | 1866 | if (MakeMove (moveBuf[i])) 1867 | { 1868 | goto goon; /* legal move */ 1869 | } 1870 | else { 1871 | printf ("Illegal move. King is in check\n"); 1872 | goto goon; 1873 | } 1874 | } 1875 | } 1876 | printf ("Illegal move.\n"); /* illegal move */ 1877 | 1878 | goon: 1879 | continue; 1880 | } 1881 | } 1882 | 1883 | int 1884 | main () 1885 | { 1886 | 1887 | setlocale (LC_ALL, ""); 1888 | 1889 | /* It mainly calls ComputerThink(maxdepth) to the desired ply */ 1890 | 1891 | char s[256]; 1892 | int from; 1893 | int dest; 1894 | int i; 1895 | //int computer_side; 1896 | 1897 | startgame (); 1898 | 1899 | max_depth = 4; /* max depth to search */ 1900 | MOVE moveBuf[200]; 1901 | int movecnt; 1902 | 1903 | puts ("Second Chess, by Emilio Diaz"); 1904 | puts (" Help"); 1905 | puts (" d: display board"); 1906 | puts (" MOVE: make a move (e.g. b1c3, a7a8q, e1g1)"); 1907 | puts (" on: force computer to move"); 1908 | puts (" quit: exit"); 1909 | puts (" sd n: set engine depth to n plies (default 4)"); 1910 | puts (" undo: take back last move"); 1911 | 1912 | side = WHITE; 1913 | computer_side = BLACK; /* Human is white side */ 1914 | 1915 | hdp = 0; /* Current move order */ 1916 | for (;;) 1917 | { 1918 | if (side == computer_side) 1919 | { /* Computer's turn */ 1920 | /* Find out the best move to react the current position */ 1921 | MOVE bestMove = ComputerThink (max_depth); 1922 | MakeMove (bestMove); 1923 | PrintBoard (); 1924 | printf ("CASTLE: %d\n", castle_rights); 1925 | continue; 1926 | } 1927 | 1928 | /* Get user input */ 1929 | printf ("sc> "); 1930 | if (scanf ("%s", s) == EOF) /* close program */ 1931 | return 0; 1932 | if (!strcmp (s, "d")) 1933 | { 1934 | PrintBoard (); 1935 | continue; 1936 | } 1937 | if (!strcmp (s, "undo")) 1938 | { 1939 | TakeBack (); 1940 | PrintBoard (); 1941 | computer_side = (WHITE + BLACK) - computer_side; 1942 | continue; 1943 | } 1944 | if (!strcmp (s, "xboard")) 1945 | { 1946 | xboard (); 1947 | return 0; 1948 | } 1949 | if (!strcmp (s, "on")) 1950 | { 1951 | computer_side = side; 1952 | continue; 1953 | } 1954 | if (!strcmp (s, "pass")) 1955 | { 1956 | side = (WHITE + BLACK) - side; 1957 | continue; 1958 | } 1959 | if (!strcmp (s, "sd")) 1960 | { 1961 | scanf ("%d", &max_depth); 1962 | continue; 1963 | } 1964 | if (!strcmp (s, "perft")) 1965 | { 1966 | scanf ("%d", &max_depth); 1967 | clock_t start; 1968 | clock_t stop; 1969 | double t = 0.0; 1970 | /* Start timer */ 1971 | start = clock (); 1972 | unsigned long long count = perft (max_depth); 1973 | /* Stop timer */ 1974 | stop = clock (); 1975 | t = (double) (stop - start) / CLOCKS_PER_SEC; 1976 | printf ("nodes = %llu\n", count); 1977 | printf ("time = %.2f s\n", t); 1978 | double Mnps = (count/t)/1000000; 1979 | printf ("MegaNodes/second = %.2f Mnps\n", Mnps); 1980 | continue; 1981 | } 1982 | if (!strcmp (s, "quit")) 1983 | { 1984 | printf ("Good bye!\n"); 1985 | return 0; 1986 | } 1987 | 1988 | /* Maybe the user entered a move? */ 1989 | from = s[0] - 'a'; 1990 | from += 8 * (8 - (s[1] - '0')); 1991 | dest = s[2] - 'a'; 1992 | dest += 8 * (8 - (s[3] - '0')); 1993 | ply = 0; 1994 | movecnt = GenMoves (side, moveBuf); 1995 | 1996 | /* Loop through the moves to see if it's legal */ 1997 | for (i = 0; i < movecnt; i++) 1998 | if (moveBuf[i].from == from && moveBuf[i].dest == dest) 1999 | { 2000 | /* Promotion move? */ 2001 | if (piece[from] == PAWN && (dest < 8 || dest > 55)) 2002 | { 2003 | switch (s[4]) 2004 | { 2005 | case 'q': 2006 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN; 2007 | break; 2008 | 2009 | case 'r': 2010 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK; 2011 | break; 2012 | 2013 | case 'b': 2014 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP; 2015 | break; 2016 | 2017 | case 'n': 2018 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT; 2019 | break; 2020 | 2021 | default: 2022 | puts 2023 | ("promoting to a McGuffin..., I'll give you a queen"); 2024 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN; 2025 | } 2026 | } 2027 | if (!MakeMove (moveBuf[i])) 2028 | { 2029 | TakeBack (); 2030 | printf ("Illegal move.\n"); 2031 | } 2032 | break; 2033 | } 2034 | PrintBoard (); 2035 | } 2036 | } 2037 | -------------------------------------------------------------------------------- /secondchessW32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/secondchessW32.exe --------------------------------------------------------------------------------