├── Makefile ├── TODO ├── README.md ├── main.c ├── legality.c ├── hashtable.h ├── random.h ├── fen.c ├── eval.c ├── engine.h ├── attacked.c ├── hashtable.c ├── pawns.h ├── moveeval.c ├── board.c ├── conversion.c ├── uci.c ├── search.c ├── board.h ├── movegen.c ├── move.c ├── book.c └── uci.txt /Makefile: -------------------------------------------------------------------------------- 1 | NAME=claudia 2 | CC=gcc 3 | CFLAGS= -std=c99 -pthread -Wall -Wsign-compare -Winline -Wno-unused -Ofast -flto 4 | DEPS=make.dep 5 | CSRCS=$(wildcard *.c) 6 | HSRCS=$(wildcard *.h) 7 | OBJS=$(CSRCS:.c=.o) 8 | 9 | .PHONY: all clean 10 | 11 | all: $(NAME) $(DEPS) 12 | 13 | $(NAME): $(OBJS) 14 | $(CC) $(CFLAGS) -o $@ $^ 15 | 16 | clean: 17 | rm -f *.o make.dep 18 | 19 | include $(DEPS) 20 | 21 | make.dep: $(CSRCS) $(HSRCS) 22 | $(CC) -MM $(CSRCS) > make.dep 23 | 24 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | FEATURES PRIORITY STATUS 3 | 4 | * Split genmove subroutines - done 5 | 6 | * Halfmove clock - done 7 | 8 | * Threefold repetition detection - done 9 | 10 | * Hash tables support - done 11 | 12 | * Change castle rights representation - done 13 | 14 | * Time control - done 15 | 16 | * Null move heuristic - done 17 | 18 | * Check extensions - done 19 | 20 | * Checks in quiescent search low pending 21 | 22 | * King safety evaluation low pending 23 | 24 | * Pawn structure evaluation medium ongoing 25 | 26 | * Ponder - done 27 | 28 | * Get rid of global board - done 29 | 30 | * Multithreading low pending 31 | 32 | * Opening book support - done 33 | 34 | * UCI Hash value option - done 35 | 36 | * UCI options low pending 37 | 38 | * Ending knowledge medium ongoing 39 | 40 | * Tidy up parser - done 41 | 42 | * Lazy evaluation - done 43 | 44 | * Killer moves - done 45 | 46 | * Bishop pair - done 47 | 48 | * Contemp factor high ongoing 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Claudia is an open source UCI chess engine written in C. 3 | 4 | It is one (and the weakest) of the eight chess engines that were originally included with [DGT 5 | Pi](http://www.digitalgametechnology.com/index.php/products/chess-computers/pi?mavikthumbnails_display_ratio=1.5) 6 | and [Picochess](https://www.picochess.org) (until July 2017), alongside Stockfish, 7 | Texel, Arasan, RodentII, Zurichess, Floyd, and Cinnamon. According to the user manual 8 | for DGT Pi, Claudia is "an attractive opponent for intermediate club players" and "has 9 | a remarkably human playing style". 10 | 11 | From time to time, Claudia plays on the Free Internet Chess Server 12 | ([FICS](https://www.freechess.org)), where it has an authorised computer account under 13 | the name of [Claudiae](https://www.ficsgames.org/cgi-bin/search.cgi?player=claudiae&action=Statistics) 14 | (the operation is fully automated through my Python script 15 | [ponderbot](https://github.com/antoniogarro/ponderbot)). 16 | 17 | I wrote Claudia from scratch in order to learn a bit about chess programming. Although 18 | there is much room to improve it, I consider Claudia a finished project which I do not 19 | plan to keep developing in the near future. 20 | 21 | 22 | Usage 23 | ----- 24 | 25 | Claudia runs as a console application and can be used with any chess GUI that supports 26 | the UCI protocol. I have compiled it with gcc (both 64 and 32 bits systems) and 27 | Visual C++. 28 | 29 | 30 | Algorithm 31 | --------- 32 | 33 | The engine uses: 34 | 35 | * 0x88 internal board representation, 36 | * bitboards for pawn structure evaluation, 37 | * a single threaded negamax algorithm, 38 | * alpha-beta pruning, 39 | * iterative deepening, 40 | * aspiration windows, 41 | * principal variation search, 42 | * null move pruning, 43 | * lazy evaluation, 44 | * quiescent search, 45 | * check extensions, 46 | * static exchange evaluation, 47 | * killer moves heuristic 48 | * transposition tables, 49 | * pondering. 50 | 51 | Its leaf evaluation function is somewhat rudimentary, taking only into account 52 | material advantage, piece mobility and pawn structure, and using a tapered evaluation 53 | with limited ending knowledge. 54 | 55 | Claudia supports opening books in Polyglot (.bin) format, and will attempt to use 56 | any opening book named "book.bin" and placed in its same directory. The default book 57 | has been built from over forty thousand high-quality tournament games played by Grand 58 | Masters and International Masters over five years. 59 | 60 | 61 | Name 62 | ---- 63 | 64 | I obviously named Claudia after Claude E. Shannon (1916 - 2001). 65 | 66 | 67 | Thanks 68 | ------ 69 | 70 | To the authors of the main references I have used: Bruce Moreland's late [web 71 | page](https://web.archive.org/web/20070707012511/http://www.brucemo.com/compchess/programming/index.htm), 72 | Mediocre chess [blog](https://mediocrechess.blogspot.com), 73 | and the [Chess Programming Wiki](https://www.chessprogramming.org/Main_Page). 74 | 75 | To the players and the staff of FICS alike, for creating an open place to play chess online 76 | that provided invaluable data to debug the program. 77 | 78 | 79 | Copyright 80 | --------- 81 | 82 | This program has been written by Antonio Garro, and is released under a permissive 83 | BSD license: the code can be used and modified, as long as proper attribution is given. 84 | Please refer to the license in the source code for further details. 85 | 86 | The Polyglot opening book support uses code written and released into the public domain 87 | by Michel Van den Bergh. 88 | 89 | The Mersenne Twister pseudorandom number generator was written by Makoto Matsumoto 90 | and Takuji Nishimura (please see the copyright notice in random.h). 91 | 92 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include 33 | #include "engine.h" 34 | #include "board.h" 35 | 36 | #define BUFFER 2048 37 | 38 | /*Globals.*/ 39 | HASHTABLE hash_table; 40 | PAWNTABLE pawn_table; 41 | ZOBKEYS zobkeys; 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | BOARD main_board; 46 | InitBoard(&main_board); 47 | ReadFEN(STARTPOS, &main_board); 48 | 49 | CONTROL engine_control; 50 | engine_control.stop = 1; 51 | 52 | ENGINE_STATE engine = {&main_board, &engine_control}; 53 | 54 | if (AllocTable(&hash_table, 0.8*TABLESIZE) == 0) { 55 | printf("Not enough memory\n"); 56 | return 1; 57 | } 58 | ClearHashTable(&hash_table); 59 | 60 | if (AllocPawnTable(&pawn_table, 0.2*TABLESIZE) == 0) { 61 | printf("Not enough memory\n"); 62 | return 1; 63 | } 64 | ClearPawnTable(&pawn_table); 65 | 66 | setvbuf(stdin, 0, _IONBF, 0); 67 | setvbuf(stdout, 0, _IONBF, 0); 68 | fflush(NULL); 69 | char input[BUFFER]; 70 | 71 | while (fgets(input, BUFFER, stdin)) { 72 | if (!Command(input, &engine)) { 73 | break; 74 | } 75 | memset(input, 0, BUFFER); 76 | } 77 | 78 | DeleteTable(&hash_table); 79 | DeletePawnTable(&pawn_table); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /legality.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | #include "engine.h" 33 | 34 | char IsLegal(BOARD *board, MOVE *curr_move) 35 | { 36 | MOVE poss_moves[MAXMOVES]; 37 | int nposs_movs = MoveGen(board, poss_moves, 1); 38 | /*We only compare info about squares to decide legality, not captured piece or previous EP:*/ 39 | MOVE sqs = SQSMASK(*curr_move); 40 | /*TODO: promoted.*/ 41 | for (int i = 0; i < nposs_movs; i++) { 42 | if (sqs == SQSMASK(poss_moves[i])) { /*curr_move is possible.*/ 43 | MakeMove(board, curr_move); 44 | if (!LeftInCheck(board)) { 45 | Takeback(board, *curr_move); 46 | return 1; /*curr_move is legal.*/ 47 | } 48 | Takeback(board, *curr_move); 49 | } 50 | } 51 | return 0; 52 | } 53 | 54 | int Perft(BOARD *board, int depth) 55 | { 56 | int val = 0; 57 | int nposs_movs = 0; 58 | MOVE poss_moves[MAXMOVES]; 59 | 60 | nposs_movs = MoveGen(board, poss_moves, 1); 61 | 62 | for (int i = 0; i < nposs_movs; i++) { 63 | MakeMove(board, &poss_moves[i]); 64 | if (depth > 1) { 65 | if (board->white_to_move) { 66 | if (!BlackInCheck(board)) val += Perft(board, depth - 1); 67 | } else { 68 | if (!WhiteInCheck(board)) val += Perft(board, depth - 1); 69 | } 70 | } else { 71 | if (board->white_to_move) { 72 | if (!BlackInCheck(board)) val++; 73 | } else { 74 | if (!WhiteInCheck(board)) val++; 75 | } 76 | } 77 | Takeback(board, poss_moves[i]); 78 | } 79 | return val; 80 | } 81 | -------------------------------------------------------------------------------- /hashtable.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #ifndef HASHTABLEH 32 | #define HASHTABLEH 33 | 34 | #include "board.h" 35 | #include "pawns.h" 36 | 37 | #define HASH_EXACT 0 38 | #define HASH_BETA 1 39 | #define HASH_ALPHA 2 40 | 41 | #define PUT_HASH_MOVE(move) ((KEY)(move & 0xFFFFF)); 42 | #define PUT_HASH_EVAL(eval) (((KEY)eval & 0xFFFFFFFF) << 20); 43 | #define PUT_HASH_DEPTH(depth) (((KEY)depth & 0x3FF)<< 52); 44 | #define PUT_HASH_FLAG(flag) ((KEY)flag << 62); 45 | 46 | #define MOVEMASK(data) (MOVE)(data & 0xFFFFF) 47 | #define EVALMASK(data) (int)(data >> 20) 48 | #define DEPTHMASK(data) (int)((data >> 52) & 0x3FF) 49 | #define FLAGMASK(data) (char)(data >> 62) 50 | 51 | #define TABLESIZE 32 52 | 53 | typedef struct{ 54 | KEY zobrist_key; 55 | /*bits 0-19: hash_move; bits 20-51: eval; bits 52-61: depth; 62-63: flags.*/ 56 | KEY data; 57 | } HashData; 58 | 59 | typedef struct HASHTABLE{ 60 | HashData *entries; 61 | int size; 62 | int full; 63 | } HASHTABLE; 64 | extern struct HASHTABLE hash_table; 65 | 66 | int AllocTable(HASHTABLE*, int); 67 | void DeleteTable(HASHTABLE*); 68 | void ClearHashTable(HASHTABLE*); 69 | void UpdateTable(HASHTABLE*, KEY, int, MOVE, int, int); 70 | MOVE GetHashMove(HASHTABLE*, KEY); 71 | int GetHashEval(HASHTABLE*, KEY, int, int, int); 72 | 73 | typedef struct{ 74 | KEY pawn_bitboard; 75 | int eval; 76 | } PawnData; 77 | 78 | typedef struct PAWNTABLE{ 79 | PawnData *entries; 80 | int size; 81 | int full; 82 | } PAWNTABLE; 83 | 84 | extern struct PAWNTABLE pawn_table; 85 | 86 | int AllocPawnTable(PAWNTABLE*, int); 87 | void DeletePawnTable(PAWNTABLE*); 88 | void ClearPawnTable(PAWNTABLE*); 89 | void UpdatePawnTable(PAWNTABLE*, BITBOARD, int); 90 | int GetPawnEval(PAWNTABLE*, BITBOARD); 91 | #endif 92 | -------------------------------------------------------------------------------- /random.h: -------------------------------------------------------------------------------- 1 | /* 2 | A C-program for MT19937-64 (2004/9/29 version). 3 | Coded by Takuji Nishimura and Makoto Matsumoto. 4 | 5 | This is a 64-bit version of Mersenne Twister pseudorandom number 6 | generator. 7 | 8 | Before using, initialize the state by using init_genrand64(seed) 9 | or init_by_array64(init_key, key_length). 10 | 11 | Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions 16 | are met: 17 | 18 | 1. Redistributions of source code must retain the above copyright 19 | notice, this list of conditions and the following disclaimer. 20 | 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 25 | 3. The names of its contributors may not be used to endorse or promote 26 | products derived from this software without specific prior written 27 | permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 33 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 34 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 35 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 36 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 37 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 38 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | References: 42 | T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' 43 | ACM Transactions on Modeling and 44 | Computer Simulation 10. (2000) 348--357. 45 | M. Matsumoto and T. Nishimura, 46 | ``Mersenne Twister: a 623-dimensionally equidistributed 47 | uniform pseudorandom number generator'' 48 | ACM Transactions on Modeling and 49 | Computer Simulation 8. (Jan. 1998) 3--30. 50 | 51 | Any feedback is very welcome. 52 | http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html 53 | email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) 54 | */ 55 | 56 | #ifndef RANDOMH 57 | #define RANDOMH 58 | 59 | #define NN 312 60 | #define MM 156 61 | #define MATRIX_A 0xB5026F5AA96619E9ULL 62 | #define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */ 63 | #define LM 0x7FFFFFFFULL /* Least significant 31 bits */ 64 | 65 | 66 | static unsigned long long mt[NN]; 67 | static int mti=NN+1; 68 | 69 | /* initializes mt[NN] with a seed */ 70 | void init_genrand64(unsigned long long seed) 71 | { 72 | mt[0] = seed; 73 | for (mti=1; mti> 62)) + mti); 75 | } 76 | 77 | /* initialize by an array with array-length */ 78 | /* init_key is the array for initializing keys */ 79 | /* key_length is its length */ 80 | void init_by_array64(unsigned long long init_key[], unsigned long long key_length) 81 | { 82 | unsigned long long i, j, k; 83 | init_genrand64(19650218ULL); 84 | i=1; j=0; 85 | k = (NN>key_length ? NN : key_length); 86 | for (; k; k--) { 87 | mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 3935559000370003845ULL)) 88 | + init_key[j] + j; /* non linear */ 89 | i++; j++; 90 | if (i>=NN) { mt[0] = mt[NN-1]; i=1; } 91 | if (j>=key_length) j=0; 92 | } 93 | for (k=NN-1; k; k--) { 94 | mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 2862933555777941757ULL)) 95 | - i; /* non linear */ 96 | i++; 97 | if (i>=NN) { mt[0] = mt[NN-1]; i=1; } 98 | } 99 | 100 | mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */ 101 | } 102 | 103 | /* generates a random number on [0, 2^64-1]-interval */ 104 | unsigned long long genrand64_int64(void) 105 | { 106 | int i; 107 | unsigned long long x; 108 | static unsigned long long mag01[2]={0ULL, MATRIX_A}; 109 | 110 | if (mti >= NN) { /* generate NN words at one time */ 111 | 112 | /* if init_genrand64() has not been called, */ 113 | /* a default initial seed is used */ 114 | if (mti == NN+1) 115 | init_genrand64(5489ULL); 116 | 117 | for (i=0;i>1) ^ mag01[(int)(x&1ULL)]; 120 | } 121 | for (;i>1) ^ mag01[(int)(x&1ULL)]; 124 | } 125 | x = (mt[NN-1]&UM)|(mt[0]&LM); 126 | mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; 127 | 128 | mti = 0; 129 | } 130 | 131 | x = mt[mti++]; 132 | 133 | x ^= (x >> 29) & 0x5555555555555555ULL; 134 | x ^= (x << 17) & 0x71D67FFFEDA60000ULL; 135 | x ^= (x << 37) & 0xFFF7EEE000000000ULL; 136 | x ^= (x >> 43); 137 | 138 | return x; 139 | } 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /fen.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | #include "engine.h" 33 | #include 34 | 35 | int ReadFEN(const char *sFEN, BOARD *board) 36 | { /*TODO: check FEN validity.*/ 37 | int fen_pos = 0; 38 | SQUARE square = 0x70; 39 | board->wk_castle = 0; 40 | board->bk_castle = 0; 41 | board->wq_castle = 0; 42 | board->bq_castle = 0; 43 | board->w_castled = 0; 44 | board->b_castled = 0; 45 | 46 | for (char on_board = 1; on_board; fen_pos++) { 47 | char empty = 0; 48 | switch (sFEN[fen_pos]) { 49 | case ' ': on_board = 0; 50 | break; 51 | case '/': square -= 0x18; 52 | break; 53 | case '1': empty = 1; 54 | break; 55 | case '2': empty = 2; 56 | break; 57 | case '3': empty = 3; 58 | break; 59 | case '4': empty = 4; 60 | break; 61 | case '5': empty = 5; 62 | break; 63 | case '6': empty = 6; 64 | break; 65 | case '7': empty = 7; 66 | break; 67 | case '8': empty = 8; 68 | break; 69 | default: 70 | board->squares[square] = CharToPiece(sFEN[fen_pos]); 71 | if (board->squares[square] == W_KING) board->wking_pos = square; 72 | else if (board->squares[square] == B_KING) board->bking_pos = square; 73 | square++; 74 | break; 75 | } 76 | for (int i = 0; i < empty; i++) board->squares[square+i] = EMPTY; 77 | square += empty; 78 | } 79 | 80 | board->white_to_move = (sFEN[fen_pos] == 'w'); 81 | fen_pos+=2; 82 | 83 | for (char on_board = 1; on_board; fen_pos++) { /*Castle rights loop.*/ 84 | switch (sFEN[fen_pos]) { 85 | case 'K': board->wk_castle = 1; 86 | break; 87 | case 'k': board->bk_castle = 1; 88 | break; 89 | case 'Q': board->wq_castle = 1; 90 | break; 91 | case 'q': board->bq_castle = 1; 92 | break; 93 | case '-': 94 | break; 95 | default: on_board = 0; 96 | break; 97 | } 98 | } 99 | /*Store En Passant coordinates. TODO: check.*/ 100 | board->en_passant = 0x00; 101 | for (char on_board = 1; on_board; fen_pos++) { 102 | switch (sFEN[fen_pos]) { 103 | case ' ': on_board = 0; 104 | break; 105 | default: 106 | board->en_passant += CharToCoordinate(sFEN[fen_pos]); 107 | break; 108 | } 109 | } 110 | /*halfmoves and moves.*/ 111 | int rev = atoi(&sFEN[fen_pos]); 112 | while (sFEN[++fen_pos] != ' '); 113 | board->ply = 2*atoi(&sFEN[fen_pos]) - board->white_to_move - 1; 114 | board->rev_plies[board->ply] = rev; 115 | InitZobrist(board); 116 | board->zobrist_history[board->ply] = board->zobrist_key; 117 | InitMaterial(board); 118 | return fen_pos; 119 | } 120 | -------------------------------------------------------------------------------- /eval.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | #include "engine.h" 33 | #include 34 | static inline int KingEval(const BOARD *board) 35 | { 36 | return (board->w_castled * (1.0-PawnStage(board)) - 37 | board->b_castled * (1.0-PawnStage(board))) * CASTLE_BONUS 38 | +((board->wk_castle + board->wq_castle) - 39 | (board->bk_castle + board->bq_castle)) * CASTLE_RIGHT_BONUS 40 | +(distance_to_center[board->bking_pos] - 41 | distance_to_center[board->wking_pos]) * KING_CENTER_BONUS * PawnStage(board); 42 | } 43 | 44 | static inline int MobilityEval(const BOARD *board) 45 | { 46 | int val = 0; 47 | for (SQUARE sq = a1; sq <= h8; sq++) { 48 | PIECE p = board->squares[sq]; 49 | if (p && p < B_KING) { 50 | val += piece_moves[p](board, sq, 0, 0, 1) * mobility_bonus[p]; 51 | } 52 | if (COLUMN(sq) == H_COLUMN) sq += 8; 53 | } 54 | return val; 55 | } 56 | 57 | static inline int PawnStructureEval(const BOARD *board) 58 | { 59 | BITBOARD bp = board->pawns[BLACK], wp = board->pawns[WHITE]; 60 | BITBOARD b = bp | wp; 61 | int val = GetPawnEval(&pawn_table, b); 62 | if (val != ERRORVALUE) return val; 63 | 64 | val = (BitCount(DoubledPawns(bp)) - BitCount(DoubledPawns(wp))) * DOUBLED_PAWN_BONUS; 65 | val += DotProduct(WPassedPawns(wp, bp), WRANKS) * PASSED_PAWN_BONUS; 66 | val -= DotProduct(BPassedPawns(bp, wp), BRANKS) * PASSED_PAWN_BONUS; 67 | 68 | val *= GameStage(board); 69 | UpdatePawnTable(&pawn_table, b, val); 70 | return val; 71 | } 72 | 73 | static inline int MaterialDraw(const BOARD *board) 74 | { 75 | unsigned char side = board->white_to_move; 76 | if (board->pawn_material[side] || board->pawn_material[1-side]) return 0; 77 | if (board->piece_material[side] >= Value(W_ROOK) || board->piece_material[1-side] >= Value(W_ROOK)) return 0; 78 | return 1; 79 | } 80 | 81 | static inline int MaterialEval(const BOARD *board) 82 | { 83 | return (board->piece_material[WHITE] + board->pawn_material[WHITE] 84 | - board->piece_material[BLACK] - board->pawn_material[BLACK]) 85 | + ((board->bishops[WHITE] == 2) - (board->bishops[BLACK] == 2)) 86 | * BISHOP_PAIR_BONUS * PawnStage(board); 87 | } 88 | 89 | int LazyEval(const BOARD *board) 90 | { 91 | if (MaterialDraw(board)) return DRAW_VALUE; 92 | int lazy = MaterialEval(board) + PawnStructureEval(board); 93 | return board->white_to_move ? lazy : -lazy; 94 | } 95 | 96 | int StaticEval(const BOARD *board) 97 | { 98 | if (MaterialDraw(board)) return DRAW_VALUE; 99 | int val = MaterialEval(board); 100 | val += MobilityEval(board); 101 | val += PawnStructureEval(board); 102 | val += KingEval(board); 103 | val *= (1.0 + SIMPLIFY_BONUS * GameStage(board)); 104 | return board->white_to_move ? val : -val; 105 | } 106 | 107 | inline int Value(PIECE piece) 108 | { 109 | return piece_values[piece]; 110 | } 111 | -------------------------------------------------------------------------------- /engine.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #ifndef ENGINEH 32 | #define ENGINEH 33 | 34 | #include 35 | #include "board.h" 36 | 37 | #define NAME "Claudia" 38 | #define VERSION "0.5.1" 39 | 40 | 41 | #ifndef VALUES 42 | #define VALUES 43 | 44 | #define ERRORVALUE -1000000001 45 | #define INFINITE 10000000 46 | #define DRAW_VALUE 0 47 | #define MATE_VALUE -100000 48 | #define HASHMOVE_VALUE 100000 49 | #define KILLER_VALUE 50 50 | 51 | static const int piece_values[] = { 52 | 0, 0, 53 | PAWN_VALUE, PAWN_VALUE, 54 | KNIGHT_VALUE, KNIGHT_VALUE, 55 | BISHOP_VALUE, BISHOP_VALUE, 56 | ROOK_VALUE, ROOK_VALUE, 57 | QUEEN_VALUE, QUEEN_VALUE, 58 | -MATE_VALUE, -MATE_VALUE 59 | }; 60 | 61 | #define N_MOBILITY 5 62 | #define B_MOBILITY 4 63 | #define R_MOBILITY 1 64 | #define Q_MOBILITY 1 65 | #define K_MOBILITY 0 66 | static const int mobility_bonus[] = { 67 | 0, 0, 68 | -1, 1, 69 | -N_MOBILITY, N_MOBILITY, 70 | -B_MOBILITY, B_MOBILITY, 71 | -R_MOBILITY, R_MOBILITY, 72 | -Q_MOBILITY, Q_MOBILITY, 73 | -K_MOBILITY, K_MOBILITY 74 | }; 75 | 76 | #define CASTLE_BONUS 60 77 | #define CASTLE_RIGHT_BONUS 20 78 | #define KING_CENTER_BONUS 10 79 | #define SIMPLIFY_BONUS 0.1 80 | #define BISHOP_PAIR_BONUS 20 81 | #define PROMOTION_VALUE 10 82 | #define CHECK_VALUE 10 /*unused*/ 83 | 84 | #define DOUBLED_PAWN_BONUS 10 85 | #define ISOLATED_PAWN_BONUS 5 /*unused*/ 86 | #define PAWN_PUSH_BONUS 0.1 /*unused*/ 87 | #define PASSED_PAWN_BONUS 20 88 | 89 | #endif 90 | 91 | #ifndef SEARCH 92 | #define SEARCH 93 | #define ASP_WINDOW 50 94 | #define LAZYBETA 400 95 | #define LAZYALPHA 1000 96 | #define MAXMOVES 250 97 | #define MAXDEPTH 70 98 | #endif 99 | 100 | static const clock_t CPMS = CLOCKS_PER_SEC/1000; 101 | 102 | typedef struct CONTROL { 103 | clock_t wtime, btime, wtime_inc, btime_inc; 104 | clock_t init_time, wish_time, max_time; 105 | int max_depth, seldepth; 106 | unsigned long long node_count; 107 | char uci, stop, ponder; 108 | MOVE best_move; 109 | int contempt; 110 | } CONTROL; 111 | 112 | typedef struct ENGINE_STATE{ 113 | BOARD *board; 114 | CONTROL *control; 115 | } ENGINE_STATE; 116 | 117 | /*UCI commands*/ 118 | typedef int CMDFN(char*, ENGINE_STATE*); 119 | 120 | struct UCI_COMMAND{ 121 | char *name; 122 | CMDFN *cmd; 123 | }; 124 | 125 | void IterativeDeep(BOARD*, CONTROL*); 126 | 127 | int ParseCommand(const char*); 128 | int Command(const char*, ENGINE_STATE*); 129 | 130 | int PolyglotChooseMove(KEY key); 131 | 132 | static void think(void *pparams) 133 | { 134 | BOARD *board = ((ENGINE_STATE*)pparams)->board; 135 | CONTROL *control = ((ENGINE_STATE*)pparams)->control; 136 | 137 | if (PolyglotChooseMove(PolyglotKey(board))) { 138 | control->stop = 1; 139 | return; 140 | } else { 141 | control->stop = 0; 142 | } 143 | IterativeDeep(board, control); 144 | control->stop = 1; 145 | return; 146 | } 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /attacked.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | 33 | int AttackingPieces(const BOARD *board, SQUARE square, COLOR attacking_color, SQUARE *attacking_sqs) 34 | { 35 | int attackers = 0; 36 | SQUARE attacking_sq = 0; 37 | 38 | PIECE N_attacker, B_attacker, R_attacker, Q_attacker, K_attacker; 39 | 40 | if (attacking_color) { 41 | for (int i = 0; w_pawn_capture[i]; i++) { 42 | attacking_sq = square - w_pawn_capture[i]; 43 | if (IN_BOARD(attacking_sq) && board->squares[attacking_sq] == W_PAWN) { 44 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 45 | else return 1; 46 | } 47 | } 48 | N_attacker = W_KNIGHT, B_attacker = W_BISHOP, R_attacker = W_ROOK, 49 | Q_attacker = W_QUEEN, K_attacker = W_KING; 50 | } else { 51 | for (int i = 0; b_pawn_capture[i]; i++) { 52 | attacking_sq = square - b_pawn_capture[i]; 53 | if (IN_BOARD(attacking_sq) && board->squares[attacking_sq] == B_PAWN) { 54 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 55 | else return 1; 56 | } 57 | } 58 | N_attacker = B_KNIGHT, B_attacker = B_BISHOP, R_attacker = B_ROOK, 59 | Q_attacker = B_QUEEN, K_attacker = B_KING; 60 | } 61 | 62 | for (int i = 0; knight_delta[i]; i++) { 63 | attacking_sq = square + knight_delta[i]; 64 | if (IN_BOARD(attacking_sq)) { 65 | if (board->squares[attacking_sq] == N_attacker) { 66 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 67 | else return 1; 68 | } 69 | } 70 | } 71 | 72 | for (int i = 0; bishop_delta[i]; i++) { 73 | for (attacking_sq = square + bishop_delta[i]; IN_BOARD(attacking_sq); attacking_sq += bishop_delta[i]) { 74 | if (board->squares[attacking_sq] == EMPTY) { 75 | continue; 76 | } else if (board->squares[attacking_sq] == B_attacker) { 77 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 78 | else return 1; 79 | break; 80 | } else if (board->squares[attacking_sq] == Q_attacker) { 81 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 82 | else return 1; 83 | break; 84 | } else break; /*Piece other than bishop/queen, or different color, stop sliding*/ 85 | } 86 | } 87 | 88 | for (int i = 0; rook_delta[i]; i++) { 89 | for (attacking_sq = square + rook_delta[i]; IN_BOARD(attacking_sq); attacking_sq += rook_delta[i]) { 90 | if (board->squares[attacking_sq] == EMPTY) { 91 | continue; 92 | } else if (board->squares[attacking_sq] == R_attacker) { 93 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 94 | else return 1; 95 | break; 96 | } else if (board->squares[attacking_sq] == Q_attacker) { 97 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 98 | else return 1; 99 | break; 100 | } else break; 101 | } 102 | } 103 | 104 | for (int i = 0; king_delta[i]; i++) { 105 | attacking_sq = square + king_delta[i]; 106 | if (IN_BOARD(attacking_sq)) { 107 | if (board->squares[attacking_sq] == K_attacker) { 108 | if (attacking_sqs) attacking_sqs[attackers++] = attacking_sq; 109 | else return 1; 110 | break; 111 | } 112 | } 113 | } 114 | return attackers; 115 | } 116 | -------------------------------------------------------------------------------- /hashtable.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include "hashtable.h" 33 | #include "engine.h" 34 | 35 | int AllocTable(HASHTABLE *ht, int table_size) 36 | { 37 | unsigned int s = 1024*1024*table_size; 38 | do { 39 | ht->entries = (HashData*) malloc(s); 40 | ht->size = s/sizeof(HashData); 41 | s *= 0.8; 42 | } while (ht->entries == 0); 43 | 44 | return ht->size; 45 | } 46 | 47 | void DeleteTable(HASHTABLE *ht) 48 | { 49 | free(ht->entries); 50 | } 51 | 52 | void ClearHashTable(HASHTABLE *ht) 53 | { 54 | for (int i = 0; i < ht->size; i++) { 55 | ht->entries[i].zobrist_key = 0; 56 | ht->entries[i].data = 0; 57 | } 58 | ht->full = 0; 59 | } 60 | 61 | void UpdateTable(HASHTABLE *ht, KEY zob_key, int eval, MOVE best_move, int depth, int flag) 62 | { 63 | int key = zob_key%ht->size; 64 | HashData *entry = &(ht->entries[key]); 65 | 66 | if (MOVEMASK(entry->data)) { 67 | if (!best_move) return; 68 | if (DEPTHMASK(entry->data) > depth) return; 69 | } 70 | /*if (entry->depth >= depth && entry->best_move && !best_move) return;*/ 71 | if (entry->zobrist_key != zob_key) { 72 | if (entry->zobrist_key == 0) ht->full++; 73 | entry->zobrist_key = zob_key; 74 | } 75 | /*if (flag == HASHEXACT || flag == HASHBETA);*/ 76 | entry->data = PUT_HASH_MOVE(best_move); 77 | entry->data |= PUT_HASH_EVAL(eval); 78 | entry->data |= PUT_HASH_DEPTH(depth); 79 | entry->data |= PUT_HASH_FLAG(flag); 80 | } 81 | 82 | MOVE GetHashMove(HASHTABLE *ht, KEY zob_key) 83 | { 84 | int key = zob_key%ht->size; 85 | if (ht->entries[key].zobrist_key == zob_key) { 86 | return MOVEMASK(ht->entries[key].data); 87 | } else return 0; 88 | } 89 | 90 | int GetHashEval(HASHTABLE *ht, KEY zob_key, int depth, int alpha, int beta) 91 | { 92 | int key = zob_key%ht->size; 93 | const HashData *entry = &(ht->entries[key]); 94 | if (entry->zobrist_key == zob_key && DEPTHMASK(entry->data) >= depth) { 95 | int eval = EVALMASK(entry->data); 96 | char flag = FLAGMASK(entry->data); 97 | if (flag == HASH_EXACT) { 98 | return eval; 99 | } 100 | if (flag == HASH_BETA && eval >= beta) { 101 | return beta; 102 | } 103 | if (flag == HASH_ALPHA && eval < alpha) { 104 | return alpha; 105 | } 106 | } 107 | return ERRORVALUE; 108 | } 109 | 110 | 111 | /*Pawn HashTable routines*/ 112 | 113 | int AllocPawnTable(PAWNTABLE *pt, int table_size) 114 | { 115 | unsigned int s = 1024*1024*table_size; 116 | do { 117 | pt->entries = (PawnData*) malloc(s); 118 | pt->size = s/sizeof(PawnData); 119 | s *= 0.8; 120 | } while (pt->entries == 0); 121 | 122 | return pt->size; 123 | } 124 | 125 | void DeletePawnTable(PAWNTABLE *pt) 126 | { 127 | free(pt->entries); 128 | } 129 | 130 | void ClearPawnTable(PAWNTABLE *pt) 131 | { 132 | for (int i = 0; i < pt->size; i++) { 133 | pt->entries[i].pawn_bitboard = 0; 134 | pt->entries[i].eval = 0; 135 | } 136 | pt->full = 0; 137 | } 138 | 139 | void UpdatePawnTable(PAWNTABLE *pt, BITBOARD pawn_bitboard, int eval) 140 | { 141 | int key = pawn_bitboard%pt->size; 142 | PawnData *entry = &(pt->entries[key]); 143 | 144 | if (entry->pawn_bitboard != pawn_bitboard) { 145 | if (entry->pawn_bitboard == 0) pt->full++; 146 | entry->pawn_bitboard = pawn_bitboard; 147 | } 148 | entry->eval = eval; 149 | } 150 | int GetPawnEval(PAWNTABLE *pt, BITBOARD pawn_bitboard) 151 | { 152 | int key = pawn_bitboard%pt->size; 153 | const PawnData *entry = &(pt->entries[key]); 154 | 155 | if (entry->pawn_bitboard == pawn_bitboard) { 156 | return entry->eval; 157 | } 158 | return ERRORVALUE; 159 | } 160 | -------------------------------------------------------------------------------- /pawns.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | #ifndef PAWNSH 31 | #define PAWNSH 32 | 33 | #include "board.h" 34 | 35 | typedef unsigned long long BITBOARD; 36 | 37 | #define NOT_A 0xfefefefefefefefe 38 | #define NOT_H 0x7f7f7f7f7f7f7f7f 39 | 40 | static char BRANKS[] = { 41 | 7,7,7,7,7,7,7,7, 42 | 6,6,6,6,6,6,6,6, 43 | 5,5,5,5,5,5,5,5, 44 | 4,4,4,4,4,4,4,4, 45 | 3,3,3,3,3,3,3,3, 46 | 2,2,2,2,2,2,2,2, 47 | 1,1,1,1,1,1,1,1, 48 | 0,0,0,0,0,0,0,0 49 | }; 50 | 51 | static char WRANKS[] = { 52 | 0,0,0,0,0,0,0,0, 53 | 1,1,1,1,1,1,1,1, 54 | 2,2,2,2,2,2,2,2, 55 | 3,3,3,3,3,3,3,3, 56 | 4,4,4,4,4,4,4,4, 57 | 5,5,5,5,5,5,5,5, 58 | 6,6,6,6,6,6,6,6, 59 | 7,7,7,7,7,7,7,7 60 | }; 61 | 62 | static inline BITBOARD BitboardSet(SQUARE sq, BITBOARD b) 63 | { 64 | return b | (1ull << (ROW(sq)>>1) << COLUMN(sq)); 65 | } 66 | 67 | static inline BITBOARD BitboardUnset(SQUARE sq, BITBOARD b) 68 | { 69 | return b ^ (1ull << (ROW(sq)>>1) << COLUMN(sq)); 70 | } 71 | 72 | static inline BITBOARD LSB(BITBOARD b) 73 | { 74 | return b ^ (b-1); 75 | } 76 | 77 | static inline int BitCount(BITBOARD b) 78 | { 79 | int count = 0; 80 | for (; b; count++) { 81 | b &= b-1; 82 | } 83 | return count; 84 | } 85 | 86 | static int DotProduct(BITBOARD b, char weights[]) 87 | { 88 | BITBOARD bit = 1; 89 | int p = 0; 90 | for (SQUARE sq = 0; b && sq < 64; sq++, bit += bit) { 91 | if (b & bit) p += weights[sq]; 92 | } 93 | return p; 94 | } 95 | 96 | static inline int BitIndexLSB(BITBOARD b) 97 | { 98 | static const BITBOARD B[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 99 | 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF00000000}; 100 | unsigned int r = (b & B[0]) != 0; 101 | for (int i = 5; i > 0; i--) { 102 | r |= ((b & B[i]) != 0) << i; 103 | } 104 | return r; 105 | } 106 | 107 | static inline BITBOARD NorthFill(BITBOARD b) 108 | { 109 | b |= (b << 8); 110 | b |= (b << 16); 111 | b |= (b << 32); 112 | return b; 113 | } 114 | static inline BITBOARD SouthFill(BITBOARD b) 115 | { 116 | b |= (b >> 8); 117 | b |= (b >> 16); 118 | b |= (b >> 32); 119 | return b; 120 | } 121 | 122 | static inline BITBOARD FileFill(BITBOARD b) 123 | { 124 | return NorthFill(b) | SouthFill(b); 125 | } 126 | 127 | static inline BITBOARD SouthOne(BITBOARD b) 128 | { 129 | return b >> 8; 130 | } 131 | 132 | static inline BITBOARD NorthOne(BITBOARD b) 133 | { 134 | return b << 8; 135 | } 136 | 137 | static inline BITBOARD EastOne(BITBOARD b) 138 | { 139 | return (b & NOT_H) << 1; 140 | } 141 | 142 | static inline BITBOARD WestOne(BITBOARD b) 143 | { 144 | return (b & NOT_A) >> 1; 145 | } 146 | 147 | static inline BITBOARD WFrontSpans(BITBOARD wpawns) 148 | { 149 | return NorthOne(NorthFill(wpawns)); 150 | } 151 | 152 | static inline BITBOARD WRearSpans(BITBOARD wpawns) 153 | { 154 | return SouthOne(SouthFill(wpawns)); 155 | } 156 | 157 | static inline BITBOARD BFrontSpans(BITBOARD bpawns) 158 | { 159 | return SouthOne(SouthFill(bpawns)); 160 | } 161 | 162 | static inline BITBOARD BRearSpans(BITBOARD bpawns) 163 | { 164 | return NorthOne(NorthFill(bpawns)); 165 | } 166 | 167 | static inline BITBOARD WPassedPawns(BITBOARD wpawns, BITBOARD bpawns) 168 | { 169 | BITBOARD front_spans = BFrontSpans(bpawns); 170 | front_spans |= EastOne(front_spans) | WestOne(front_spans); 171 | return wpawns & ~front_spans; 172 | } 173 | 174 | static inline BITBOARD BPassedPawns(BITBOARD bpawns, BITBOARD wpawns) 175 | { 176 | BITBOARD front_spans = WFrontSpans(wpawns); 177 | front_spans |= EastOne(front_spans) | WestOne(front_spans); 178 | return bpawns & ~front_spans; 179 | } 180 | 181 | static inline BITBOARD DoubledPawns(BITBOARD pawns) 182 | { 183 | return pawns & WRearSpans(pawns); 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /moveeval.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | #include "engine.h" 33 | 34 | static int SEE(BOARD *board, MOVE *main_capture) 35 | { 36 | SQUARE dest = DESTMASK(*main_capture); 37 | SQUARE captured, sq; 38 | SQUARE attacking_sqs[10]; 39 | SQUARE less_attack_sq; 40 | int depth = 0, val = 0; 41 | MOVE move_hist[20]; 42 | 43 | MakeMove(board, main_capture); 44 | 45 | int attackers = AttackingPieces(board, dest, board->white_to_move, attacking_sqs); 46 | 47 | while (attackers) { 48 | less_attack_sq = attacking_sqs[0]; 49 | for (int i = 0; i < attackers; i++) { 50 | sq = attacking_sqs[i]; 51 | if (board->squares[less_attack_sq] > board->squares[sq]) { 52 | less_attack_sq = attacking_sqs[i]; 53 | } 54 | } 55 | 56 | if ( (board->squares[less_attack_sq] == B_PAWN && ROW(dest) == FIRST_ROW) 57 | || (board->squares[less_attack_sq] == W_PAWN && ROW(dest) == EIGHT_ROW) ) { 58 | move_hist[depth] = Move(B_QUEEN, dest, less_attack_sq); 59 | } 60 | else move_hist[depth] = Move(0, dest, less_attack_sq); 61 | 62 | MakeMove(board, &move_hist[depth++]); 63 | attackers = AttackingPieces(board, dest, board->white_to_move, attacking_sqs); 64 | } 65 | 66 | while (depth--) { 67 | captured = CAPTMASK(move_hist[depth]); 68 | if (val + Value(captured) > 0) val = -(val + Value(captured)); 69 | else val = 0; 70 | Takeback(board, move_hist[depth]); 71 | } 72 | captured = CAPTMASK(*main_capture); 73 | val = val + Value(captured); 74 | Takeback(board, *main_capture); 75 | 76 | return val; 77 | } 78 | 79 | static int QuietMoveEval(BOARD *board, MOVE *move, const MOVE killers[]) 80 | { 81 | if (SQSMASK(*move) == SQSMASK(killers[0]) || SQSMASK(*move) == SQSMASK(killers[1])) { 82 | return KILLER_VALUE; 83 | } else if (PROMMASK(*move)) { 84 | return PROMOTION_VALUE; 85 | } else { 86 | return 0; 87 | } 88 | } 89 | 90 | static int EvaluateMove(BOARD *board, MOVE *curr_move, const MOVE hash_move, const MOVE killers[]) 91 | { 92 | /*Compare with hash_move, using only orig, des; curr_move may not have captured or ep info.*/ 93 | if (SQSMASK(*curr_move) == SQSMASK(hash_move)) { 94 | return HASHMOVE_VALUE; /*search HashMove first.*/ 95 | } 96 | /*Evaluate captures with SEE:*/ 97 | SQUARE dest = DESTMASK(*curr_move); 98 | if (board->squares[dest] != EMPTY) { 99 | return SEE(board, curr_move); 100 | } else { 101 | return QuietMoveEval(board, curr_move, killers); 102 | } 103 | } 104 | 105 | int SortMoves(BOARD *board, MOVE *moves, int nmoves, MOVE killers[]) 106 | { 107 | int eval[MAXMOVES], good = 0; 108 | MOVE hash_move = GetHashMove(&hash_table, board->zobrist_key); 109 | /*Evaluate every move, store evaluations:*/ 110 | for (int i = 0; i < nmoves; i++) { 111 | eval[i] = EvaluateMove(board, &moves[i], hash_move, killers); 112 | if (eval[i] > 0) good++; 113 | } 114 | /*Order according to that evaluation: insertion sort*/ 115 | for (int i = 1; i < nmoves; i++) { 116 | for (int j = i; j > 0 && (eval[j-1] < eval[j]); j--) { 117 | MOVE tmp = moves[j-1]; 118 | moves[j-1] = moves[j]; 119 | moves[j] = tmp; 120 | 121 | int ev = eval[j-1]; 122 | eval[j-1] = eval[j]; 123 | eval[j] = ev; 124 | } 125 | } 126 | return good; 127 | } 128 | 129 | int FilterWinning(BOARD *board, MOVE *captures, int ncapts) 130 | { 131 | int good_capts = 0; 132 | int eval[MAXMOVES]; 133 | 134 | /*evaluate every move, store evaluations:*/ 135 | for (int i = 0; i < ncapts; i++) { 136 | eval[i] = SEE(board, &captures[i]); 137 | if (eval[i] > 0) good_capts++; 138 | } 139 | for (int i = 1; i < ncapts; i++) { 140 | for (int j = i; j > 0 && (eval[j-1] < eval[j]); j--) { 141 | MOVE tmp = captures[j-1]; 142 | captures[j-1] = captures[j]; 143 | captures[j] = tmp; 144 | 145 | int ev = eval[j-1]; 146 | eval[j-1] = eval[j]; 147 | eval[j] = ev; 148 | } 149 | } 150 | return good_capts; 151 | } 152 | -------------------------------------------------------------------------------- /board.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include "board.h" 33 | #include "random.h" 34 | 35 | void InitBoard(BOARD *board) 36 | { 37 | unsigned long long init[4]={0x12345ULL,0x23456ULL,0x34567ULL,0x45678ULL}; 38 | unsigned long long length = 4; 39 | init_by_array64(init, length); 40 | board->zobrist_key = 0; 41 | for (SQUARE sq = 0; sq < BOARDSIZE; sq++) { 42 | board->squares[sq] = EMPTY; 43 | /*Note j = 1; we want zobrist keys for EMPTY to be 0:*/ 44 | for (int j = 1; j <= 0xF; j++) { 45 | zobkeys.zob_pieces[j][sq] = genrand64_int64(); 46 | } 47 | zobkeys.zob_enpass[sq] = genrand64_int64(); 48 | } 49 | for (int i = 0; i < 4; i++) zobkeys.zob_castle[i] = genrand64_int64(); 50 | zobkeys.zob_side = genrand64_int64(); 51 | board->wk_castle = 0; 52 | board->bk_castle = 0; 53 | board->wq_castle = 0; 54 | board->bq_castle = 0; 55 | board->en_passant = INVALID_SQ; /*there's no en passant pawn initialy.*/ 56 | board->pawn_material[0] = 0, board->pawn_material[1] = 0; 57 | board->piece_material[0] = 0, board->piece_material[1] = 0; 58 | board->bishops[0] = 0, board->bishops[1] = 0; 59 | } 60 | 61 | void InitZobrist(BOARD *board) 62 | { 63 | board->zobrist_key = 0; 64 | for (int i = 0; i < BOARDSIZE; i++) { 65 | if (IN_BOARD(i)) board->zobrist_key ^= zobkeys.zob_pieces[board->squares[i]][i]; 66 | } 67 | if (board->wk_castle) board->zobrist_key ^= zobkeys.zob_castle[0]; 68 | if (board->wq_castle) board->zobrist_key ^= zobkeys.zob_castle[1]; 69 | if (board->bk_castle) board->zobrist_key ^= zobkeys.zob_castle[2]; 70 | if (board->bq_castle) board->zobrist_key ^= zobkeys.zob_castle[3]; 71 | 72 | if (IN_BOARD(board->en_passant)) board->zobrist_key ^= zobkeys.zob_enpass[board->en_passant]; 73 | if (board->white_to_move) board->zobrist_key ^= zobkeys.zob_side; 74 | } 75 | 76 | void InitMaterial(BOARD *board) 77 | { 78 | board->pawn_material[0] = 0, board->pawn_material[1] = 0; 79 | board->piece_material[0] = 0, board->piece_material[1] = 0; 80 | board->pawns[0] = 0, board->pawns[1] = 0; 81 | board->bishops[0] = 0, board->bishops[1] = 0; 82 | for (int sq = 0; sq < BOARDSIZE; sq++) { 83 | PIECE p = board->squares[sq]; 84 | if (IN_BOARD(sq) && p != EMPTY && p != W_KING && p != B_KING) { 85 | if (p == W_PAWN || p == B_PAWN) { 86 | board->pawn_material[GET_COLOR(p)] += Value(p); 87 | board->pawns[GET_COLOR(p)] = BitboardSet(sq, board->pawns[GET_COLOR(p)]); 88 | } else { 89 | if (p == W_BISHOP || p == B_BISHOP) board->bishops[GET_COLOR(p)]++; 90 | board->piece_material[GET_COLOR(p)] += Value(p); 91 | } 92 | } 93 | } 94 | } 95 | 96 | void PrintBoard(const BOARD *board) 97 | { 98 | printf("\n"); 99 | printf("\n+--+--+--+--+--+--+--+--+ %c %c%c%c%c +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+\n", 100 | (board->white_to_move+1?'W':'B'), 101 | (board->wq_castle?'Q':' '), (board->wk_castle?'K':' '), 102 | (board->bq_castle?'q':' '), (board->bk_castle?'k':' ')); 103 | 104 | for (int i = 0x70; i >= 0; i++) { 105 | if (!(i&0x88)) { 106 | printf("| %c", PieceToChar(board->squares[i])); 107 | } else { 108 | printf("| "); 109 | for (int j = 0; j<8; j++) printf(" %c ", (board->pawns[0] & (1ull << (ROW(i-1) >> 1) << j)) ? 'p' : ' '); 110 | printf(" "); 111 | for (int j = 0; j<8; j++) printf(" %c ", (board->pawns[1] & (1ull << (ROW(i-1) >> 1) << j)) ? 'P' : ' '); 112 | printf("\n+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+\n"); 113 | i -= 0x19; 114 | } 115 | } 116 | printf("Ply: %i (%i) EnPassant: %x\n", board->ply, board->rev_plies[board->ply], board->en_passant); 117 | printf("Material: W: %i %i; B: %i %i; Zobrist: %Lu; Stage: %f PawnStage: %f\n", 118 | board->piece_material[1], board->pawn_material[1], 119 | board->piece_material[0], board->pawn_material[0], 120 | board->zobrist_key, GameStage(board), PawnStage(board)); 121 | printf("BB: %llx , %llx; Passers: %llx ranks %i; %llx ranks %i ", 122 | board->pawns[0], board->pawns[1], 123 | WPassedPawns(board->pawns[1], board->pawns[0]), 124 | DotProduct(WPassedPawns(board->pawns[1], board->pawns[0]), WRANKS), 125 | BPassedPawns(board->pawns[0], board->pawns[1]), 126 | DotProduct(BPassedPawns(board->pawns[0], board->pawns[1]), BRANKS)); 127 | printf("Doubled: %i %i; Eval: %i\n", 128 | BitCount(DoubledPawns(board->pawns[1])), 129 | BitCount(DoubledPawns(board->pawns[0])), 130 | StaticEval(board)); 131 | } 132 | -------------------------------------------------------------------------------- /conversion.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | 33 | PIECE CharToPiece(const char fen) 34 | { 35 | char piece = 0; 36 | switch (fen) { 37 | case 'p': piece = B_PAWN; 38 | break; 39 | case 'P': piece = W_PAWN; 40 | break; 41 | case 'n': piece = B_KNIGHT; 42 | break; 43 | case 'N': piece = W_KNIGHT; 44 | break; 45 | case 'b': piece = B_BISHOP; 46 | break; 47 | case 'B': piece = W_BISHOP; 48 | break; 49 | case 'r': piece = B_ROOK; 50 | break; 51 | case 'R': piece = W_ROOK; 52 | break; 53 | case 'q': piece = B_QUEEN; 54 | break; 55 | case 'Q': piece = W_QUEEN; 56 | break; 57 | case 'k': piece = B_KING; 58 | break; 59 | case 'K': piece = W_KING; 60 | break; 61 | default: piece = EMPTY; 62 | break; 63 | } 64 | return piece; 65 | } 66 | 67 | char PieceToChar(PIECE piece) 68 | { 69 | //const char *pieces = " PpNnBbRrQqKkCCC"; 70 | const char *pieces = " CpPnNbBrRqQkKCC"; 71 | return pieces[piece]; 72 | } 73 | 74 | char CharToCoordinate(const char fen) 75 | { 76 | char coord = 0x77; 77 | switch (fen) { 78 | case '1': coord = 0x00; 79 | break; 80 | case '2': coord = 0x10; 81 | break; 82 | case '3': coord = 0x20; 83 | break; 84 | case '4': coord = 0x30; 85 | break; 86 | case '5': coord = 0x40; 87 | break; 88 | case '6': coord = 0x50; 89 | break; 90 | case '7': coord = 0x60; 91 | break; 92 | case '8': coord = 0x70; 93 | break; 94 | case 'a': coord = 0x00; 95 | break; 96 | case 'b': coord = 0x01; 97 | break; 98 | case 'c': coord = 0x02; 99 | break; 100 | case 'd': coord = 0x03; 101 | break; 102 | case 'e': coord = 0x04; 103 | break; 104 | case 'f': coord = 0x05; 105 | break; 106 | case 'g': coord = 0x06; 107 | break; 108 | case 'h': coord = 0x07; 109 | break; 110 | default: coord = 0x0F; 111 | break; 112 | } 113 | return coord; 114 | } 115 | 116 | char RowCoordinateToChar(const char coord) 117 | { 118 | char row; 119 | switch (coord) { 120 | case 0x00: row = '1'; 121 | break; 122 | case 0x01: row = '2'; 123 | break; 124 | case 0x02: row = '3'; 125 | break; 126 | case 0x03: row = '4'; 127 | break; 128 | case 0x04: row = '5'; 129 | break; 130 | case 0x05: row = '6'; 131 | break; 132 | case 0x06: row = '7'; 133 | break; 134 | case 0x07: row = '8'; 135 | break; 136 | default: row = 0; 137 | break; 138 | } 139 | return row; 140 | } 141 | 142 | char ColumnCoordinateToChar(const char coord) 143 | { 144 | char column; 145 | switch (coord) { 146 | case 0x00: column = 'a'; 147 | break; 148 | case 0x01: column = 'b'; 149 | break; 150 | case 0x02: column = 'c'; 151 | break; 152 | case 0x03: column = 'd'; 153 | break; 154 | case 0x04: column = 'e'; 155 | break; 156 | case 0x05: column = 'f'; 157 | break; 158 | case 0x06: column = 'g'; 159 | break; 160 | case 0x07: column = 'h'; 161 | break; 162 | default: column = 0; 163 | break; 164 | } 165 | return column; 166 | } 167 | 168 | MOVE AlgebToMove(const char *str_mov) 169 | { 170 | MOVE curr_move = 0; 171 | char square = 0; 172 | 173 | /*Pieced promoted to:*/ 174 | square = CharToPiece(str_mov[4]); 175 | curr_move += square; 176 | curr_move = curr_move << 8; 177 | 178 | /*DEST:*/ 179 | square = CharToCoordinate(str_mov[3]) + CharToCoordinate(str_mov[2]); 180 | curr_move += square; 181 | curr_move = curr_move << 8; 182 | 183 | /*ORIG:*/ 184 | square = CharToCoordinate(str_mov[1]) + CharToCoordinate(str_mov[0]); 185 | curr_move += square; 186 | 187 | return curr_move; 188 | } 189 | 190 | void MoveToAlgeb(const MOVE curr_move, char *str_mov) 191 | { 192 | MOVE aux_move = (curr_move & 0xFFFFF) >> 16; 193 | str_mov [4] = PieceToChar(aux_move); 194 | if (str_mov[4] == 'C' || str_mov[4] == ' ') { 195 | str_mov[4] = ' '; 196 | str_mov[5] = 0; 197 | } else { 198 | str_mov[5] = ' '; 199 | str_mov[6] = 0; 200 | } 201 | 202 | /*DEST ROW:*/ 203 | aux_move = (curr_move & 0xFFFF) >> 12; 204 | str_mov [3] = RowCoordinateToChar(aux_move); 205 | 206 | /*DEST COLUMN:*/ 207 | aux_move = (curr_move & 0xFFF) >> 8; 208 | str_mov [2] = ColumnCoordinateToChar(aux_move); 209 | 210 | /*ORIG ROW:*/ 211 | aux_move = (curr_move & 0xFF) >> 4; 212 | str_mov [1] = RowCoordinateToChar(aux_move); 213 | 214 | /*ORIG COLUMN:*/ 215 | aux_move = (curr_move & 0xF); 216 | str_mov [0] = ColumnCoordinateToChar(aux_move); 217 | } 218 | -------------------------------------------------------------------------------- /uci.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include 33 | #include 34 | #ifdef __linux__ 35 | #include 36 | #elif _WIN32 37 | #include 38 | #endif 39 | #include "engine.h" 40 | #include "hashtable.h" 41 | 42 | 43 | CMDFN make_move, quit, go, stop, ponderhit, perft, position, uci, isready, setoption, ucinewgame, showboard; 44 | 45 | const struct UCI_COMMAND uci_commands[] = {{"INV", &make_move}, 46 | {"quit", &quit}, 47 | {"go", &go}, 48 | {"stop", &stop}, 49 | {"ponderhit", &ponderhit}, 50 | {"perft", &perft}, 51 | {"position", &position}, 52 | {"uci", &uci}, 53 | {"isready", &isready}, 54 | {"setoption", &setoption}, 55 | {"ucinewgame", &ucinewgame}, 56 | {"show", &showboard}}; 57 | 58 | int ParseCommand(const char *command) 59 | { if (command == 0) return 0; 60 | for (unsigned int i = 0; i < sizeof(uci_commands)/sizeof(struct UCI_COMMAND); i++) { 61 | if (!strcmp(command, uci_commands[i].name)) return i; 62 | } 63 | return 0; 64 | } 65 | 66 | int Command(const char *input, ENGINE_STATE *stat) 67 | { 68 | char input_copy[2048], cmd_str[20]; 69 | strcpy(input_copy, input); 70 | sscanf(input, "%s", cmd_str); 71 | int cmd = ParseCommand(cmd_str); 72 | return uci_commands[cmd].cmd(input_copy, stat); 73 | } 74 | 75 | inline void ManageTimes(int nmoves, ENGINE_STATE *stat) 76 | { 77 | if (stat->board->white_to_move) { 78 | stat->control->wish_time = stat->control->wtime/nmoves + stat->control->wtime_inc; 79 | stat->control->max_time = stat->control->wtime; 80 | } else { 81 | stat->control->wish_time = stat->control->btime/nmoves + stat->control->btime_inc; 82 | stat->control->max_time = stat->control->btime; 83 | } 84 | /* stat->control->max_time = (stat->control->max_time/2 < 5*stat->control->wish_time) ? 85 | stat->control->max_time/2 : 5*stat->control->wish_time; */ 86 | } 87 | 88 | inline void ResetTimes(ENGINE_STATE *stat) 89 | { 90 | stat->control->wtime = 0; stat->control->btime = 0; 91 | stat->control->wtime_inc = 0; stat->control->btime_inc = 0; 92 | } 93 | 94 | int make_move(char *input, ENGINE_STATE *stat) 95 | { 96 | char *str_param = strtok(input, " \n\t"); 97 | if (str_param) { 98 | MOVE curr_move = AlgebToMove(str_param); 99 | if (IsLegal(stat->board, &curr_move)) MakeMove(stat->board, &curr_move); 100 | } 101 | return 1; 102 | } 103 | 104 | int quit(char *input, ENGINE_STATE *stat) 105 | { 106 | stat->control->stop = 1; 107 | return 0; 108 | } 109 | 110 | int go(char *input, ENGINE_STATE *stat) 111 | { 112 | stat->control->max_depth = MAXDEPTH; 113 | stat->control->max_time = INFINITE; 114 | stat->control->wish_time = INFINITE; 115 | stat->control->stop = 1; 116 | stat->control->ponder = 0; 117 | ResetTimes(stat); 118 | int movestogo = 35; 119 | char manage_times = 1; 120 | char *str_param = strtok(input, " \n\t"); 121 | for (str_param = strtok(NULL, " \n\t"); str_param; str_param = strtok(NULL, " \n\t")) { 122 | if (!strcmp("depth", str_param)) { 123 | str_param = strtok(NULL, " \n\t"); 124 | if (str_param) { 125 | stat->control->max_depth = atoi(str_param); 126 | manage_times = 0; 127 | } 128 | break; 129 | } else if (!strcmp("movetime", str_param)) { 130 | str_param = strtok(NULL, " \n\t"); 131 | if (str_param) { 132 | stat->control->wish_time = INFINITE; 133 | stat->control->max_time = atol(str_param); 134 | manage_times = 0; 135 | } 136 | } else if (!strcmp("infinite", str_param)) { 137 | manage_times = 0; 138 | break; 139 | } else if (!strcmp("ponder", str_param)) { 140 | stat->control->ponder = 1; 141 | } else if (!strcmp("btime", str_param)) { 142 | str_param = strtok(NULL, " \n\t"); 143 | if (str_param) { 144 | stat->control->btime = atoi(str_param); 145 | } 146 | } else if (!strcmp("wtime", str_param)) { 147 | str_param = strtok(NULL, " \n\t"); 148 | if (str_param) { 149 | stat->control->wtime = atoi(str_param); 150 | } 151 | } else if (!strcmp("binc", str_param)) { 152 | str_param = strtok(NULL, " \n\t"); 153 | if (str_param) { 154 | stat->control->btime_inc = atoi(str_param); 155 | } 156 | } else if (!strcmp("winc", str_param)) { 157 | str_param = strtok(NULL, " \n\t"); 158 | if (str_param) { 159 | stat->control->wtime_inc = atoi(str_param); 160 | } 161 | } else if (!strcmp("movestogo", str_param)) { 162 | str_param = strtok(NULL, " \n\t"); 163 | if (str_param) { 164 | movestogo = atoi(str_param); 165 | } 166 | } else break; 167 | } 168 | 169 | if (stat->control->stop) { 170 | if (manage_times) { 171 | ManageTimes(movestogo, stat); 172 | } 173 | stat->control->stop = 0; 174 | stat->control->init_time = clock(); 175 | #ifdef __linux__ 176 | pthread_attr_t tattr; 177 | pthread_attr_init(&tattr); 178 | pthread_attr_setdetachstate(&tattr,PTHREAD_CREATE_DETACHED); 179 | 180 | pthread_t thread_id; 181 | pthread_create(&thread_id, &tattr, (void *)(think), stat); 182 | #elif defined _WIN32 183 | _beginthread(think, 0, stat); 184 | #endif 185 | } 186 | return 1; 187 | } 188 | 189 | int stop(char *input, ENGINE_STATE *stat) 190 | { 191 | stat->control->ponder = 0; 192 | stat->control->stop = 1; 193 | return 1; 194 | } 195 | 196 | int ponderhit(char *input, ENGINE_STATE *stat) 197 | { 198 | stat->control->ponder=0; 199 | return 1; 200 | } 201 | 202 | int perft(char *input, ENGINE_STATE *stat) 203 | { 204 | int depth = 0; 205 | sscanf(input, "perft %i", &depth); 206 | stat->control->init_time = clock(); 207 | unsigned int nodes = Perft(stat->board, depth); 208 | float ms = (clock() - stat->control->init_time)/CPMS; 209 | printf("Depth: %i Moves: %i knps: %u\n", depth, nodes, (unsigned int)(nodes/ms)); 210 | return 1; 211 | } 212 | 213 | int position(char *input, ENGINE_STATE *stat) 214 | { 215 | strtok(input, " \n\t"); 216 | char *str_param = strtok(NULL, " \n\t"); 217 | if (!strcmp(str_param, "startpos")) ReadFEN(STARTPOS, stat->board); 218 | else if (!strcmp(str_param, "fen")) { 219 | /*Don't split chain at spaces; cut at 'm' for 'moves' or at '\n'.*/ 220 | str_param = strtok(NULL, "m\n\t"); 221 | if (str_param) ReadFEN(str_param, stat->board); 222 | } else return 0; 223 | 224 | str_param = strtok(NULL, " \n\t"); /*e.g. str_param == "moves"*/ 225 | str_param = strtok(NULL, " \n\t"); /*e.g. str_param == "e2e4"*/ 226 | while (str_param) { 227 | MOVE curr_move = AlgebToMove(str_param); 228 | if (IsLegal(stat->board, &curr_move)) MakeMove(stat->board, &curr_move); 229 | else return 0; 230 | str_param = strtok(NULL, " \n\t"); 231 | } 232 | return 1; 233 | } 234 | 235 | int uci(char *input, ENGINE_STATE *stat) 236 | { 237 | stat->control->uci = 1; 238 | printf("id name %s v. %s\n", NAME, VERSION); 239 | printf("id author Antonio Garro\n"); 240 | printf("option name Hash type spin default %i min 32 max 2048\n", TABLESIZE); 241 | printf("uciok\n"); 242 | return 1; 243 | } 244 | 245 | int isready(char *input, ENGINE_STATE *stat) 246 | { 247 | printf("readyok\n"); 248 | return 1; 249 | } 250 | 251 | int setoption(char *input, ENGINE_STATE *stat) 252 | { 253 | int val = 0; 254 | if (sscanf(input, "setoption name Hash value %i", &val)) { 255 | DeleteTable(&hash_table); 256 | DeletePawnTable(&pawn_table); 257 | if (AllocPawnTable(&pawn_table, 0.2*val) == 0) return 0; 258 | if (AllocTable(&hash_table, 0.8*val) == 0) return 0; 259 | ClearHashTable(&hash_table); 260 | ClearPawnTable(&pawn_table); 261 | } else if (sscanf(input, "setoption name Contempt value %i", &val)) { 262 | stat->control->contempt = val; 263 | printf("contempt: %i\n", stat->control->contempt); 264 | } 265 | return 1; 266 | } 267 | 268 | int ucinewgame(char *input, ENGINE_STATE *stat) 269 | { 270 | ClearHashTable(&hash_table); 271 | ClearPawnTable(&pawn_table); 272 | return 1; 273 | } 274 | 275 | int showboard(char *input, ENGINE_STATE *stat) 276 | { 277 | if (!stat->control->uci) PrintBoard(stat->board); 278 | return 1; 279 | } 280 | -------------------------------------------------------------------------------- /search.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include 33 | #include "engine.h" 34 | #include "hashtable.h" 35 | 36 | #define PVLEN 100 37 | #define SPVLEN 600 38 | #define MVLEN 7 39 | 40 | /*This works because the replacement scheme ensures shallow PV is not overwritten, 41 | and may fail if the hash table is full.*/ 42 | static int RetrievePV(BOARD *board, MOVE *PV, int depth) 43 | { 44 | int PVlen = 0; 45 | MOVE mov = GetHashMove(&hash_table, board->zobrist_key); 46 | while (mov && PVlen <= depth && IsLegal(board, &mov)) { 47 | PV[PVlen++] = mov; 48 | MakeMove(board, &mov); 49 | mov = GetHashMove(&hash_table, board->zobrist_key); 50 | } 51 | for (int i = PVlen; i > 0; i--) { 52 | Takeback(board, PV[i-1]); 53 | } 54 | return PVlen; 55 | } 56 | 57 | static int AssessDraw(const BOARD *board, int contempt) 58 | { 59 | int draw = board->white_to_move ? 60 | DRAW_VALUE + contempt*(1.0-GameStage(board)): 61 | DRAW_VALUE - contempt*(1.0-GameStage(board)); 62 | if (board->rev_plies[board->ply] >= 50) { 63 | return draw; 64 | } else { 65 | for (int p = board->ply-board->rev_plies[board->ply]; p < board->ply; p++) { 66 | if (board->zobrist_history[p] == board->zobrist_key) { 67 | return draw; 68 | } 69 | } 70 | } 71 | return ERRORVALUE; 72 | } 73 | 74 | static int DrawMove(BOARD *board, MOVE move) 75 | { 76 | MakeMove(board, &move); 77 | int draw = AssessDraw(board, 0); 78 | Takeback(board, move); 79 | return draw != ERRORVALUE; 80 | } 81 | 82 | static int AlphaBeta (BOARD *board, int depth, int alpha, int beta, 83 | int root, CONTROL *control, char skip_null, MOVE killers[][2]) 84 | { 85 | int nmoves, good = 0, nlegal = 0; 86 | MOVE moves[MAXMOVES]; 87 | MOVE best_move = 0; 88 | char str_mov[MVLEN]; 89 | int val = ERRORVALUE; 90 | char hash_flag = HASH_ALPHA; 91 | 92 | int in_check = InCheck(board, 0); 93 | 94 | if (root > control->seldepth) control->seldepth = root; 95 | 96 | if (depth > 0 || in_check) { 97 | if (root > 0) { 98 | val = GetHashEval(&hash_table, board->zobrist_key, depth, alpha, beta); 99 | if (val != ERRORVALUE) return val; 100 | } 101 | if (depth > 2 && !in_check) { 102 | if (!skip_null && board->piece_material[board->white_to_move] != 0) { 103 | MOVE null_mv = NULL_MOVE; 104 | MakeMove(board, &null_mv); 105 | val = -AlphaBeta(board, depth-3, -beta, -beta+1, root+1, control, 1, killers); 106 | Takeback(board, null_mv); 107 | if (val >= beta) return beta; 108 | } 109 | } 110 | nmoves = MoveGen(board, moves, 1); 111 | good = SortMoves(board, moves, nmoves, killers[root]); 112 | } else { 113 | if (!control->ponder && clock() - control->init_time >= (control->max_time - 10)*CPMS) { 114 | control->stop = 1; 115 | } 116 | val = LazyEval(board); 117 | if (val-LAZYBETA >= beta) return beta; 118 | if (val+LAZYALPHA < alpha) return alpha; 119 | 120 | val = StaticEval(board); 121 | UpdateTable(&hash_table, board->zobrist_key, val, 0, 0, HASH_EXACT); 122 | if (val >= beta) return beta; 123 | if (val > alpha) alpha = val; 124 | 125 | nmoves = CaptureGen(board, moves); 126 | nmoves = FilterWinning(board, moves, nmoves); 127 | } 128 | 129 | for (int i = 0; i < nmoves; i++) { 130 | MakeMove(board, &moves[i]); 131 | control->node_count++; 132 | if (LeftInCheck(board)) { 133 | Takeback(board, moves[i]); 134 | continue; 135 | } 136 | if (root == 0) { 137 | if (!control->best_move) control->best_move = moves[i]; /* Better than nothing. */ 138 | if (depth > 6 && !control->ponder) { 139 | MoveToAlgeb(moves[i], str_mov); 140 | printf("info depth %i seldepth %i hashfull %i currmove %s currmovenumber %i\n", 141 | depth, control->seldepth, hash_table.full/(hash_table.size/1000), str_mov, i+1); 142 | } 143 | } 144 | nlegal++; 145 | val = AssessDraw(board, control->contempt); 146 | if (val == ERRORVALUE) { 147 | int ext = 0; //InCheck(board, 0) ? 1 : 0; 148 | if (best_move) { 149 | int LMR = (depth > 2 && !in_check && i > good && 150 | !CAPTMASK(moves[i]) && !InCheck(board, 0)) ? 1 : 0; 151 | val = -AlphaBeta(board, depth+ext-LMR-1, -alpha-1, -alpha, root+1, control, 0, killers); 152 | if (val > alpha) { 153 | val = -AlphaBeta(board, depth+ext-1, -alpha-1, -alpha, root+1, control, 0, killers); 154 | if (val > alpha && val < beta) { 155 | val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers); 156 | } 157 | } 158 | } else { 159 | val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers); 160 | } 161 | } 162 | Takeback(board, moves[i]); 163 | if (!control->ponder && control->stop) return alpha; 164 | if (val >= beta) { 165 | UpdateTable(&hash_table, board->zobrist_key, val, moves[i], depth, HASH_BETA); 166 | if (CAPTMASK(moves[i]) == 0 && killers[root][0] != moves[i] && killers[root][1] != moves[i]) { 167 | killers[root][1] = killers[root][0]; 168 | killers[root][0] = moves[i]; 169 | } 170 | return beta; 171 | } 172 | if (val > alpha) { 173 | alpha = val; 174 | hash_flag = HASH_EXACT; 175 | best_move = moves[i]; 176 | if (root == 0) control->best_move = best_move; 177 | } 178 | if (root == 0 && ((clock() - control->init_time) > control->wish_time*CPMS)) { 179 | /* if short of time, don't search anymore after current move */ 180 | control->stop = 1; 181 | return alpha; 182 | } 183 | } 184 | if (nlegal == 0) { 185 | if (in_check) { 186 | /*UpdateTable(&hash_table, board->zobrist_key, MATE_VALUE+root, 0, depth, HASH_EXACT, hash_table.entries);*/ 187 | return MATE_VALUE; 188 | } else if (depth > 0) { 189 | /*UpdateTable(&hash_table, board->zobrist_key, DRAW_VALUE, 0, depth, HASH_EXACT, hash_table.entries);*/ 190 | return DRAW_VALUE; /*Stalemate*/ 191 | } 192 | } else { 193 | UpdateTable(&hash_table, board->zobrist_key, alpha, best_move, depth, hash_flag); 194 | } 195 | return alpha; 196 | } 197 | 198 | void IterativeDeep(BOARD *board, CONTROL *control) 199 | { 200 | MOVE iPV[PVLEN]; 201 | char sPV[SPVLEN]; 202 | char str_mov[MVLEN]; 203 | int eval = 0, pvlen = 0; 204 | int alpha = -INFINITE; 205 | int beta = INFINITE; 206 | int widening = ASP_WINDOW; 207 | unsigned long long nps = 0; 208 | MOVE killers[MAXDEPTH][2]; 209 | control->best_move = 0; 210 | 211 | /*printf("time %llu %llu\n", control->max_time, control->wish_time);*/ 212 | 213 | for (int depth = 1; depth <= control->max_depth;) { 214 | clock_t curr_time = clock(); 215 | memset(sPV, 0, SPVLEN); 216 | control->node_count = 0; 217 | control->seldepth = 0; 218 | 219 | eval = AlphaBeta(board, depth, alpha, beta, 0, control, 1, killers); 220 | if (control->stop && !control->ponder) { 221 | break; 222 | } 223 | pvlen = RetrievePV(board, iPV, depth+10); 224 | for (int i = 0; i < pvlen; i++) { 225 | MoveToAlgeb(iPV[i], str_mov); 226 | strcat(sPV, str_mov); 227 | } 228 | 229 | curr_time = (clock() - curr_time)/CPMS; 230 | if (curr_time) { 231 | nps = 1000*(control->node_count/curr_time); 232 | } 233 | if (eval > MATE_VALUE/2 && -eval > MATE_VALUE/2) { 234 | printf("info depth %u time %llu nodes %llu nps %llu score cp %i pv %s\n", 235 | depth, (unsigned long long)curr_time, control->node_count, nps, eval, sPV); 236 | } else if (-eval < MATE_VALUE/2) { 237 | printf("info depth %u time %llu nodes %llu nps %llu score mate %i pv %s\n", 238 | depth, (unsigned long long)curr_time, control->node_count, nps, (pvlen+1)/2, sPV); 239 | } else if (eval < MATE_VALUE/2) { 240 | printf("info depth %u time %llu nodes %llu nps %llu score mate %i pv %s\n", 241 | depth, (unsigned long long)curr_time, control->node_count, nps, -(pvlen+1)/2, sPV); 242 | } 243 | if (eval <= alpha || eval >= beta) { 244 | alpha = -INFINITE; 245 | beta = INFINITE; 246 | } else { 247 | if (3*curr_time > control->wish_time*CPMS - (clock()-control->init_time)) { 248 | control->stop = 1; 249 | } 250 | alpha = eval - ASP_WINDOW; 251 | beta = eval + ASP_WINDOW; 252 | depth++; 253 | } 254 | } 255 | control->stop = 1; 256 | if (DrawMove(board, control->best_move)) { 257 | printf("info draw\n"); 258 | } 259 | MoveToAlgeb(control->best_move, str_mov); 260 | printf("bestmove %s", str_mov); 261 | if (pvlen > 1 && iPV[0] == control->best_move) { 262 | MoveToAlgeb(iPV[1], str_mov); 263 | printf("ponder %s", str_mov); 264 | } 265 | printf("\n"); 266 | } 267 | -------------------------------------------------------------------------------- /board.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #ifndef BOARDH 32 | #define BOARDH 33 | 34 | /*Type to store moves: ORIG:bits 0-7, DEST:bits 8-15, PROMOTED and CASTLE RIGHTS:bits 16-19, 35 | CAPTURED:bits 20-23, PAWN_EP:bits 24-31 -> 0xEECPDDOO*/ 36 | typedef unsigned int MOVE; 37 | 38 | typedef unsigned char SQUARE; 39 | typedef unsigned char PIECE; 40 | typedef unsigned char COLOR; 41 | 42 | /*Zobrist keys*/ 43 | typedef unsigned long long KEY; 44 | 45 | #define SQSMASK(move) (move & 0xFFFF) 46 | #define ORIGMASK(move) (move & 0xFF) 47 | #define DESTMASK(move) ((move & 0xFFFF) >> 8) 48 | #define PROMMASK(move) ((move & 0xFFFFF) >> 16) 49 | #define CAPTMASK(move) ((move & 0xFFFFFF) >> 20) 50 | #define EPMASK(move) (move >> 24) 51 | 52 | /* white pieces have least significant bit = 1; black = 0.*/ 53 | /* K_CASTLE_RIGHT | Q_CASTLE_RIGHT = BOTH_CASTLES */ 54 | enum PIECES { EMPTY, 55 | K_CASTLE_RIGHT, 56 | B_PAWN, 57 | W_PAWN, 58 | B_KNIGHT, 59 | W_KNIGHT, 60 | B_BISHOP, 61 | W_BISHOP, 62 | B_ROOK, 63 | W_ROOK, 64 | B_QUEEN, 65 | W_QUEEN, 66 | B_KING, 67 | W_KING, 68 | Q_CASTLE_RIGHT, 69 | BOTH_CASTLES 70 | }; 71 | 72 | #define WHITE 1 73 | #define BLACK 0 74 | #define TURN_BLACK(piece) (piece & 0xE) 75 | #define TURN_WHITE(piece) (piece | 0x1) 76 | /* #define BLACK_TO_COLOR(blackpiece, piece) ((blackpiece)|(piece & 0x1)) */ 77 | #define GET_COLOR(piece) (piece & 0x1) 78 | 79 | #define FIRST_ROW 0x00 80 | #define SECOND_ROW 0x10 81 | #define THIRD_ROW 0x20 82 | #define FOURTH_ROW 0x30 83 | #define FIFTH_ROW 0x40 84 | #define SIXTH_ROW 0x50 85 | #define SEVENTH_ROW 0x60 86 | #define EIGHT_ROW 0x70 87 | 88 | #define A_COLUMN 0x00 89 | #define B_COLUMN 0x01 90 | #define C_COLUMN 0x02 91 | #define D_COLUMN 0x03 92 | #define E_COLUMN 0x04 93 | #define F_COLUMN 0x05 94 | #define G_COLUMN 0x06 95 | #define H_COLUMN 0x07 96 | 97 | #define COLUMN(square) ((square) & 0x0F) 98 | #define ROW(square) ((square) & 0xF0) 99 | #define SQUARE(row, column) (row + column) 100 | #define IN_BOARD(square) !((square) & 0x88) 101 | #define INVALID_SQ 0xFF 102 | #define NULL_MOVE 0xFFFF 103 | 104 | #define ROW8(sq) ((sq) >> 4) 105 | 106 | #define a1 0x00 107 | #define b1 0x01 108 | #define c1 0x02 109 | #define d1 0x03 110 | #define e1 0x04 111 | #define f1 0x05 112 | #define g1 0x06 113 | #define h1 0x07 114 | #define a8 0x70 115 | #define b8 0x71 116 | #define c8 0x72 117 | #define d8 0x73 118 | #define e8 0x74 119 | #define f8 0x75 120 | #define g8 0x76 121 | #define h8 0x77 122 | 123 | #define STARTPOS "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n" 124 | 125 | #define ROW_UP 0x10 126 | #define ROW_DOWN -0x10 127 | 128 | #define HISTLEN 500 129 | #define BOARDSIZE 0x80 130 | 131 | #define PAWN_VALUE 100 132 | #define KNIGHT_VALUE 300 133 | #define BISHOP_VALUE 310 134 | #define ROOK_VALUE 500 135 | #define QUEEN_VALUE 900 136 | 137 | #define STARTPAWNS 1600 138 | #define STARTMATERIAL 6240 139 | #include "hashtable.h" 140 | #include "pawns.h" 141 | 142 | typedef struct BOARD { 143 | PIECE squares[BOARDSIZE]; 144 | BITBOARD pawns[2]; 145 | COLOR white_to_move; 146 | /*Coordinates "behind" the pawn that can be captured en passant, as in FEN:*/ 147 | SQUARE en_passant; 148 | unsigned char wk_castle, wq_castle, bk_castle, bq_castle; 149 | unsigned char w_castled, b_castled; 150 | SQUARE wking_pos, bking_pos; 151 | int ply; 152 | int rev_plies[HISTLEN]; 153 | KEY zobrist_key; 154 | KEY zobrist_history[HISTLEN]; 155 | int piece_material[2]; 156 | int pawn_material[2]; 157 | int bishops[2]; 158 | } BOARD; 159 | 160 | typedef struct ZOBKEYS { 161 | KEY zob_pieces[16][BOARDSIZE]; 162 | KEY zob_enpass[BOARDSIZE]; 163 | KEY zob_castle[4]; 164 | KEY zob_side; 165 | } ZOBKEYS; 166 | 167 | extern ZOBKEYS zobkeys; 168 | 169 | KEY PolyglotKey(const BOARD*); 170 | 171 | void InitBoard(BOARD*); 172 | void InitZobrist(BOARD*); 173 | void InitMaterial(BOARD*); 174 | void PrintBoard(const BOARD*); 175 | int ReadFEN(const char*, BOARD*); 176 | 177 | int MoveGen(const BOARD*, MOVE*, char); 178 | int CaptureGen(const BOARD*, MOVE*); 179 | int GenerateWhiteCastle(const BOARD*, MOVE*, int); 180 | int GenerateBlackCastle(const BOARD*, MOVE*, int); 181 | 182 | typedef int (PIECEMOVES)(const BOARD*, SQUARE, MOVE*, int, char); 183 | 184 | PIECEMOVES WhitePawnMoves, BlackPawnMoves, NonSlidingMoves, SlidingMoves; 185 | 186 | static PIECEMOVES *const piece_moves[] = { 187 | 0, 188 | 0, 189 | &BlackPawnMoves, 190 | &WhitePawnMoves, 191 | &NonSlidingMoves, 192 | &NonSlidingMoves, 193 | &SlidingMoves, 194 | &SlidingMoves, 195 | &SlidingMoves, 196 | &SlidingMoves, 197 | &SlidingMoves, 198 | &SlidingMoves, 199 | &NonSlidingMoves, 200 | &NonSlidingMoves, 201 | }; 202 | 203 | #ifndef DELTAS 204 | #define DELTAS 205 | static const SQUARE w_pawn_capture[] = {0x0F, 0x11, 0}; 206 | static const SQUARE b_pawn_capture[] = {-0x0F, -0x11, 0}; 207 | static const SQUARE knight_delta[] = {0x21, 0x12, 0x1F, 0x0E, -0x12, -0x0E, -0x21, -0x1F, 0}; 208 | static const SQUARE bishop_delta[] = {0x11, 0x0F, -0x11, -0x0F, 0}; 209 | static const SQUARE rook_delta[] = {0x01, 0x10, -0x01, -0x10, 0}; 210 | static const SQUARE king_delta[] = {0x11, 0x0F, -0x11, -0x0F, 0x01, 0x10, -0x01, -0x10, 0}; 211 | #ifdef POINTDELTAS 212 | static const SQUARE *const deltas[] = { 213 | 0, 214 | 0, 215 | b_pawn_capture, 216 | w_pawn_capture, 217 | knight_delta, 218 | knight_delta, 219 | bishop_delta, 220 | bishop_delta, 221 | rook_delta, 222 | rook_delta, 223 | king_delta, 224 | king_delta, 225 | king_delta, 226 | king_delta, 227 | }; 228 | #else 229 | static const SQUARE deltas[][9] = { 230 | {0,0,0,0,0,0,0,0,0,}, 231 | {0,0,0,0,0,0,0,0,0,}, 232 | {-0x0F, -0x11,0,0,0,0,0,0,0}, 233 | {0x0F, 0x11,0,0,0,0,0,0,0}, 234 | {0x21, 0x12, 0x1F, 0x0E, -0x12, -0x0E, -0x21, -0x1F, 0}, 235 | {0x21, 0x12, 0x1F, 0x0E, -0x12, -0x0E, -0x21, -0x1F, 0}, 236 | {0x11, 0x0F, -0x11, -0x0F,0,0,0,0,0}, 237 | {0x11, 0x0F, -0x11, -0x0F,0,0,0,0,0}, 238 | {0x01, 0x10, -0x01, -0x10,0,0,0,0,0}, 239 | {0x01, 0x10, -0x01, -0x10,0,0,0,0,0}, 240 | {0x11, 0x0F, -0x11, -0x0F, 0x01, 0x10, -0x01, -0x10, 0}, 241 | {0x11, 0x0F, -0x11, -0x0F, 0x01, 0x10, -0x01, -0x10, 0}, 242 | {0x11, 0x0F, -0x11, -0x0F, 0x01, 0x10, -0x01, -0x10, 0}, 243 | {0x11, 0x0F, -0x11, -0x0F, 0x01, 0x10, -0x01, -0x10, 0} 244 | }; 245 | #endif 246 | 247 | static const SQUARE distance_to_center[] = { 248 | 6, 5, 4, 3, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 249 | 5, 4, 3, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 250 | 4, 3, 2, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 251 | 3, 2, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 252 | 3, 2, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 253 | 4, 3, 2, 1, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 254 | 5, 4, 3, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 255 | 6, 5, 4, 3, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0 256 | }; 257 | #endif 258 | 259 | void MakeMove(BOARD*, MOVE*); 260 | void Takeback(BOARD*, const MOVE); 261 | 262 | char IsLegal(BOARD*, MOVE*); 263 | int Perft(BOARD*, int); 264 | 265 | int SortMoves(BOARD*, MOVE*, int, MOVE[]); 266 | int FilterWinning(BOARD*, MOVE*, int); 267 | 268 | int LazyEval(const BOARD*); 269 | int StaticEval(const BOARD*); 270 | int Value(PIECE); 271 | 272 | int AttackingPieces(const BOARD*, SQUARE, COLOR, SQUARE*); 273 | 274 | inline int IsAttacked(const BOARD *board, SQUARE square, COLOR attacking_color) 275 | { 276 | return AttackingPieces(board, square, attacking_color, 0); 277 | } 278 | 279 | inline int WhiteInCheck(const BOARD *board) { 280 | return IsAttacked(board, board->wking_pos, BLACK); 281 | } 282 | 283 | inline int BlackInCheck(const BOARD *board) { 284 | return IsAttacked(board, board->bking_pos, WHITE); 285 | } 286 | 287 | inline int InCheck(const BOARD *board, SQUARE *attacking_sqs) { 288 | if (board->white_to_move) return AttackingPieces(board, board->wking_pos, BLACK, attacking_sqs); 289 | else return AttackingPieces(board, board->bking_pos, WHITE, attacking_sqs); 290 | } 291 | 292 | inline int LeftInCheck(const BOARD *board) { 293 | if (board->white_to_move) return IsAttacked(board, board->bking_pos, WHITE); 294 | else return IsAttacked(board, board->wking_pos, BLACK); 295 | } 296 | 297 | inline MOVE Move(PIECE piece, SQUARE dest, SQUARE orig) 298 | { 299 | return (piece << 16) | (dest << 8) | orig; 300 | } 301 | 302 | /*Game stage according to material present; 0 -> 1 as game progresses.*/ 303 | inline float PawnStage(const BOARD *board) 304 | { 305 | return 1.0f - (float)(board->pawn_material[0] + board->pawn_material[1])/STARTPAWNS; 306 | } 307 | 308 | inline float GameStage(const BOARD *board) 309 | { 310 | return 1.0f - (float)(board->piece_material[0] + board->piece_material[1])/STARTMATERIAL; 311 | } 312 | 313 | /* Some methods to convert coordinates to algebraic notation, and the other way round.*/ 314 | PIECE CharToPiece(const char); 315 | char PieceToChar(PIECE); 316 | char CharToCoordinate(const char); 317 | char RowCoordinateToChar(const char); 318 | char ColumnCoordinateToChar(const char); 319 | MOVE AlgebToMove(const char*); 320 | void MoveToAlgeb(const MOVE, char*); 321 | #endif 322 | 323 | -------------------------------------------------------------------------------- /movegen.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include "board.h" 32 | 33 | inline int WhitePawnMoves(const BOARD *board, SQUARE orig, MOVE *poss_moves, int nmoves, char noncaptures) 34 | { 35 | SQUARE dest = orig + ROW_UP; 36 | if (noncaptures && IN_BOARD(dest) && board->squares[dest] == EMPTY) { 37 | if (ROW(dest) == EIGHT_ROW) { /*Promotions.*/ 38 | if (poss_moves) poss_moves[nmoves] = Move(W_QUEEN, dest, orig); 39 | nmoves++; 40 | if (poss_moves) poss_moves[nmoves] = Move(W_KNIGHT, dest, orig); 41 | nmoves++; 42 | if (poss_moves) poss_moves[nmoves] = Move(W_ROOK, dest, orig); 43 | nmoves++; 44 | if (poss_moves) poss_moves[nmoves] = Move(W_BISHOP, dest, orig); 45 | nmoves++; 46 | } else { 47 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 48 | nmoves++; 49 | if (ROW(dest) == THIRD_ROW) { 50 | dest = dest + ROW_UP; 51 | if (IN_BOARD(dest) && board->squares[dest] == EMPTY) { 52 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 53 | nmoves++; 54 | } 55 | } 56 | } 57 | } 58 | for (int i = 0; w_pawn_capture[i]; i++) { 59 | dest = orig + w_pawn_capture[i]; 60 | if (IN_BOARD(dest)) { 61 | if (board->squares[dest] == EMPTY) { 62 | if (dest == board->en_passant) { /*Captures en Passant.*/ 63 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 64 | nmoves++; 65 | } 66 | } else if (GET_COLOR(board->squares[dest]) == BLACK) { 67 | if (ROW(dest) == EIGHT_ROW) { 68 | if (poss_moves) poss_moves[nmoves] = Move(W_QUEEN, dest, orig); 69 | nmoves++; 70 | if (poss_moves) poss_moves[nmoves] = Move(W_KNIGHT, dest, orig); 71 | nmoves++; 72 | if (poss_moves) poss_moves[nmoves] = Move(W_ROOK, dest, orig); 73 | nmoves++; 74 | if (poss_moves) poss_moves[nmoves] = Move(W_BISHOP, dest, orig); 75 | nmoves++; 76 | } else { 77 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 78 | nmoves++; 79 | } 80 | } 81 | } 82 | } 83 | return nmoves; 84 | } 85 | 86 | inline int BlackPawnMoves(const BOARD *board, SQUARE orig, MOVE *poss_moves, int nmoves, char noncaptures) 87 | { 88 | SQUARE dest = orig + ROW_DOWN; 89 | if (noncaptures && IN_BOARD(dest) && board->squares[dest] == EMPTY) { 90 | if (ROW(dest) == FIRST_ROW) { 91 | if (poss_moves) poss_moves[nmoves] = Move(B_QUEEN, dest, orig); 92 | nmoves++; 93 | if (poss_moves) poss_moves[nmoves] = Move(B_KNIGHT, dest, orig); 94 | nmoves++; 95 | if (poss_moves) poss_moves[nmoves] = Move(B_ROOK, dest, orig); 96 | nmoves++; 97 | if (poss_moves) poss_moves[nmoves] = Move(B_BISHOP, dest, orig); 98 | nmoves++; 99 | } else { 100 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 101 | nmoves++; 102 | if (ROW(dest) == SIXTH_ROW) { 103 | dest = dest + ROW_DOWN; 104 | if (IN_BOARD(dest)) { 105 | if (board->squares[dest] == EMPTY) { 106 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 107 | nmoves++; 108 | } 109 | } 110 | } 111 | } 112 | } 113 | for (int i = 0; b_pawn_capture[i]; i++) { 114 | dest = orig + b_pawn_capture[i]; 115 | if (IN_BOARD(dest)) { 116 | if (board->squares[dest] == EMPTY) { 117 | if (dest == board->en_passant) { 118 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 119 | nmoves++; 120 | } 121 | } else if (GET_COLOR(board->squares[dest])) { 122 | if (ROW(dest) == FIRST_ROW) { 123 | if (poss_moves) poss_moves[nmoves] = Move(B_QUEEN, dest, orig); 124 | nmoves++; 125 | if (poss_moves) poss_moves[nmoves] = Move(B_KNIGHT, dest, orig); 126 | nmoves++; 127 | if (poss_moves) poss_moves[nmoves] = Move(B_ROOK, dest, orig); 128 | nmoves++; 129 | if (poss_moves) poss_moves[nmoves] = Move(B_BISHOP, dest, orig); 130 | nmoves++; 131 | } else { 132 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 133 | nmoves++; 134 | } 135 | } 136 | } 137 | } 138 | return nmoves; 139 | } 140 | 141 | inline int SlidingMoves(const BOARD *board, SQUARE orig, MOVE *poss_moves, int nmoves, char noncaptures) 142 | { 143 | PIECE p = board->squares[orig]; 144 | for (const SQUARE *d = deltas[p]; *d; d++) { 145 | for (SQUARE dest = orig + *d; IN_BOARD(dest); dest += *d) { 146 | if (board->squares[dest] == EMPTY) { 147 | if (noncaptures) { 148 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 149 | nmoves++; 150 | } 151 | } else if (GET_COLOR(board->squares[dest]) != GET_COLOR(p)) { 152 | /*Different color Piece, capture, stop sliding.*/ 153 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 154 | nmoves++; 155 | break; 156 | } else break; /*same color piece, stop sliding.*/ 157 | } 158 | } 159 | return nmoves; 160 | } 161 | 162 | inline int NonSlidingMoves(const BOARD *board, SQUARE orig, MOVE *poss_moves, int nmoves, char noncaptures) 163 | { 164 | PIECE p = board->squares[orig]; 165 | for (const SQUARE *d = deltas[p]; *d; d++) { 166 | SQUARE dest = orig + *d; 167 | if (IN_BOARD(dest)) { 168 | if (board->squares[dest] == EMPTY) { 169 | if (noncaptures) { 170 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 171 | nmoves++; 172 | } 173 | } else if (GET_COLOR(board->squares[dest]) != GET_COLOR(p)) { 174 | if (poss_moves) poss_moves[nmoves] = Move(0, dest, orig); 175 | nmoves++; 176 | } 177 | } 178 | } 179 | return nmoves; 180 | } 181 | 182 | int GenerateWhiteCastle(const BOARD *board, MOVE *poss_moves, int nmoves) 183 | { 184 | if (board->wk_castle && board->squares[h1] == W_ROOK && board->squares[g1] == EMPTY 185 | && board->squares[f1] == EMPTY && !WhiteInCheck(board) 186 | && !IsAttacked(board, f1, BLACK)) { 187 | if (poss_moves) poss_moves[nmoves] = Move(0, g1, e1); 188 | nmoves++; 189 | } 190 | if (board->wq_castle && board->squares[a1] == W_ROOK &&board->squares[b1] == EMPTY 191 | && board->squares[c1] == EMPTY && board->squares[d1] == EMPTY 192 | && !WhiteInCheck(board) && !IsAttacked(board, d1, BLACK)) { 193 | if (poss_moves) poss_moves[nmoves] = Move(0, c1, e1); 194 | nmoves++; 195 | } 196 | return nmoves; 197 | } 198 | 199 | int GenerateBlackCastle(const BOARD *board, MOVE *poss_moves, int nmoves) 200 | { 201 | if (board->bk_castle && board->squares[h8] == B_ROOK &&board->squares[g8] == EMPTY 202 | && board->squares[f8] == EMPTY && !BlackInCheck(board) 203 | && !IsAttacked(board, f8, WHITE)) { 204 | if (poss_moves) poss_moves[nmoves] = Move(0, g8, e8); 205 | nmoves++; 206 | } 207 | if (board->bq_castle && board->squares[a8] == B_ROOK &&board->squares[b8] == EMPTY 208 | && board->squares[c8] == EMPTY && board->squares[d8] == EMPTY 209 | && !BlackInCheck(board) && !IsAttacked(board, d8, WHITE)) { 210 | if (poss_moves) poss_moves[nmoves] = Move(0, c8, e8); 211 | nmoves++; 212 | } 213 | return nmoves; 214 | } 215 | 216 | int CaptureGen(const BOARD *board, MOVE *poss_moves) 217 | { 218 | return MoveGen(board, poss_moves, 0); 219 | } 220 | #define JUMP 221 | #ifdef JUMP 222 | int MoveGen(const BOARD *board, MOVE *poss_moves, char noncaptures) 223 | { 224 | int nmoves = 0; 225 | for (SQUARE orig = a1; orig <= h8; orig++) { 226 | PIECE p = board->squares[orig]; 227 | if (p && GET_COLOR(p) == board->white_to_move) { 228 | nmoves = piece_moves[p](board, orig, poss_moves, nmoves, noncaptures); 229 | } 230 | if (COLUMN(orig) == H_COLUMN) orig += 8; 231 | } 232 | if (noncaptures) { 233 | if (board->white_to_move) nmoves = GenerateWhiteCastle(board, poss_moves, nmoves); 234 | else nmoves = GenerateBlackCastle(board, poss_moves, nmoves); 235 | } 236 | return nmoves; 237 | } 238 | #else 239 | int MoveGen(const BOARD *board, MOVE *poss_moves, char noncaptures) 240 | { 241 | int nmoves = 0; 242 | for (SQUARE orig = a1; orig <= h8; orig++) { 243 | PIECE p = board->squares[orig]; 244 | if (board->white_to_move) { 245 | switch(p) { 246 | case W_PAWN: 247 | nmoves = WhitePawnMoves(board, orig, poss_moves, nmoves, noncaptures); 248 | break; 249 | case W_KNIGHT: 250 | nmoves = NonSlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 251 | break; 252 | case W_BISHOP: 253 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 254 | break; 255 | case W_ROOK: 256 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 257 | break; 258 | case W_QUEEN: 259 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 260 | break; 261 | case W_KING: 262 | nmoves = NonSlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 263 | break; 264 | default: break; 265 | } 266 | if (noncaptures) nmoves = GenerateWhiteCastle(board, poss_moves, nmoves); 267 | } else { 268 | switch(p) { 269 | case B_PAWN: 270 | nmoves = BlackPawnMoves(board, orig, poss_moves, nmoves, noncaptures); 271 | break; 272 | case B_KNIGHT: 273 | nmoves = NonSlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 274 | break; 275 | case B_BISHOP: 276 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 277 | break; 278 | case B_ROOK: 279 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 280 | break; 281 | case B_QUEEN: 282 | nmoves = SlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 283 | break; 284 | case B_KING: 285 | nmoves = NonSlidingMoves(board, orig, poss_moves, nmoves, noncaptures); 286 | break; 287 | default: break; 288 | } 289 | if (noncaptures) nmoves = GenerateBlackCastle(board, poss_moves, nmoves); 290 | } 291 | if (COLUMN(orig) == H_COLUMN) orig += 8; 292 | } 293 | return nmoves; 294 | } 295 | #endif 296 | -------------------------------------------------------------------------------- /move.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | 31 | #include 32 | #include "board.h" 33 | 34 | inline void RememberCaptured(MOVE *move, PIECE captured) 35 | { 36 | /*captured piece: bits 20-23; 0 if EMPTY, o en passant capture:*/ 37 | *move |= (captured << 20); 38 | } 39 | 40 | inline void RememberEP(MOVE *move, SQUARE en_passant) 41 | { 42 | /*stores board->en_passant in order to undo.*/ 43 | *move |= (en_passant << 24); 44 | } 45 | 46 | inline void RememberCastleRight(MOVE *move, unsigned char rights) 47 | { 48 | /*Stores lost castle rights: 'bits promoted' set to 14 if long castle is lost, 1 if short, 15 if both.*/ 49 | *move |= (rights << 16); 50 | } 51 | 52 | static void RemovePiece(BOARD *board, SQUARE sq) 53 | { 54 | PIECE p = board->squares[sq]; 55 | board->zobrist_key ^= zobkeys.zob_pieces[p][sq]; 56 | if (p == W_PAWN || p == B_PAWN) { 57 | board->pawn_material[GET_COLOR(p)] -= Value(p); 58 | board->pawns[GET_COLOR(p)] = BitboardUnset(sq, board->pawns[GET_COLOR(p)]); 59 | } else if (p != EMPTY && p != W_KING && p != B_KING) { 60 | if (p == W_BISHOP || p == B_BISHOP) board->bishops[GET_COLOR(p)]--; 61 | board->piece_material[GET_COLOR(p)] -= Value(p); 62 | } 63 | board->squares[sq] = EMPTY; 64 | } 65 | 66 | static void DropPiece(BOARD *board, SQUARE sq, PIECE p) 67 | { 68 | board->zobrist_key ^= zobkeys.zob_pieces[p][sq]; 69 | if (p == W_PAWN || p == B_PAWN) { 70 | board->pawn_material[GET_COLOR(p)] += Value(p); 71 | board->pawns[GET_COLOR(p)] = BitboardSet(sq, board->pawns[GET_COLOR(p)]); 72 | } else if (p != EMPTY && p != W_KING && p != B_KING) { 73 | if (p == W_BISHOP || p == B_BISHOP) board->bishops[GET_COLOR(p)]++; 74 | board->piece_material[GET_COLOR(p)] += Value(p); 75 | } 76 | board->squares[sq] = p; 77 | } 78 | 79 | static inline void MoveWhitePawn(BOARD *board, SQUARE orig, SQUARE dest, const MOVE *curr_move) 80 | { 81 | PIECE promoted = PROMMASK(*curr_move); 82 | /*promoted does NOT store the correct color, because algebraic notation does not ensure Q != q.*/ 83 | 84 | if (ROW(dest) == EIGHT_ROW) { /*Promotion*/ 85 | DropPiece(board, dest, TURN_WHITE(promoted)); 86 | board->en_passant = INVALID_SQ; /*Invalid square: no pawn en passant.*/ 87 | } else { 88 | DropPiece(board, dest, W_PAWN); 89 | if (ROW(dest) == FOURTH_ROW && ROW(orig) == SECOND_ROW) { 90 | board->en_passant = dest + ROW_DOWN; 91 | } else { 92 | /*Remove en passant captured pawn (we won't later).*/ 93 | if (dest == board->en_passant) RemovePiece(board, dest + ROW_DOWN); 94 | board->en_passant = INVALID_SQ; 95 | } 96 | } 97 | board->rev_plies[board->ply] = 0; 98 | } 99 | 100 | static inline void MoveBlackPawn(BOARD *board, SQUARE orig, SQUARE dest, const MOVE *curr_move) 101 | { 102 | PIECE promoted = PROMMASK(*curr_move); 103 | if (ROW(dest) == FIRST_ROW) { 104 | DropPiece(board, dest, TURN_BLACK(promoted)); 105 | board->en_passant = INVALID_SQ; 106 | } else { 107 | DropPiece(board, dest, B_PAWN); 108 | if (ROW(dest) == FIFTH_ROW && ROW(orig) == SEVENTH_ROW) { 109 | board->en_passant = dest + ROW_UP; 110 | } else { 111 | if (dest == board->en_passant) RemovePiece(board, dest + ROW_UP); 112 | board->en_passant = INVALID_SQ; 113 | } 114 | } 115 | board->rev_plies[board->ply] = 0; 116 | } 117 | 118 | static inline void MoveWhiteKing(BOARD *board, SQUARE orig, SQUARE dest, MOVE *curr_move) 119 | { 120 | DropPiece(board, dest, W_KING); 121 | board->wking_pos = dest; 122 | if (orig == e1) { 123 | if (dest == g1) { /*Short castle*/ 124 | RemovePiece(board, h1); 125 | DropPiece(board, f1, W_ROOK); 126 | board->w_castled = 1; 127 | } 128 | if (dest == c1) { /*Long castle*/ 129 | RemovePiece(board, a1); 130 | DropPiece(board, d1, W_ROOK); 131 | board->w_castled = 1; 132 | } 133 | if (board->wq_castle) RememberCastleRight(curr_move, Q_CASTLE_RIGHT); 134 | if (board->wk_castle) RememberCastleRight(curr_move, K_CASTLE_RIGHT); 135 | } 136 | board->wk_castle = 0, board->wq_castle = 0; 137 | board->en_passant = INVALID_SQ; 138 | } 139 | 140 | static inline void MoveBlackKing(BOARD *board, SQUARE orig, SQUARE dest, MOVE *curr_move) 141 | { 142 | DropPiece(board, dest, B_KING); 143 | board->bking_pos = dest; 144 | if (orig == e8) { 145 | if (dest == g8) { 146 | RemovePiece(board, h8); 147 | DropPiece(board, f8, B_ROOK); 148 | board->b_castled = 1; 149 | } 150 | if (dest == c8) { 151 | RemovePiece(board, a8); 152 | DropPiece(board, d8, B_ROOK); 153 | board->b_castled = 1; 154 | } 155 | if (board->bq_castle) RememberCastleRight(curr_move, Q_CASTLE_RIGHT); 156 | if (board->bk_castle) RememberCastleRight(curr_move, K_CASTLE_RIGHT); 157 | } 158 | board->bk_castle = 0, board->bq_castle = 0; 159 | board->en_passant = INVALID_SQ; 160 | } 161 | 162 | static inline void MoveWhiteRook(BOARD *board, SQUARE orig, SQUARE dest, MOVE *curr_move) 163 | { 164 | if (board->wq_castle && orig == a1) { 165 | RememberCastleRight(curr_move, Q_CASTLE_RIGHT); 166 | board->wq_castle = 0; 167 | } 168 | if (board->wk_castle && orig == h1) { 169 | RememberCastleRight(curr_move, K_CASTLE_RIGHT); 170 | board->wk_castle = 0; 171 | } 172 | DropPiece(board, dest, W_ROOK); 173 | board->en_passant = INVALID_SQ; 174 | } 175 | 176 | static inline void MoveBlackRook(BOARD *board, SQUARE orig, SQUARE dest, MOVE *curr_move) 177 | { 178 | if (board->bq_castle && orig == a8) { 179 | RememberCastleRight(curr_move, Q_CASTLE_RIGHT); 180 | board->bq_castle = 0; 181 | } 182 | if (board->bk_castle && orig == h8) { 183 | RememberCastleRight(curr_move, K_CASTLE_RIGHT); 184 | board->bk_castle = 0; 185 | } 186 | DropPiece(board, dest, B_ROOK); 187 | board->en_passant = INVALID_SQ; 188 | } 189 | 190 | /* 191 | 'MakeMove()' modifies curr_move to update information depending on the position (captured, castle, EP...). 192 | 'MakeMove()' does NOT verify legality! 193 | */ 194 | void MakeMove(BOARD *board, MOVE *curr_move) 195 | { 196 | board->ply++; 197 | SQUARE orig = ORIGMASK(*curr_move); 198 | SQUARE dest = DESTMASK(*curr_move); 199 | 200 | RememberEP(curr_move, board->en_passant); 201 | 202 | /*don't update 'castle rights' or 'en passant' board->zobrist_key; useless?*/ 203 | /*if (IN_BOARD(board->en_passant)) board->zobrist_key ^= zobkeys.zob_enpass[board->en_passant];*/ 204 | 205 | if (board->squares[dest]) { 206 | RememberCaptured(curr_move, board->squares[dest]); 207 | RemovePiece(board, dest); 208 | board->rev_plies[board->ply] = 0; 209 | } else { 210 | board->rev_plies[board->ply] = board->rev_plies[board->ply-1]+1; 211 | } 212 | 213 | switch (board->squares[orig]) { 214 | case W_PAWN: 215 | MoveWhitePawn(board, orig, dest, curr_move); 216 | break; 217 | case B_PAWN: 218 | MoveBlackPawn(board, orig, dest, curr_move); 219 | break; 220 | case W_KING: 221 | MoveWhiteKing(board, orig, dest, curr_move); 222 | break; 223 | case B_KING: 224 | MoveBlackKing(board, orig, dest, curr_move); 225 | break; 226 | case W_ROOK: 227 | MoveWhiteRook(board, orig, dest, curr_move); 228 | break; 229 | case B_ROOK: 230 | MoveBlackRook(board, orig, dest, curr_move); 231 | break; 232 | default: 233 | DropPiece(board, dest, board->squares[orig]); 234 | board->en_passant = INVALID_SQ; 235 | break; 236 | } 237 | 238 | RemovePiece(board, orig); 239 | /*if (IN_BOARD(board->en_passant)) board->zobrist_key ^= zobkeys.zob_enpass[board->en_passant];*/ 240 | board->white_to_move = !(board->white_to_move); 241 | board->zobrist_key ^= zobkeys.zob_side; 242 | board->zobrist_history[board->ply] = board->zobrist_key; 243 | 244 | } 245 | 246 | 247 | /************************************************************************************** 248 | Takebacks. 249 | ***************************************************************************************/ 250 | 251 | static inline void TakebackWhiteKing(BOARD *board, SQUARE orig, SQUARE dest, PIECE promoted) 252 | { 253 | DropPiece(board, orig, W_KING); 254 | board->wking_pos = orig; 255 | if (orig == e1) { 256 | if (dest == g1) { /*short castle.*/ 257 | RemovePiece(board, f1); 258 | DropPiece(board, h1, W_ROOK); 259 | board->wk_castle = 1; 260 | board->w_castled = 0; 261 | } else if (dest == c1) { /*Long castle.*/ 262 | RemovePiece(board, d1); 263 | DropPiece(board, a1, W_ROOK); 264 | board->wq_castle = 1; 265 | board->w_castled = 0; 266 | } 267 | if (promoted == Q_CASTLE_RIGHT || promoted == BOTH_CASTLES) { 268 | board->wq_castle = 1; 269 | } 270 | if (promoted == K_CASTLE_RIGHT || promoted == BOTH_CASTLES) { 271 | board->wk_castle = 1; 272 | } 273 | } 274 | } 275 | 276 | static inline void TakebackBlackKing(BOARD *board, SQUARE orig, SQUARE dest, PIECE promoted) 277 | { 278 | DropPiece(board, orig, B_KING); 279 | board->bking_pos = orig; 280 | if (orig == e8) { 281 | if (dest == g8) { 282 | RemovePiece(board, f8); 283 | DropPiece(board, h8, B_ROOK); 284 | board->bk_castle = 1; 285 | board->b_castled = 0; 286 | } else if (dest == c8) { 287 | RemovePiece(board, d8); 288 | DropPiece(board, a8, B_ROOK); 289 | board->bq_castle = 1; 290 | board->b_castled = 0; 291 | } 292 | if (promoted == Q_CASTLE_RIGHT || promoted == BOTH_CASTLES) { 293 | board->bq_castle = 1; 294 | } 295 | if (promoted == K_CASTLE_RIGHT || promoted == BOTH_CASTLES) { 296 | board->bk_castle = 1; 297 | } 298 | } 299 | } 300 | 301 | static inline void TakebackWhiteRook(BOARD *board, SQUARE orig, SQUARE dest, PIECE promoted) 302 | { 303 | if (promoted) { 304 | if (promoted == Q_CASTLE_RIGHT) { 305 | board->wq_castle = 1; 306 | DropPiece(board, orig, W_ROOK); 307 | } else if (promoted == K_CASTLE_RIGHT) { 308 | board->wk_castle = 1; 309 | DropPiece(board, orig, W_ROOK); 310 | } else { 311 | DropPiece(board, orig, W_PAWN); 312 | } 313 | } else { 314 | DropPiece(board, orig, W_ROOK); 315 | } 316 | } 317 | 318 | static inline void TakebackBlackRook(BOARD *board, SQUARE orig, SQUARE dest, PIECE promoted) 319 | { 320 | if (promoted) { 321 | if (promoted == Q_CASTLE_RIGHT) { 322 | board->bq_castle = 1; 323 | DropPiece(board, orig, B_ROOK); 324 | } else if (promoted == K_CASTLE_RIGHT) { 325 | board->bk_castle = 1; 326 | DropPiece(board, orig, B_ROOK); 327 | } else { 328 | DropPiece(board, orig, B_PAWN); 329 | } 330 | } else { 331 | DropPiece(board, orig, B_ROOK); 332 | } 333 | } 334 | 335 | void Takeback(BOARD *board, const MOVE prev_move) 336 | { 337 | SQUARE orig = ORIGMASK(prev_move); 338 | SQUARE dest = DESTMASK(prev_move); 339 | PIECE promoted = PROMMASK(prev_move); 340 | PIECE captured = CAPTMASK(prev_move); 341 | 342 | /*if (IN_BOARD(board->en_passant)) board->zobrist_key ^= zobkeys.zob_enpass[board->en_passant];*/ 343 | board->en_passant = EPMASK(prev_move); 344 | /*if (IN_BOARD(board->en_passant)) board->zobrist_key ^= zobkeys.zob_enpass[board->en_passant];*/ 345 | board->white_to_move = !(board->white_to_move); 346 | board->zobrist_key ^= zobkeys.zob_side; 347 | 348 | switch(board->squares[dest]) { 349 | case W_PAWN: 350 | if (dest == board->en_passant) DropPiece(board, dest + ROW_DOWN, B_PAWN); 351 | DropPiece(board, orig, W_PAWN); 352 | break; 353 | case B_PAWN: 354 | if (dest == board->en_passant) DropPiece(board, dest + ROW_UP, W_PAWN); 355 | DropPiece(board, orig, B_PAWN); 356 | break; 357 | case W_KING: 358 | TakebackWhiteKing(board, orig, dest, promoted); 359 | break; 360 | case B_KING: 361 | TakebackBlackKing(board, orig, dest, promoted); 362 | break; 363 | case W_ROOK: 364 | TakebackWhiteRook(board, orig, dest, promoted); 365 | break; 366 | case B_ROOK: 367 | TakebackBlackRook(board, orig, dest, promoted); 368 | break; 369 | 370 | default: 371 | if (promoted) { 372 | /*drop a PAWN, same color as the piece's on dest.*/ 373 | DropPiece(board, orig, (GET_COLOR(board->squares[dest]) ? W_PAWN : B_PAWN)); 374 | } else { 375 | DropPiece(board, orig, board->squares[dest]); 376 | } 377 | break; 378 | } 379 | RemovePiece(board, dest); 380 | if (captured) DropPiece(board, dest, captured); 381 | board->ply--; 382 | } 383 | -------------------------------------------------------------------------------- /book.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014, Antonio Garro. * 3 | * All rights reserved * 4 | * * 5 | * Redistribution and use in source and binary forms, with or without modification, are * 6 | * permitted provided that the following conditions are met: * 7 | * * 8 | * 1. Redistributions of source code must retain the above copyright notice, this list * 9 | * of conditions and the following disclaimer. * 10 | * * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this * 12 | * list of conditions and the following disclaimer in the documentation and/or other * 13 | * materials provided with the distribution. * 14 | * * 15 | * 3. Neither the name of the copyright holder nor the names of its contributors may be * 16 | * used to endorse or promote products derived from this software without specific * 17 | * prior written permission. * 18 | * * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 29 | ***************************************************************************************/ 30 | /*************************************************************************************** 31 | * This file uses code released into the public domain by Michel Van den Bergh. * 32 | ***************************************************************************************/ 33 | 34 | #include 35 | #include 36 | #include 37 | #include "engine.h" 38 | #include "board.h" 39 | 40 | typedef unsigned char uint8; 41 | typedef unsigned short uint16; 42 | typedef unsigned int uint32; 43 | 44 | KEY Random64[781] = { 45 | 0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL, 0x9C15F73E62A76AE2ULL, 46 | 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL, 0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 47 | 0x0D7E765D58755C10ULL, 0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL, 48 | 0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL, 0x239F8B2D7FF719CCULL, 49 | 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL, 0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 50 | 0x82C7709E781EB7CCULL, 0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL, 51 | 0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL, 0x19F3C751D3E92AE1ULL, 52 | 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL, 0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 53 | 0x4C9F34427501B447ULL, 0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL, 54 | 0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL, 0x735E2B97A4C45A23ULL, 55 | 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL, 0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 56 | 0x9F74D14F7454A824ULL, 0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL, 57 | 0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL, 0x7EF48F2B83024E20ULL, 58 | 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL, 0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 59 | 0x42E240CB63689F2FULL, 0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL, 60 | 0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL, 0xEC16CA8AEA98AD76ULL, 61 | 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL, 0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 62 | 0x19FC8A768CF4B6D4ULL, 0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL, 63 | 0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL, 0x24C3C94DF9C8D3F6ULL, 64 | 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL, 0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 65 | 0x27E6AD7891165C3FULL, 0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL, 66 | 0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL, 0xF9B89D3E99A075C2ULL, 67 | 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL, 0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 68 | 0x87BF02C6B49E2AE9ULL, 0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL, 69 | 0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL, 0x5BFEA5B4712768E9ULL, 70 | 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL, 0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 71 | 0x2171E64683023A08ULL, 0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL, 72 | 0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL, 0x7B32F7D1E03680ECULL, 73 | 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL, 0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 74 | 0xCF464CEC899A2F8AULL, 0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL, 75 | 0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL, 0xA246637CFF328532ULL, 76 | 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL, 0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 77 | 0x56436C9FE1A1AA8DULL, 0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL, 78 | 0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL, 0xDD2C5BC84BC8D8FCULL, 79 | 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL, 0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 80 | 0xDEC468145B7605F6ULL, 0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL, 81 | 0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL, 0x21F08570F420E565ULL, 82 | 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL, 0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 83 | 0xC5CC1D89724FA456ULL, 0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL, 84 | 0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL, 0xAEF3AF4A563DFE43ULL, 85 | 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL, 0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 86 | 0xBCE5D2248682C115ULL, 0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL, 87 | 0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL, 0xB3819A42ABE61C87ULL, 88 | 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL, 0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 89 | 0xD7288E012AEB8D31ULL, 0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL, 90 | 0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL, 0x9AE182C8BC9474E8ULL, 91 | 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL, 0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 92 | 0xFC6A82D64B8655FBULL, 0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL, 93 | 0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL, 0x08BD35CC38336615ULL, 94 | 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL, 0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 95 | 0xD2B7ADEEDED1F73FULL, 0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL, 96 | 0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL, 0x4F2A5CB07F6A35B3ULL, 97 | 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL, 0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 98 | 0x39B0BF7DDE437BA2ULL, 0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL, 99 | 0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL, 0x7A1EE967D27579E2ULL, 100 | 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL, 0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 101 | 0xA90B24499FCFAFB1ULL, 0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL, 102 | 0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL, 0x9D1DFA2EFC557F73ULL, 103 | 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL, 0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 104 | 0x5A110C6058B920A0ULL, 0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL, 105 | 0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL, 0x881B82A13B51B9E2ULL, 106 | 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL, 0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 107 | 0xF678647E3519AC6EULL, 0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL, 108 | 0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL, 0x48CBFF086DDF285AULL, 109 | 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL, 0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 110 | 0x0CE2A38C344A6EEDULL, 0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL, 111 | 0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL, 0xD49503536ABCA345ULL, 112 | 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL, 0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 113 | 0xD60F6DCEDC314222ULL, 0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL, 114 | 0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL, 0xB344C470397BBA52ULL, 115 | 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL, 0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 116 | 0x7A13F18BBEDC4FF5ULL, 0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL, 117 | 0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL, 0x565C31F7DE89EA27ULL, 118 | 0x30F5611484119414ULL, 0xD873DB391292ED4FULL, 0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 119 | 0x947AE053EE56E63CULL, 0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL, 120 | 0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL, 0x35DD37D5871448AFULL, 121 | 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL, 0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 122 | 0x693501D628297551ULL, 0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL, 123 | 0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL, 0xE9F6760E32CD8021ULL, 124 | 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL, 0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 125 | 0x23B70EDB1955C4BFULL, 0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL, 126 | 0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL, 0x2FE4B17170E59750ULL, 127 | 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL, 0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 128 | 0x3E2B8BCBF016D66DULL, 0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL, 129 | 0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL, 0x18A6A990C8B35EBDULL, 130 | 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL, 0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 131 | 0xB7A0B174CFF6F36EULL, 0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL, 132 | 0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL, 0xDBC0D2B6AB90A559ULL, 133 | 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL, 0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 134 | 0x7B77497B32503B12ULL, 0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL, 135 | 0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL, 0xC678B6D860284A1CULL, 136 | 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL, 0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 137 | 0xE479EE5B9930578CULL, 0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL, 138 | 0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL, 0x7A76956C3EAFB413ULL, 139 | 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL, 0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 140 | 0x4DA8979A0041E8A9ULL, 0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL, 141 | 0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL, 0xCE68341F79893389ULL, 142 | 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL, 0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 143 | 0xDBC27AB5447822BFULL, 0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL, 144 | 0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL, 0xAF08DA9177DDA93DULL, 145 | 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL, 0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 146 | 0xF3B8B6675A6507FFULL, 0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL, 147 | 0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL, 0xE1925C71285279F5ULL, 148 | 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL, 0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 149 | 0x13328503DF48229FULL, 0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL, 150 | 0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL, 0x94EBC8ABCFB56DAEULL, 151 | 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL, 0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 152 | 0x51D2B1AB2DDFB636ULL, 0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL, 153 | 0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL, 0xAAC40A2703D9BEA0ULL, 154 | 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL, 0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 155 | 0x26E6DB8FFDF5ADFEULL, 0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL, 156 | 0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL, 0x8FE88B57305E2AB6ULL, 157 | 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL, 0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 158 | 0xB67C1FA481680AF8ULL, 0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL, 159 | 0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL, 0x53898E4C3910DA55ULL, 160 | 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL, 0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 161 | 0x66C1A2A1A60CD889ULL, 0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL, 162 | 0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL, 0x261E4E4C0A333A9DULL, 163 | 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL, 0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 164 | 0xCF3F4688801EB9AAULL, 0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL, 165 | 0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL, 0x258E5A80C7204C4BULL, 166 | 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL, 0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 167 | 0x2472F6207C2D0484ULL, 0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL, 168 | 0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL, 0x0B090A7560A968E3ULL, 169 | 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL, 0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 170 | 0x14A195640116F336ULL, 0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL, 171 | 0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL, 0xA1E9300CD8520548ULL, 172 | 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL, 0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 173 | 0x001F837CC7350524ULL, 0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL, 174 | 0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL, 0x1BDA0492E7E4586EULL, 175 | 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL, 0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 176 | 0x3871700761B3F743ULL, 0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL, 177 | 0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL, 0x0647DFEDCD894A29ULL, 178 | 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL, 0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 179 | 0xA2EBEE47E2FBFCE1ULL, 0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL, 180 | 0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL, 0x98F076A4F7A2322EULL, 181 | 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL, 0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 182 | 0x61BDD1307C66E300ULL, 0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL, 183 | 0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL, 0xD39BB9C3A48DB6CFULL, 184 | 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL, 0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 185 | 0x959F587D507A8359ULL, 0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL, 186 | 0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL, 0x7976033A39F7D952ULL, 187 | 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL, 0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 188 | 0x9D765E419FB69F6DULL, 0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL, 189 | 0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL, 0x08DD9BDFD96B9F63ULL, 190 | 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL, 0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 191 | 0xB0774D261CC609DBULL, 0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL, 192 | 0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL, 0x93B633ABFA3469F8ULL, 193 | 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL, 0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 194 | 0xD83CC2687A19255FULL, 0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL, 195 | 0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL, 0x944F6DE09134DFB6ULL, 196 | 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL, 0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 197 | 0x5092EF950A16DA0BULL, 0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL, 198 | 0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL, 0x50065E535A213CF6ULL, 199 | 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL, 0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 200 | 0x32AB0EDB696703D3ULL, 0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL, 201 | 0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL, 0xF43C732873F24C13ULL, 202 | 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL, 0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 203 | 0xCD04F3FF001A4778ULL, 0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL, 204 | 0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL, 0xB5B4071DBFC73A66ULL, 205 | 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL, 0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 206 | 0x1BDEA12E35F6A8C9ULL, 0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL, 207 | 0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL, 0x3FA9DDFB67E2F199ULL, 208 | 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL, 0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 209 | 0x81536D601170FC20ULL, 0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL, 210 | 0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL, 0xB49B52E587A1EE60ULL, 211 | 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL, 0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 212 | 0x24B33C9D7ED25117ULL, 0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL, 213 | 0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL, 0x8A328A1CEDFE552CULL, 214 | 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL, 0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 215 | 0xF6F7FD1431714200ULL, 0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL, 216 | 0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL, 0x4659D2B743848A2CULL, 217 | 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL, 0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 218 | 0xC7F6AA2DE59AEA61ULL, 0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL, 219 | 0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL, 0xD9E92AA246BF719EULL, 220 | 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL, 0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 221 | 0x55B6344CF97AAFAEULL, 0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL, 222 | 0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL, 0x2102AE466EBB1148ULL, 223 | 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL, 0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 224 | 0x1AF3DBE25D8F45DAULL, 0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL, 225 | 0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL, 0x522E23F3925E319EULL, 226 | 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL, 0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 227 | 0x7DC7785B8EFDFC80ULL, 0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL, 228 | 0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL, 0xD586BD01C5C217F6ULL, 229 | 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL, 0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 230 | 0x9E4C1269BAA4BF37ULL, 0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL, 231 | 0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL, 0x59300222B4561E00ULL, 232 | 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL, 0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 233 | 0x150F361DAB9DEC26ULL, 0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL, 234 | 0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL, 0x71F1CE2490D20B07ULL, 235 | 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL, 0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 236 | 0x5FA7867CAF35E149ULL, 0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL, 237 | 0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL, 0x1EF6E6DBB1961EC9ULL, 238 | 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL, 0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 239 | 0xCF3145DE0ADD4289ULL, 0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL, 240 | 0xF8D626AAAF278509ULL 241 | }; 242 | 243 | KEY *RandomPiece = Random64; 244 | KEY *RandomCastle = Random64+768; 245 | KEY *RandomEnPassant = Random64+772; 246 | KEY *RandomTurn = Random64+780; 247 | 248 | typedef struct { 249 | KEY key; 250 | uint16 move; 251 | uint16 weight; 252 | uint32 learn; 253 | } entry_t; 254 | 255 | KEY PolyglotKey(const BOARD *board) 256 | { 257 | KEY key = 0; 258 | for (int i = 0; i<128; i++) { 259 | int p = board->squares[i] - 2; 260 | if (IN_BOARD(i) && p >= 0) key ^= RandomPiece[64*p+8*(ROW8(i))+COLUMN(i)]; 261 | } 262 | 263 | if (board->wk_castle) key ^= RandomCastle[0]; 264 | if (board->wq_castle) key ^= RandomCastle[1]; 265 | if (board->bk_castle) key ^= RandomCastle[2]; 266 | if (board->bq_castle) key ^= RandomCastle[3]; 267 | 268 | if (IN_BOARD(board->en_passant)) { 269 | int r = ROW(board->en_passant); 270 | int c = COLUMN(board->en_passant); 271 | if (r == THIRD_ROW) { 272 | if ((IN_BOARD(r + ROW_UP + c + 1) && board->squares[r + ROW_UP + c + 1] == B_PAWN)|| 273 | (IN_BOARD(r + ROW_UP + c + 1) && board->squares[r + ROW_UP + c - 1] == B_PAWN)) { 274 | key ^= RandomEnPassant[c]; 275 | } 276 | } else { 277 | if ((IN_BOARD(r + ROW_DOWN + c + 1) && board->squares[r + ROW_DOWN + c + 1] == W_PAWN)|| 278 | (IN_BOARD(r + ROW_DOWN + c + 1) && board->squares[r + ROW_DOWN + c - 1] == W_PAWN)) { 279 | key ^= RandomEnPassant[c]; 280 | } 281 | } 282 | } 283 | if (board->white_to_move) key ^= RandomTurn[0]; 284 | return key; 285 | } 286 | 287 | #define MAX_MOVES 100 288 | 289 | entry_t entry_none = { 290 | 0, 0, 0, 0 291 | }; 292 | 293 | int PolyglotIntFromFile(FILE *f, int l, KEY *r) 294 | { 295 | for (int i = 0; i < l; i++) { 296 | int c = fgetc(f); 297 | if (c == EOF) { 298 | return 1; 299 | } 300 | (*r) = ((*r) << 8) + c; 301 | } 302 | return 0; 303 | } 304 | 305 | int PolyglotEntry(FILE *f, entry_t *entry) 306 | { 307 | KEY r = 0; 308 | if (PolyglotIntFromFile(f, 8, &r)) { 309 | return 1; 310 | } 311 | entry->key = r; 312 | if (PolyglotIntFromFile(f, 2, &r)) { 313 | return 1; 314 | } 315 | entry->move = r; 316 | if (PolyglotIntFromFile(f, 2, &r)) { 317 | return 1; 318 | } 319 | entry->weight = r; 320 | if (PolyglotIntFromFile(f, 4, &r)) { 321 | return 1; 322 | } 323 | entry->learn = r; 324 | return 0; 325 | } 326 | 327 | int PolyglotFindKey(FILE *f, KEY key, entry_t *entry) 328 | { 329 | entry_t first_entry = entry_none, last_entry, middle_entry; 330 | int first = -1; 331 | 332 | if (fseek(f, -16, SEEK_END)) { 333 | *entry = entry_none; 334 | entry->key = key + 1; //hack 335 | return -1; 336 | } 337 | int last = ftell(f)/16; 338 | PolyglotEntry(f, &last_entry); 339 | for (;;) { 340 | if (last-first == 1) { 341 | *entry = last_entry; 342 | return last; 343 | } 344 | int middle = (first+last)/2; 345 | fseek(f, 16*middle, SEEK_SET); 346 | PolyglotEntry(f, &middle_entry); 347 | if (key <= middle_entry.key) { 348 | last = middle; 349 | last_entry = middle_entry; 350 | } else { 351 | first = middle; 352 | first_entry = middle_entry; 353 | } 354 | } 355 | } 356 | 357 | void PolyglotMoveToString(char move_s[6], uint16 move) 358 | { 359 | char *promote_pieces = " nbrq"; 360 | int f = (move>>6)&077; 361 | int fr = (f>>3)&0x7; 362 | int ff = f&0x7; 363 | int t = move&077; 364 | int tr = (t>>3)&0x7; 365 | int tf = t&0x7; 366 | int p = (move>>12)&0x7; 367 | 368 | move_s[0] = ff+'a'; 369 | move_s[1] = fr+'1'; 370 | move_s[2] = tf+'a'; 371 | move_s[3] = tr+'1'; 372 | 373 | if (p) { 374 | move_s[4] = promote_pieces[p]; 375 | move_s[5] = '\0'; 376 | } else { 377 | move_s[4] = '\0'; 378 | } 379 | 380 | if (!strcmp(move_s, "e1h1")) { 381 | strcpy(move_s, "e1g1"); 382 | } else if (!strcmp(move_s, "e1a1")) { 383 | strcpy(move_s, "e1c1"); 384 | } else if (!strcmp(move_s, "e8h8")) { 385 | strcpy(move_s, "e8g8"); 386 | } else if (!strcmp(move_s, "e8a8")) { 387 | strcpy(move_s, "e8c8"); 388 | } 389 | } 390 | 391 | int PolyglotChooseMove(KEY key) 392 | { 393 | entry_t entry; 394 | entry_t entries[MAX_MOVES]; 395 | 396 | FILE *f = fopen("book.bin", "rb"); 397 | if (!f) { 398 | /* perror("book.bin"); */ 399 | return 0; 400 | } 401 | int offset = PolyglotFindKey(f,key,&entry); 402 | if (entry.key!=key) { 403 | fclose(f); 404 | return 0; 405 | } 406 | entries[0] = entry; 407 | int count = 1; 408 | 409 | fseek(f, 16*(offset+1), SEEK_SET); 410 | 411 | int total_weight = entry.weight; 412 | 413 | for (;;) { 414 | if (PolyglotEntry(f, &entry)) break; 415 | if (entry.key != key) break; 416 | 417 | if (count == MAX_MOVES) { 418 | fclose(f); 419 | return 0; 420 | } 421 | entries[count++] = entry; 422 | total_weight += entry.weight; 423 | } 424 | fclose(f); 425 | 426 | char move_s[6]; 427 | printf("info string book"); 428 | for (int i = 0; i < count; i++) { 429 | PolyglotMoveToString(move_s, entries[i].move); 430 | printf(" %s", move_s); 431 | } 432 | printf("\n"); 433 | srand(clock()); 434 | int r = rand()%total_weight; 435 | int i = 0; 436 | for (int w = entries[0].weight; w < r; i++) { 437 | w += entries[i+1].weight; 438 | } 439 | 440 | PolyglotMoveToString(move_s, entries[i].move); 441 | printf("bestmove %s\n", move_s); 442 | return 1; 443 | } 444 | -------------------------------------------------------------------------------- /uci.txt: -------------------------------------------------------------------------------- 1 | The UCI protocol was developed in 2000 by Rudolf Huber and Stefan Meyer-Kahlen (www.shredderchess.com) 2 | 3 | Description of the universal chess interface (UCI) April 2006 4 | ================================================================= 5 | 6 | * The specification is independent of the operating system. For Windows, 7 | the engine is a normal exe file, either a console or "real" windows application. 8 | 9 | * all communication is done via standard input and output with text commands, 10 | 11 | * The engine should boot and wait for input from the GUI, 12 | the engine should wait for the "isready" or "setoption" command to set up its internal parameters 13 | as the boot process should be as quick as possible. 14 | 15 | * the engine must always be able to process input from stdin, even while thinking. 16 | 17 | * all command strings the engine receives will end with '\n', 18 | also all commands the GUI receives should end with '\n', 19 | Note: '\n' can be 0x0d or 0x0a0d or any combination depending on your OS. 20 | If you use Engine and GUI in the same OS this should be no problem if you communicate in text mode, 21 | but be aware of this when for example running a Linux engine in a Windows GUI. 22 | 23 | * arbitrary white space between tokens is allowed 24 | Example: "debug on\n" and " debug on \n" and "\t debug \t \t\ton\t \n" 25 | all set the debug mode of the engine on. 26 | 27 | * The engine will always be in forced mode which means it should never start calculating 28 | or pondering without receiving a "go" command first. 29 | 30 | * Before the engine is asked to search on a position, there will always be a position command 31 | to tell the engine about the current position. 32 | 33 | * by default all the opening book handling is done by the GUI, 34 | but there is an option for the engine to use its own book ("OwnBook" option, see below) 35 | 36 | * if the engine or the GUI receives an unknown command or token it should just ignore it and try to 37 | parse the rest of the string in this line. 38 | Examples: "joho debug on\n" should switch the debug mode on given that joho is not defined, 39 | "debug joho on\n" will be undefined however. 40 | 41 | * if the engine receives a command which is not supposed to come, for example "stop" when the engine is 42 | not calculating, it should also just ignore it. 43 | 44 | 45 | Move format: 46 | ------------ 47 | 48 | The move format is in long algebraic notation. 49 | A nullmove from the Engine to the GUI should be sent as 0000. 50 | Examples: e2e4, e7e5, e1g1 (white short castling), e7e8q (for promotion) 51 | 52 | 53 | 54 | GUI to engine: 55 | -------------- 56 | 57 | These are all the command the engine gets from the interface. 58 | 59 | * uci 60 | tell engine to use the uci (universal chess interface), 61 | this will be sent once as a first command after program boot 62 | to tell the engine to switch to uci mode. 63 | After receiving the uci command the engine must identify itself with the "id" command 64 | and send the "option" commands to tell the GUI which engine settings the engine supports if any. 65 | After that the engine should send "uciok" to acknowledge the uci mode. 66 | If no uciok is sent within a certain time period, the engine task will be killed by the GUI. 67 | 68 | * debug [ on | off ] 69 | switch the debug mode of the engine on and off. 70 | In debug mode the engine should send additional infos to the GUI, e.g. with the "info string" command, 71 | to help debugging, e.g. the commands that the engine has received etc. 72 | This mode should be switched off by default and this command can be sent 73 | any time, also when the engine is thinking. 74 | 75 | * isready 76 | this is used to synchronize the engine with the GUI. When the GUI has sent a command or 77 | multiple commands that can take some time to complete, 78 | this command can be used to wait for the engine to be ready again or 79 | to ping the engine to find out if it is still alive. 80 | E.g. this should be sent after setting the path to the tablebases as this can take some time. 81 | This command is also required once before the engine is asked to do any search 82 | to wait for the engine to finish initializing. 83 | This command must always be answered with "readyok" and can be sent also when the engine is calculating 84 | in which case the engine should also immediately answer with "readyok" without stopping the search. 85 | 86 | * setoption name [value ] 87 | this is sent to the engine when the user wants to change the internal parameters 88 | of the engine. For the "button" type no value is needed. 89 | One string will be sent for each parameter and this will only be sent when the engine is waiting. 90 | The name and value of the option in should not be case sensitive and can inlude spaces. 91 | The substrings "value" and "name" should be avoided in and to allow unambiguous parsing, 92 | for example do not use = "draw value". 93 | Here are some strings for the example below: 94 | "setoption name Nullmove value true\n" 95 | "setoption name Selectivity value 3\n" 96 | "setoption name Style value Risky\n" 97 | "setoption name Clear Hash\n" 98 | "setoption name NalimovPath value c:\chess\tb\4;c:\chess\tb\5\n" 99 | 100 | * register 101 | this is the command to try to register an engine or to tell the engine that registration 102 | will be done later. This command should always be sent if the engine has sent "registration error" 103 | at program startup. 104 | The following tokens are allowed: 105 | * later 106 | the user doesn't want to register the engine now. 107 | * name 108 | the engine should be registered with the name 109 | * code 110 | the engine should be registered with the code 111 | Example: 112 | "register later" 113 | "register name Stefan MK code 4359874324" 114 | 115 | * ucinewgame 116 | this is sent to the engine when the next search (started with "position" and "go") will be from 117 | a different game. This can be a new game the engine should play or a new game it should analyse but 118 | also the next position from a testsuite with positions only. 119 | If the GUI hasn't sent a "ucinewgame" before the first "position" command, the engine shouldn't 120 | expect any further ucinewgame commands as the GUI is probably not supporting the ucinewgame command. 121 | So the engine should not rely on this command even though all new GUIs should support it. 122 | As the engine's reaction to "ucinewgame" can take some time the GUI should always send "isready" 123 | after "ucinewgame" to wait for the engine to finish its operation. 124 | 125 | * position [fen | startpos ] moves .... 126 | set up the position described in fenstring on the internal board and 127 | play the moves on the internal chess board. 128 | if the game was played from the start position the string "startpos" will be sent 129 | Note: no "new" command is needed. However, if this position is from a different game than 130 | the last position sent to the engine, the GUI should have sent a "ucinewgame" inbetween. 131 | 132 | * go 133 | start calculating on the current position set up with the "position" command. 134 | There are a number of commands that can follow this command, all will be sent in the same string. 135 | If one command is not sent its value should be interpreted as it would not influence the search. 136 | * searchmoves .... 137 | restrict search to this moves only 138 | Example: After "position startpos" and "go infinite searchmoves e2e4 d2d4" 139 | the engine should only search the two moves e2e4 and d2d4 in the initial position. 140 | * ponder 141 | start searching in pondering mode. 142 | Do not exit the search in ponder mode, even if it's mate! 143 | This means that the last move sent in in the position string is the ponder move. 144 | The engine can do what it wants to do, but after a "ponderhit" command 145 | it should execute the suggested move to ponder on. This means that the ponder move sent by 146 | the GUI can be interpreted as a recommendation about which move to ponder. However, if the 147 | engine decides to ponder on a different move, it should not display any mainlines as they are 148 | likely to be misinterpreted by the GUI because the GUI expects the engine to ponder 149 | on the suggested move. 150 | * wtime 151 | white has x msec left on the clock 152 | * btime 153 | black has x msec left on the clock 154 | * winc 155 | white increment per move in mseconds if x > 0 156 | * binc 157 | black increment per move in mseconds if x > 0 158 | * movestogo 159 | there are x moves to the next time control, 160 | this will only be sent if x > 0, 161 | if you don't get this and get the wtime and btime it's sudden death 162 | * depth 163 | search x plies only. 164 | * nodes 165 | search x nodes only, 166 | * mate 167 | search for a mate in x moves 168 | * movetime 169 | search exactly x mseconds 170 | * infinite 171 | search until the "stop" command. Do not exit the search without being told so in this mode! 172 | 173 | * stop 174 | stop calculating as soon as possible, 175 | don't forget the "bestmove" and possibly the "ponder" token when finishing the search 176 | 177 | * ponderhit 178 | the user has played the expected move. This will be sent if the engine was told to ponder on the same move 179 | the user has played. The engine should continue searching but switch from pondering to normal search. 180 | 181 | * quit 182 | quit the program as soon as possible 183 | 184 | 185 | Engine to GUI: 186 | -------------- 187 | 188 | * id 189 | * name 190 | this must be sent after receiving the "uci" command to identify the engine, 191 | e.g. "id name Shredder X.Y\n" 192 | * author 193 | this must be sent after receiving the "uci" command to identify the engine, 194 | e.g. "id author Stefan MK\n" 195 | 196 | * uciok 197 | Must be sent after the id and optional options to tell the GUI that the engine 198 | has sent all infos and is ready in uci mode. 199 | 200 | * readyok 201 | This must be sent when the engine has received an "isready" command and has 202 | processed all input and is ready to accept new commands now. 203 | It is usually sent after a command that can take some time to be able to wait for the engine, 204 | but it can be used anytime, even when the engine is searching, 205 | and must always be answered with "isready". 206 | 207 | * bestmove [ ponder ] 208 | the engine has stopped searching and found the move best in this position. 209 | the engine can send the move it likes to ponder on. The engine must not start pondering automatically. 210 | this command must always be sent if the engine stops searching, also in pondering mode if there is a 211 | "stop" command, so for every "go" command a "bestmove" command is needed! 212 | Directly before that the engine should send a final "info" command with the final search information, 213 | the the GUI has the complete statistics about the last search. 214 | 215 | * copyprotection 216 | this is needed for copyprotected engines. After the uciok command the engine can tell the GUI, 217 | that it will check the copy protection now. This is done by "copyprotection checking". 218 | If the check is ok the engine should send "copyprotection ok", otherwise "copyprotection error". 219 | If there is an error the engine should not function properly but should not quit alone. 220 | If the engine reports "copyprotection error" the GUI should not use this engine 221 | and display an error message instead! 222 | The code in the engine can look like this 223 | TellGUI("copyprotection checking\n"); 224 | // ... check the copy protection here ... 225 | if(ok) 226 | TellGUI("copyprotection ok\n"); 227 | else 228 | TellGUI("copyprotection error\n"); 229 | 230 | * registration 231 | this is needed for engines that need a username and/or a code to function with all features. 232 | Analog to the "copyprotection" command the engine can send "registration checking" 233 | after the uciok command followed by either "registration ok" or "registration error". 234 | Also after every attempt to register the engine it should answer with "registration checking" 235 | and then either "registration ok" or "registration error". 236 | In contrast to the "copyprotection" command, the GUI can use the engine after the engine has 237 | reported an error, but should inform the user that the engine is not properly registered 238 | and might not use all its features. 239 | In addition the GUI should offer to open a dialog to 240 | enable registration of the engine. To try to register an engine the GUI can send 241 | the "register" command. 242 | The GUI has to always answer with the "register" command if the engine sends "registration error" 243 | at engine startup (this can also be done with "register later") 244 | and tell the user somehow that the engine is not registered. 245 | This way the engine knows that the GUI can deal with the registration procedure and the user 246 | will be informed that the engine is not properly registered. 247 | 248 | * info 249 | the engine wants to send information to the GUI. This should be done whenever one of the info has changed. 250 | The engine can send only selected infos or multiple infos with one info command, 251 | e.g. "info currmove e2e4 currmovenumber 1" or 252 | "info depth 12 nodes 123456 nps 100000". 253 | Also all infos belonging to the pv should be sent together 254 | e.g. "info depth 2 score cp 214 time 1242 nodes 2124 nps 34928 pv e2e4 e7e5 g1f3" 255 | I suggest to start sending "currmove", "currmovenumber", "currline" and "refutation" only after one second 256 | to avoid too much traffic. 257 | Additional info: 258 | * depth 259 | search depth in plies 260 | * seldepth 261 | selective search depth in plies, 262 | if the engine sends seldepth there must also be a "depth" present in the same string. 263 | * time 264 | the time searched in ms, this should be sent together with the pv. 265 | * nodes 266 | x nodes searched, the engine should send this info regularly 267 | * pv ... 268 | the best line found 269 | * multipv 270 | this for the multi pv mode. 271 | for the best move/pv add "multipv 1" in the string when you send the pv. 272 | in k-best mode always send all k variants in k strings together. 273 | * score 274 | * cp 275 | the score from the engine's point of view in centipawns. 276 | * mate 277 | mate in y moves, not plies. 278 | If the engine is getting mated use negative values for y. 279 | * lowerbound 280 | the score is just a lower bound. 281 | * upperbound 282 | the score is just an upper bound. 283 | * currmove 284 | currently searching this move 285 | * currmovenumber 286 | currently searching move number x, for the first move x should be 1 not 0. 287 | * hashfull 288 | the hash is x permill full, the engine should send this info regularly 289 | * nps 290 | x nodes per second searched, the engine should send this info regularly 291 | * tbhits 292 | x positions where found in the endgame table bases 293 | * sbhits 294 | x positions where found in the shredder endgame databases 295 | * cpuload 296 | the cpu usage of the engine is x permill. 297 | * string 298 | any string str which will be displayed be the engine, 299 | if there is a string command the rest of the line will be interpreted as . 300 | * refutation ... 301 | move is refuted by the line ... , i can be any number >= 1. 302 | Example: after move d1h5 is searched, the engine can send 303 | "info refutation d1h5 g6h5" 304 | if g6h5 is the best answer after d1h5 or if g6h5 refutes the move d1h5. 305 | if there is no refutation for d1h5 found, the engine should just send 306 | "info refutation d1h5" 307 | The engine should only send this if the option "UCI_ShowRefutations" is set to true. 308 | * currline ... 309 | this is the current line the engine is calculating. is the number of the cpu if 310 | the engine is running on more than one cpu. = 1,2,3.... 311 | if the engine is just using one cpu, can be omitted. 312 | If is greater than 1, always send all k lines in k strings together. 313 | The engine should only send this if the option "UCI_ShowCurrLine" is set to true. 314 | 315 | 316 | * option 317 | This command tells the GUI which parameters can be changed in the engine. 318 | This should be sent once at engine startup after the "uci" and the "id" commands 319 | if any parameter can be changed in the engine. 320 | The GUI should parse this and build a dialog for the user to change the settings. 321 | Note that not every option needs to appear in this dialog as some options like 322 | "Ponder", "UCI_AnalyseMode", etc. are better handled elsewhere or are set automatically. 323 | If the user wants to change some settings, the GUI will send a "setoption" command to the engine. 324 | Note that the GUI need not send the setoption command when starting the engine for every option if 325 | it doesn't want to change the default value. 326 | For all allowed combinations see the examples below, 327 | as some combinations of this tokens don't make sense. 328 | One string will be sent for each parameter. 329 | * name 330 | The option has the name id. 331 | Certain options have a fixed value for , which means that the semantics of this option is fixed. 332 | Usually those options should not be displayed in the normal engine options window of the GUI but 333 | get a special treatment. "Pondering" for example should be set automatically when pondering is 334 | enabled or disabled in the GUI options. The same for "UCI_AnalyseMode" which should also be set 335 | automatically by the GUI. All those certain options have the prefix "UCI_" except for the 336 | first 6 options below. If the GUI gets an unknown Option with the prefix "UCI_", it should just 337 | ignore it and not display it in the engine's options dialog. 338 | * = Hash, type is spin 339 | the value in MB for memory for hash tables can be changed, 340 | this should be answered with the first "setoptions" command at program boot 341 | if the engine has sent the appropriate "option name Hash" command, 342 | which should be supported by all engines! 343 | So the engine should use a very small hash first as default. 344 | * = NalimovPath, type string 345 | this is the path on the hard disk to the Nalimov compressed format. 346 | Multiple directories can be concatenated with ";" 347 | * = NalimovCache, type spin 348 | this is the size in MB for the cache for the nalimov table bases 349 | These last two options should also be present in the initial options exchange dialog 350 | when the engine is booted if the engine supports it 351 | * = Ponder, type check 352 | this means that the engine is able to ponder. 353 | The GUI will send this whenever pondering is possible or not. 354 | Note: The engine should not start pondering on its own if this is enabled, this option is only 355 | needed because the engine might change its time management algorithm when pondering is allowed. 356 | * = OwnBook, type check 357 | this means that the engine has its own book which is accessed by the engine itself. 358 | if this is set, the engine takes care of the opening book and the GUI will never 359 | execute a move out of its book for the engine. If this is set to false by the GUI, 360 | the engine should not access its own book. 361 | * = MultiPV, type spin 362 | the engine supports multi best line or k-best mode. the default value is 1 363 | * = UCI_ShowCurrLine, type check, should be false by default, 364 | the engine can show the current line it is calculating. see "info currline" above. 365 | * = UCI_ShowRefutations, type check, should be false by default, 366 | the engine can show a move and its refutation in a line. see "info refutations" above. 367 | * = UCI_LimitStrength, type check, should be false by default, 368 | The engine is able to limit its strength to a specific Elo number, 369 | This should always be implemented together with "UCI_Elo". 370 | * = UCI_Elo, type spin 371 | The engine can limit its strength in Elo within this interval. 372 | If UCI_LimitStrength is set to false, this value should be ignored. 373 | If UCI_LimitStrength is set to true, the engine should play with this specific strength. 374 | This should always be implemented together with "UCI_LimitStrength". 375 | * = UCI_AnalyseMode, type check 376 | The engine wants to behave differently when analysing or playing a game. 377 | For example when playing it can use some kind of learning. 378 | This is set to false if the engine is playing a game, otherwise it is true. 379 | * = UCI_Opponent, type string 380 | With this command the GUI can send the name, title, elo and if the engine is playing a human 381 | or computer to the engine. 382 | The format of the string has to be [GM|IM|FM|WGM|WIM|none] [|none] [computer|human] 383 | Examples: 384 | "setoption name UCI_Opponent value GM 2800 human Gary Kasparov" 385 | "setoption name UCI_Opponent value none none computer Shredder" 386 | * = UCI_EngineAbout, type string 387 | With this command, the engine tells the GUI information about itself, for example a license text, 388 | usually it doesn't make sense that the GUI changes this text with the setoption command. 389 | Example: 390 | "option name UCI_EngineAbout type string default Shredder by Stefan Meyer-Kahlen, see www.shredderchess.com" 391 | * = UCI_ShredderbasesPath, type string 392 | this is either the path to the folder on the hard disk containing the Shredder endgame databases or 393 | the path and filename of one Shredder endgame datbase. 394 | * = UCI_SetPositionValue, type string 395 | the GUI can send this to the engine to tell the engine to use a certain value in centipawns from white's 396 | point of view if evaluating this specifix position. 397 | The string can have the formats: 398 | + | clear + | clearall 399 | 400 | * type 401 | The option has type t. 402 | There are 5 different types of options the engine can send 403 | * check 404 | a checkbox that can either be true or false 405 | * spin 406 | a spin wheel that can be an integer in a certain range 407 | * combo 408 | a combo box that can have different predefined strings as a value 409 | * button 410 | a button that can be pressed to send a command to the engine 411 | * string 412 | a text field that has a string as a value, 413 | an empty string has the value "" 414 | * default 415 | the default value of this parameter is x 416 | * min 417 | the minimum value of this parameter is x 418 | * max 419 | the maximum value of this parameter is x 420 | * var 421 | a predefined value of this parameter is x 422 | Examples: 423 | Here are 5 strings for each of the 5 possible types of options 424 | "option name Nullmove type check default true\n" 425 | "option name Selectivity type spin default 2 min 0 max 4\n" 426 | "option name Style type combo default Normal var Solid var Normal var Risky\n" 427 | "option name NalimovPath type string default c:\\n" 428 | "option name Clear Hash type button\n" 429 | 430 | 431 | 432 | Examples: 433 | --------- 434 | 435 | This is how the communication when the engine boots can look like: 436 | 437 | GUI engine 438 | 439 | // tell the engine to switch to UCI mode 440 | uci 441 | 442 | // engine identify 443 | id name Shredder 444 | id author Stefan MK 445 | 446 | // engine sends the options it can change 447 | // the engine can change the hash size from 1 to 128 MB 448 | option name Hash type spin default 1 min 1 max 128 449 | 450 | // the engine supports Nalimov endgame tablebases 451 | option name NalimovPath type string default 452 | option name NalimovCache type spin default 1 min 1 max 32 453 | 454 | // the engine can switch off Nullmove and set the playing style 455 | option name Nullmove type check default true 456 | option name Style type combo default Normal var Solid var Normal var Risky 457 | 458 | // the engine has sent all parameters and is ready 459 | uciok 460 | 461 | // Note: here the GUI can already send a "quit" command if it just wants to find out 462 | // details about the engine, so the engine should not initialize its internal 463 | // parameters before here. 464 | // now the GUI sets some values in the engine 465 | // set hash to 32 MB 466 | setoption name Hash value 32 467 | 468 | // init tbs 469 | setoption name NalimovCache value 1 470 | setoption name NalimovPath value d:\tb;c\tb 471 | 472 | // waiting for the engine to finish initializing 473 | // this command and the answer is required here! 474 | isready 475 | 476 | // engine has finished setting up the internal values 477 | readyok 478 | 479 | // now we are ready to go 480 | 481 | // if the GUI is supporting it, tell the engine that is is 482 | // searching on a game that it hasn't searched on before 483 | ucinewgame 484 | 485 | // if the engine supports the "UCI_AnalyseMode" option and the next search is supposed to 486 | // be an analysis, the GUI should set "UCI_AnalyseMode" to true if it is currently 487 | // set to false with this engine 488 | setoption name UCI_AnalyseMode value true 489 | 490 | // tell the engine to search infinite from the start position after 1.e4 e5 491 | position startpos moves e2e4 e7e5 492 | go infinite 493 | 494 | // the engine starts sending infos about the search to the GUI 495 | // (only some examples are given) 496 | 497 | 498 | info depth 1 seldepth 0 499 | info score cp 13 depth 1 nodes 13 time 15 pv f1b5 500 | info depth 2 seldepth 2 501 | info nps 15937 502 | info score cp 14 depth 2 nodes 255 time 15 pv f1c4 f8c5 503 | info depth 2 seldepth 7 nodes 255 504 | info depth 3 seldepth 7 505 | info nps 26437 506 | info score cp 20 depth 3 nodes 423 time 15 pv f1c4 g8f6 b1c3 507 | info nps 41562 508 | .... 509 | 510 | 511 | // here the user has seen enough and asks to stop the searching 512 | stop 513 | 514 | // the engine has finished searching and is sending the bestmove command 515 | // which is needed for every "go" command sent to tell the GUI 516 | // that the engine is ready again 517 | bestmove g1f3 ponder d8f6 518 | 519 | 520 | 521 | Chess960 522 | ======== 523 | 524 | UCI could easily be extended to support Chess960 (also known as Fischer Random Chess). 525 | 526 | The engine has to tell the GUI that it is capable of playing Chess960 and the GUI has to tell 527 | the engine that is should play according to the Chess960 rules. 528 | This is done by the special engine option UCI_Chess960. If the engine knows about Chess960 529 | it should send the command 'option name UCI_Chess960 type check default false' 530 | to the GUI at program startup. 531 | Whenever a Chess960 game is played, the GUI should set this engine option to 'true'. 532 | 533 | Castling is different in Chess960 and the white king move when castling short is not always e1g1. 534 | A king move could both be the castling king move or just a normal king move. 535 | This is why castling moves are sent in the form king "takes" his own rook. 536 | Example: e1h1 for the white short castle move in the normal chess start position. 537 | 538 | In EPD and FEN position strings specifying the castle rights with w and q is not enough as 539 | there could be more than one rook on the right or left side of the king. 540 | This is why the castle rights are specified with the letter of the castle rook's line. 541 | Upper case letters for white's and lower case letters for black's castling rights. 542 | Example: The normal chess position would be: 543 | rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w AHah - 544 | 545 | --------------------------------------------------------------------------------