├── LICENSE ├── README.md ├── readme.txt └── src ├── Makefile ├── adapter.cpp ├── adapter.h ├── attack.cpp ├── attack.h ├── board.cpp ├── board.h ├── book.cpp ├── book.h ├── book_make.cpp ├── book_make.h ├── book_merge.cpp ├── book_merge.h ├── colour.cpp ├── colour.h ├── engine.cpp ├── engine.h ├── epd.cpp ├── epd.h ├── fen.cpp ├── fen.h ├── game.cpp ├── game.h ├── hash.cpp ├── hash.h ├── io.cpp ├── io.h ├── line.cpp ├── line.h ├── list.cpp ├── list.h ├── main.cpp ├── main.h ├── move.cpp ├── move.h ├── move_do.cpp ├── move_do.h ├── move_gen.cpp ├── move_gen.h ├── move_legal.cpp ├── move_legal.h ├── option.cpp ├── option.h ├── parse.cpp ├── parse.h ├── pgn.cpp ├── pgn.h ├── piece.cpp ├── piece.h ├── posix.cpp ├── posix.h ├── random.cpp ├── random.h ├── san.cpp ├── san.h ├── search.cpp ├── search.h ├── square.cpp ├── square.h ├── uci.cpp ├── uci.h ├── util.cpp └── util.h /README.md: -------------------------------------------------------------------------------- 1 | polyglot 2 | ======== 3 | 4 | This is the open source polyglot chess opening book utility. I could not find this on github anywhere. Changes to support game indexing via leveldb have been added. 5 | Fabien Letouzey's original readme is in readme.txt. 6 | 7 | New Features: 8 | Builds a polyglot book but supports a leveldb position/game index as well. The leveldb option can be enabled with -leveldb 9 | 10 | Compile: 11 | 1. Install leveldb library (for mac OS X, brew install leveldb) 12 | 2. Execute make 13 | 14 | To build a simple opening book without a game index: 15 | 16 | 1. ./polyglot make-book -pgn \ -min-game 1 17 | 18 | To build a game index: 19 | 20 | 1. ./polyglot make-book -pgn \ -leveldb \ -min-game 1 21 | 22 | Builds a leveldb game number and header index. To access the indexes: 23 | 24 | 1. To access the game header index: 25 | The "game\_\\_data" key contains a pipe (|) separated list of values: 26 | 1. White player name 27 | 1. White player elo 28 | 1. Black player name 29 | 1. Black player elo 30 | 1. result (1-0, 0-1, 1/2-1/2 etc) 31 | 1. Date 32 | 1. Site 33 | 1. ECO 34 | 1. last\_stream\_position 35 | 1. Start FEN 36 | 1. Most of the fields are self-explanatory, the last\_stream\_position key contains the fseek position of the game (similar to the byte position of the game) in the PGN file. This is useful when wanting to quickly retrieve that game. To optimize retrieval, look up the last\_stream\_position of the next game and get all content between the fseeks. Note: The fseek content does not start with the opening "[", one needs to add in an opening "[" after the seek to work with PGN parsers. 37 | 38 | 2. Position index: 39 | To look up the games referenced by a position: 40 | 1. Compute the polyglot hash for a board position. Look up the position_hash as a key, a list of comma separated values containing game ids will be returned. Note: There will a trailing comma after the last game. The code reading the list of games has to ignore the last comma. 41 | 2. The games are not in any order. 42 | 43 | 3. Additional metadata can be accessed via: 44 | "total\_game\_count" contains the total number of games in the pgn file. 45 | "pgn\_filename" contains the name of the original PGN file. 46 | 47 | 4. Additional notes: 48 | 1. The leveldb game indexing is currently done in RAM. Later versions will be done without RAM. Thus, the RAM needed is similar to polyglot's typical RAM needs. 49 | 2. The kivy-chess github project currently uses the leveldb indexes. 50 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # files 3 | 4 | EXE = polyglot 5 | 6 | OBJS = adapter.o attack.o board.o book.o book_make.o book_merge.o colour.o \ 7 | engine.o epd.o fen.o game.o hash.o io.o line.o list.o main.o move.o \ 8 | move_do.o move_gen.o move_legal.o option.o parse.o pgn.o piece.o \ 9 | posix.o random.o san.o search.o square.o uci.o util.o 10 | 11 | PREFIX = /usr 12 | BINDIR = $(PREFIX)/bin 13 | 14 | # rules 15 | 16 | all: $(EXE) .depend 17 | 18 | clean: 19 | $(RM) *.o .depend 20 | 21 | install: all 22 | -mkdir -p -m 755 $(BINDIR) 23 | -cp $(EXE) $(BINDIR) 24 | -strip $(BINDIR)/$(EXE) 25 | 26 | uninstall: 27 | $(RM) $(BINDIR)/$(EXE) 28 | 29 | # general 30 | 31 | CXX = g++ 32 | CXXFLAGS = -pipe 33 | LDFLAGS = -lm 34 | LATE_LD_FLAGS = -lleveldb 35 | # C++ 36 | 37 | CXXFLAGS += -fno-exceptions -fno-rtti 38 | 39 | # optimisation 40 | 41 | CXXFLAGS += -O2 42 | CXXFLAGS += -fomit-frame-pointer 43 | 44 | # strip 45 | 46 | #LDFLAGS += -s 47 | 48 | # dependencies 49 | 50 | $(EXE): $(OBJS) 51 | $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LATE_LD_FLAGS) 52 | 53 | %.s: %.cpp 54 | $(CXX) -S $(CXXFLAGS) $< 55 | 56 | .depend: 57 | $(CXX) -MM $(OBJS:.o=.cpp) > $@ 58 | #include .depend 59 | -------------------------------------------------------------------------------- /src/adapter.h: -------------------------------------------------------------------------------- 1 | 2 | // adapter.h 3 | 4 | #ifndef ADAPTER_H 5 | #define ADAPTER_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern void adapter_loop (); 14 | 15 | #endif // !defined ADAPTER_H 16 | 17 | // end of adapter.h 18 | 19 | -------------------------------------------------------------------------------- /src/attack.cpp: -------------------------------------------------------------------------------- 1 | 2 | // attack.cpp 3 | 4 | // includes 5 | 6 | #include "board.h" 7 | #include "colour.h" 8 | #include "move.h" 9 | #include "attack.h" 10 | #include "piece.h" 11 | #include "util.h" 12 | 13 | // macros 14 | 15 | #define DELTA_INC(delta) (DeltaInc[128+(delta)]) 16 | #define DELTA_MASK(delta) (DeltaMask[128+(delta)]) 17 | 18 | // "constants" 19 | 20 | const sint8 KnightInc[8+1] = { 21 | -33, -31, -18, -14, +14, +18, +31, +33, 0 22 | }; 23 | 24 | const sint8 BishopInc[4+1] = { 25 | -17, -15, +15, +17, 0 26 | }; 27 | 28 | const sint8 RookInc[4+1] = { 29 | -16, -1, +1, +16, 0 30 | }; 31 | 32 | const sint8 QueenInc[8+1] = { 33 | -17, -16, -15, -1, +1, +15, +16, +17, 0 34 | }; 35 | 36 | const sint8 KingInc[8+1] = { 37 | -17, -16, -15, -1, +1, +15, +16, +17, 0 38 | }; 39 | 40 | // variables 41 | 42 | static sint8 DeltaInc[256]; 43 | static uint8 DeltaMask[256]; 44 | 45 | // prototypes 46 | 47 | static bool delta_is_ok (int delta); 48 | static bool inc_is_ok (int inc); 49 | 50 | // functions 51 | 52 | // attack_init() 53 | 54 | void attack_init() { 55 | 56 | int delta; 57 | int dir, inc, dist; 58 | 59 | for (delta = -128; delta < +128; delta++) { 60 | DeltaInc[128+delta] = IncNone; 61 | DeltaMask[128+delta] = 0; 62 | } 63 | 64 | DeltaMask[128-17] |= BlackPawnFlag; 65 | DeltaMask[128-15] |= BlackPawnFlag; 66 | 67 | DeltaMask[128+15] |= WhitePawnFlag; 68 | DeltaMask[128+17] |= WhitePawnFlag; 69 | 70 | for (dir = 0; dir < 8; dir++) { 71 | delta = KnightInc[dir]; 72 | ASSERT(delta_is_ok(delta)); 73 | DeltaMask[128+delta] |= KnightFlag; 74 | } 75 | 76 | for (dir = 0; dir < 4; dir++) { 77 | inc = BishopInc[dir]; 78 | ASSERT(inc!=IncNone); 79 | for (dist = 1; dist < 8; dist++) { 80 | delta = inc*dist; 81 | ASSERT(delta_is_ok(delta)); 82 | ASSERT(DeltaInc[128+delta]==IncNone); 83 | DeltaInc[128+delta] = inc; 84 | DeltaMask[128+delta] |= BishopFlag; 85 | } 86 | } 87 | 88 | for (dir = 0; dir < 4; dir++) { 89 | inc = RookInc[dir]; 90 | ASSERT(inc!=IncNone); 91 | for (dist = 1; dist < 8; dist++) { 92 | delta = inc*dist; 93 | ASSERT(delta_is_ok(delta)); 94 | ASSERT(DeltaInc[128+delta]==IncNone); 95 | DeltaInc[128+delta] = inc; 96 | DeltaMask[128+delta] |= RookFlag; 97 | } 98 | } 99 | 100 | for (dir = 0; dir < 8; dir++) { 101 | delta = KingInc[dir]; 102 | ASSERT(delta_is_ok(delta)); 103 | DeltaMask[128+delta] |= KingFlag; 104 | } 105 | } 106 | 107 | // delta_is_ok() 108 | 109 | static bool delta_is_ok(int delta) { 110 | 111 | if (delta < -119 || delta > +119) return false; 112 | 113 | return true; 114 | } 115 | 116 | // inc_is_ok() 117 | 118 | static bool inc_is_ok(int inc) { 119 | 120 | int dir; 121 | 122 | for (dir = 0; dir < 8; dir++) { 123 | if (KingInc[dir] == inc) return true; 124 | } 125 | 126 | return false; 127 | } 128 | 129 | // is_in_check() 130 | 131 | bool is_in_check(const board_t * board, int colour) { 132 | 133 | ASSERT(board_is_ok(board)); 134 | ASSERT(colour_is_ok(colour)); 135 | 136 | return is_attacked(board,king_pos(board,colour),colour_opp(colour)); 137 | } 138 | 139 | // is_attacked() 140 | 141 | bool is_attacked(const board_t * board, int to, int colour) { 142 | 143 | const uint8 * ptr; 144 | int from, piece; 145 | 146 | ASSERT(board_is_ok(board)); 147 | ASSERT(square_is_ok(to)); 148 | ASSERT(colour_is_ok(colour)); 149 | 150 | for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { 151 | 152 | piece = board->square[from]; 153 | ASSERT(colour_equal(piece,colour)); 154 | 155 | if (piece_attack(board,piece,from,to)) return true; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | // piece_attack() 162 | 163 | bool piece_attack(const board_t * board, int piece, int from, int to) { 164 | 165 | int delta; 166 | int inc, sq; 167 | 168 | ASSERT(board_is_ok(board)); 169 | ASSERT(piece_is_ok(piece)); 170 | ASSERT(square_is_ok(from)); 171 | ASSERT(square_is_ok(to)); 172 | 173 | delta = to - from; 174 | ASSERT(delta_is_ok(delta)); 175 | 176 | if ((piece & DELTA_MASK(delta)) == 0) return false; // no pseudo-attack 177 | 178 | if (!piece_is_slider(piece)) return true; 179 | 180 | inc = DELTA_INC(delta); 181 | ASSERT(inc_is_ok(inc)); 182 | 183 | for (sq = from+inc; sq != to; sq += inc) { 184 | ASSERT(square_is_ok(sq)); 185 | if (board->square[sq] != Empty) return false; // blocker 186 | } 187 | 188 | return true; 189 | } 190 | 191 | // is_pinned() 192 | 193 | bool is_pinned(const board_t * board, int from, int to, int colour) { 194 | 195 | int king; 196 | int inc; 197 | int sq, piece; 198 | 199 | ASSERT(board!=NULL); 200 | ASSERT(square_is_ok(from)); 201 | ASSERT(square_is_ok(to)); 202 | ASSERT(colour_is_ok(colour)); 203 | 204 | king = king_pos(board,colour); 205 | 206 | inc = DELTA_INC(king-from); 207 | if (inc == IncNone) return false; // not a line 208 | 209 | sq = from; 210 | do sq += inc; while (board->square[sq] == Empty); 211 | 212 | if (sq != king) return false; // blocker 213 | 214 | sq = from; 215 | do sq -= inc; while ((piece=board->square[sq]) == Empty); 216 | 217 | return square_is_ok(sq) 218 | && (piece & DELTA_MASK(king-sq)) != 0 219 | && piece_colour(piece) == colour_opp(colour) 220 | && DELTA_INC(king-to) != inc; 221 | } 222 | 223 | // end of attack.cpp 224 | 225 | -------------------------------------------------------------------------------- /src/attack.h: -------------------------------------------------------------------------------- 1 | 2 | // attack.h 3 | 4 | #ifndef ATTACK_H 5 | #define ATTACK_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // constants 13 | 14 | const int IncNone = 0; 15 | 16 | // "constants" 17 | 18 | extern const sint8 KnightInc[8+1]; 19 | extern const sint8 BishopInc[4+1]; 20 | extern const sint8 RookInc[4+1]; 21 | extern const sint8 QueenInc[8+1]; 22 | extern const sint8 KingInc[8+1]; 23 | 24 | // functions 25 | 26 | extern void attack_init (); 27 | 28 | extern bool is_in_check (const board_t * board, int colour); 29 | extern bool is_attacked (const board_t * board, int to, int colour); 30 | extern bool piece_attack (const board_t * board, int piece, int from, int to); 31 | 32 | extern bool is_pinned (const board_t * board, int from, int to, int colour); 33 | 34 | #endif // !defined ATTACK_H 35 | 36 | // end of attack.h 37 | 38 | -------------------------------------------------------------------------------- /src/board.cpp: -------------------------------------------------------------------------------- 1 | 2 | // board.cpp 3 | 4 | // includes 5 | 6 | #include 7 | 8 | #include "attack.h" 9 | #include "board.h" 10 | #include "colour.h" 11 | #include "fen.h" 12 | #include "hash.h" 13 | #include "list.h" 14 | #include "move.h" 15 | #include "move_do.h" 16 | #include "move_gen.h" 17 | #include "move_legal.h" 18 | #include "piece.h" 19 | #include "util.h" 20 | 21 | // constants 22 | 23 | static const bool UseSlowDebug = false; 24 | 25 | // functions 26 | 27 | // board_is_ok() 28 | 29 | bool board_is_ok(const board_t * board) { 30 | 31 | int sq, piece; 32 | int colour, pos; 33 | int king, rook; 34 | 35 | if (board == NULL) return false; 36 | 37 | // optional heavy DEBUG mode 38 | 39 | if (!UseSlowDebug) return true; 40 | 41 | // squares 42 | 43 | for (sq = 0; sq < SquareNb; sq++) { 44 | piece = board->square[sq]; 45 | if (square_is_ok(sq)) { 46 | pos = board->pos[sq]; 47 | if (piece == Empty) { 48 | if (pos != -1) return false; 49 | } else { 50 | if (pos < 0) return false; 51 | if (board->list[piece_colour(piece)][pos] != sq) return false; 52 | } 53 | } else { 54 | if (piece != Knight64) return false; 55 | } 56 | } 57 | 58 | // white piece list 59 | 60 | colour = White; 61 | pos = 0; 62 | 63 | if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return false; 64 | 65 | sq = board->list[colour][pos]; 66 | if (sq == SquareNone) return false; 67 | if (board->pos[sq] != pos) return false; 68 | piece = board->square[sq]; 69 | if (!colour_equal(piece,colour) || !piece_is_king(piece)) return false; 70 | 71 | for (pos++; pos < board->list_size[colour]; pos++) { 72 | sq = board->list[colour][pos]; 73 | if (sq == SquareNone) return false; 74 | if (board->pos[sq] != pos) return false; 75 | if (!colour_equal(board->square[sq],colour)) return false; 76 | } 77 | 78 | sq = board->list[colour][pos]; 79 | if (sq != SquareNone) return false; 80 | 81 | // black piece list 82 | 83 | colour = Black; 84 | pos = 0; 85 | 86 | if (board->list_size[colour] <= 0 || board->list_size[colour] > 16) return false; 87 | 88 | sq = board->list[colour][pos]; 89 | if (sq == SquareNone) return false; 90 | if (board->pos[sq] != pos) return false; 91 | piece = board->square[sq]; 92 | if (!colour_equal(piece,colour) || !piece_is_king(piece)) return false; 93 | 94 | for (pos++; pos < board->list_size[colour]; pos++) { 95 | sq = board->list[colour][pos]; 96 | if (sq == SquareNone) return false; 97 | if (board->pos[sq] != pos) return false; 98 | if (!colour_equal(board->square[sq],colour)) return false; 99 | } 100 | 101 | sq = board->list[colour][pos]; 102 | if (sq != SquareNone) return false; 103 | 104 | // TODO: material 105 | 106 | if (board->number[WhiteKing12] != 1) return false; 107 | if (board->number[BlackKing12] != 1) return false; 108 | 109 | if (!colour_is_ok(board->turn)) return false; 110 | 111 | // castling status 112 | 113 | if (board->castle[White][SideH] != SquareNone) { 114 | 115 | king = board->list[White][0]; 116 | if (king < A1 || king > H1) return false; 117 | if (board->square[king] != WhiteKing256) return false; 118 | 119 | rook = board->castle[White][SideH]; 120 | if (rook < A1 || rook > H1) return false; 121 | if (board->square[rook] != WhiteRook256) return false; 122 | 123 | if (rook <= king) return false; 124 | } 125 | 126 | if (board->castle[White][SideA] != SquareNone) { 127 | 128 | king = board->list[White][0]; 129 | if (king < A1 || king > H1) return false; 130 | if (board->square[king] != WhiteKing256) return false; 131 | 132 | rook = board->castle[White][SideA]; 133 | if (rook < A1 || rook > H1) return false; 134 | if (board->square[rook] != WhiteRook256) return false; 135 | 136 | if (rook >= king) return false; 137 | } 138 | 139 | if (board->castle[Black][SideH] != SquareNone) { 140 | 141 | king = board->list[Black][0]; 142 | if (king < A8 || king > H8) return false; 143 | if (board->square[king] != BlackKing256) return false; 144 | 145 | rook = board->castle[Black][SideH]; 146 | if (rook < A8 || rook > H8) return false; 147 | if (board->square[rook] != BlackRook256) return false; 148 | 149 | if (rook <= king) return false; 150 | } 151 | 152 | if (board->castle[Black][SideA] != SquareNone) { 153 | 154 | king = board->list[Black][0]; 155 | if (king < A8 || king > H8) return false; 156 | if (board->square[king] != BlackKing256) return false; 157 | 158 | rook = board->castle[Black][SideA]; 159 | if (rook < A8 || rook > H8) return false; 160 | if (board->square[rook] != BlackRook256) return false; 161 | 162 | if (rook >= king) return false; 163 | } 164 | 165 | return true; 166 | } 167 | 168 | // board_clear() 169 | 170 | void board_clear(board_t * board) { 171 | 172 | int file, rank, sq; 173 | int colour, pos; 174 | int piece; 175 | 176 | ASSERT(board!=NULL); 177 | 178 | // edge squares 179 | 180 | for (sq = 0; sq < SquareNb; sq++) { 181 | board->square[sq] = Knight64; // HACK: uncoloured knight 182 | board->pos[sq] = -1; 183 | } 184 | 185 | // empty squares 186 | 187 | for (rank = 0; rank < 8; rank++) { 188 | for (file = 0; file < 8; file++) { 189 | sq = square_make(file,rank); 190 | board->square[sq] = Empty; 191 | } 192 | } 193 | 194 | // piece lists 195 | 196 | for (colour = 0; colour < 3; colour++) { 197 | for (pos = 0; pos < 32; pos++) { // HACK 198 | board->list[colour][pos] = SquareNone; 199 | } 200 | board->list_size[colour] = 0; 201 | } 202 | 203 | // material 204 | 205 | for (piece = 0; piece < 12; piece++) { 206 | board->number[piece] = 0; 207 | } 208 | 209 | // rest 210 | 211 | board->turn = ColourNone; 212 | board->castle[White][SideH] = SquareNone; 213 | board->castle[White][SideA] = SquareNone; 214 | board->castle[Black][SideH] = SquareNone; 215 | board->castle[Black][SideA] = SquareNone; 216 | board->ep_square = SquareNone; 217 | 218 | board->ply_nb = 0; 219 | board->move_nb = 0; 220 | 221 | board->key = 0; 222 | } 223 | 224 | // board_start() 225 | 226 | void board_start(board_t * board) { 227 | 228 | ASSERT(board!=NULL); 229 | 230 | if (!board_from_fen(board,StartFen)) ASSERT(false); 231 | } 232 | 233 | // board_copy() 234 | 235 | void board_copy(board_t * dst, const board_t * src) { 236 | 237 | ASSERT(dst!=NULL); 238 | ASSERT(board_is_ok(src)); 239 | 240 | *dst = *src; 241 | } 242 | 243 | // board_equal() 244 | 245 | bool board_equal(const board_t * board_1, const board_t * board_2) { 246 | 247 | int sq_64, sq; 248 | 249 | ASSERT(board_is_ok(board_1)); 250 | ASSERT(board_is_ok(board_2)); 251 | 252 | // fast comparison 253 | 254 | if (board_1->key != board_2->key) return false; 255 | 256 | // slow comparison 257 | 258 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 259 | sq = square_from_64(sq_64); 260 | if (board_1->square[sq] != board_2->square[sq]) return false; 261 | } 262 | 263 | if (board_1->turn != board_2->turn) return false; 264 | if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return false; 265 | if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return false; 266 | if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return false; 267 | if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return false; 268 | if (board_1->ep_square != board_2->ep_square) return false; 269 | 270 | return true; 271 | } 272 | 273 | // board_init_list() 274 | 275 | void board_init_list(board_t * board) { 276 | 277 | int sq_64, sq, piece; 278 | int colour, pos; 279 | 280 | ASSERT(board!=NULL); 281 | 282 | // init 283 | 284 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 285 | sq = square_from_64(sq_64); 286 | board->pos[sq] = -1; 287 | } 288 | 289 | for (piece = 0; piece < 12; piece++) board->number[piece] = 0; 290 | 291 | // white piece list 292 | 293 | colour = White; 294 | pos = 0; 295 | 296 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 297 | sq = square_from_64(sq_64); 298 | piece = board->square[sq]; 299 | ASSERT(pos>=0&&pos<=16); 300 | if (colour_equal(piece,colour) && piece_is_king(piece)) { 301 | board->pos[sq] = pos; 302 | board->list[colour][pos] = sq; 303 | pos++; 304 | board->number[piece_to_12(piece)]++; 305 | } 306 | } 307 | ASSERT(pos==1); 308 | 309 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 310 | sq = square_from_64(sq_64); 311 | piece = board->square[sq]; 312 | ASSERT(pos>=0&&pos<=16); 313 | if (colour_equal(piece,colour) && !piece_is_king(piece)) { 314 | board->pos[sq] = pos; 315 | board->list[colour][pos] = sq; 316 | pos++; 317 | board->number[piece_to_12(piece)]++; 318 | } 319 | } 320 | 321 | ASSERT(pos>=1&&pos<=16); 322 | board->list[colour][pos] = SquareNone; 323 | board->list_size[colour] = pos; 324 | 325 | // black piece list 326 | 327 | colour = Black; 328 | pos = 0; 329 | 330 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 331 | sq = square_from_64(sq_64); 332 | piece = board->square[sq]; 333 | ASSERT(pos>=0&&pos<=16); 334 | if (colour_equal(piece,colour) && piece_is_king(piece)) { 335 | board->pos[sq] = pos; 336 | board->list[colour][pos] = sq; 337 | pos++; 338 | board->number[piece_to_12(piece)]++; 339 | } 340 | } 341 | ASSERT(pos==1); 342 | 343 | for (sq_64 = 0; sq_64 < 64; sq_64++) { 344 | sq = square_from_64(sq_64); 345 | piece = board->square[sq]; 346 | ASSERT(pos>=1&&pos<=16); 347 | if (colour_equal(piece,colour) && !piece_is_king(piece)) { 348 | board->pos[sq] = pos; 349 | board->list[colour][pos] = sq; 350 | pos++; 351 | board->number[piece_to_12(piece)]++; 352 | } 353 | } 354 | 355 | ASSERT(pos>=1&&pos<=16); 356 | board->list[colour][pos] = SquareNone; 357 | board->list_size[colour] = pos; 358 | 359 | // hash key 360 | 361 | board->key = hash_key(board); 362 | } 363 | 364 | // board_flags() 365 | 366 | int board_flags(const board_t * board) { 367 | 368 | int flags; 369 | 370 | flags = 0; 371 | 372 | if (board->castle[White][SideH] != SquareNone) flags |= 1 << 0; 373 | if (board->castle[White][SideA] != SquareNone) flags |= 1 << 1; 374 | if (board->castle[Black][SideH] != SquareNone) flags |= 1 << 2; 375 | if (board->castle[Black][SideA] != SquareNone) flags |= 1 << 3; 376 | 377 | return flags; 378 | } 379 | 380 | // board_can_play() 381 | 382 | bool board_can_play(const board_t * board) { 383 | 384 | list_t list[1]; 385 | int i, move; 386 | 387 | ASSERT(board_is_ok(board)); 388 | 389 | gen_moves(list,board); 390 | 391 | for (i = 0; i < list_size(list); i++) { 392 | move = list_move(list,i); 393 | if (pseudo_is_legal(move,board)) return true; 394 | } 395 | 396 | return false; // no legal move 397 | } 398 | 399 | // board_mobility() 400 | 401 | int board_mobility(const board_t * board) { 402 | 403 | list_t list[1]; 404 | 405 | ASSERT(board_is_ok(board)); 406 | 407 | gen_legal_moves(list,board); 408 | 409 | return list_size(list); 410 | } 411 | 412 | // board_is_check() 413 | 414 | bool board_is_check(const board_t * board) { 415 | 416 | ASSERT(board_is_ok(board)); 417 | 418 | return is_in_check(board,board->turn); 419 | } 420 | 421 | // board_is_mate() 422 | 423 | bool board_is_mate(const board_t * board) { 424 | 425 | ASSERT(board_is_ok(board)); 426 | 427 | if (!board_is_check(board)) return false; 428 | if (board_can_play(board)) return false; 429 | 430 | return true; 431 | } 432 | 433 | // board_is_stalemate() 434 | 435 | bool board_is_stalemate(const board_t * board) { 436 | 437 | ASSERT(board_is_ok(board)); 438 | 439 | if (board_is_check(board)) return false; 440 | if (board_can_play(board)) return false; 441 | 442 | return true; 443 | } 444 | 445 | // king_pos() 446 | 447 | int king_pos(const board_t * board, int colour) { 448 | 449 | ASSERT(board_is_ok(board)); 450 | ASSERT(colour_is_ok(colour)); 451 | 452 | return board->list[colour][0]; 453 | } 454 | 455 | // board_disp() 456 | 457 | void board_disp(const board_t * board) { 458 | 459 | int file, rank, sq; 460 | int piece, c; 461 | char fen[256]; 462 | 463 | ASSERT(board!=NULL); 464 | 465 | if (!board_to_fen(board,fen,256)) ASSERT(false); 466 | my_log("POLYGLOT %s\n",fen); 467 | my_log("POLYGLOT\n"); 468 | 469 | for (rank = 7; rank >= 0; rank--) { 470 | 471 | my_log("POLYGLOT "); 472 | 473 | for (file = 0; file < 8; file++) { 474 | 475 | sq = square_make(file,rank); 476 | piece = board->square[sq]; 477 | 478 | c = (piece != Empty) ? piece_to_char(piece) : '-'; 479 | my_log("%c ",c); 480 | } 481 | 482 | my_log("\n"); 483 | } 484 | 485 | my_log("POLYGLOT\n"); 486 | 487 | my_log("POLYGLOT %s to play\n",(colour_is_black(board->turn))?"black":"white"); 488 | my_log("POLYGLOT\n"); 489 | } 490 | 491 | // end of board.cpp 492 | 493 | -------------------------------------------------------------------------------- /src/board.h: -------------------------------------------------------------------------------- 1 | 2 | // board.h 3 | 4 | #ifndef BOARD_H 5 | #define BOARD_H 6 | 7 | // includes 8 | 9 | #include "colour.h" 10 | #include "square.h" 11 | #include "util.h" 12 | 13 | // constants 14 | 15 | const int Empty = 0; 16 | 17 | const int SideH = 0; 18 | const int SideA = 1; 19 | const int SideNb = 2; 20 | 21 | // types 22 | 23 | struct board_t { 24 | 25 | uint8 square[SquareNb]; 26 | sint8 pos[SquareNb]; 27 | 28 | uint8 list[ColourNb][32]; 29 | sint8 list_size[ColourNb]; 30 | 31 | sint8 number[12]; 32 | 33 | sint8 turn; 34 | uint8 castle[ColourNb][SideNb]; 35 | uint8 ep_square; 36 | 37 | sint16 ply_nb; 38 | sint16 move_nb; 39 | 40 | uint64 key; 41 | }; 42 | 43 | // functions 44 | 45 | extern bool board_is_ok (const board_t * board); 46 | 47 | extern void board_clear (board_t * board); 48 | extern void board_start (board_t * board); 49 | 50 | extern void board_copy (board_t * dst, const board_t * src); 51 | extern bool board_equal (const board_t * board_1, const board_t * board_2); 52 | 53 | extern void board_init_list (board_t * board); 54 | 55 | extern int board_flags (const board_t * board); 56 | 57 | extern bool board_can_play (const board_t * board); 58 | extern int board_mobility (const board_t * board); 59 | 60 | extern bool board_is_check (const board_t * board); 61 | extern bool board_is_mate (const board_t * board); 62 | extern bool board_is_stalemate (const board_t * board); 63 | 64 | extern int king_pos (const board_t * board, int colour); 65 | 66 | extern void board_disp (const board_t * board); 67 | 68 | #endif // !defined BOARD_H 69 | 70 | // end of board.h 71 | 72 | -------------------------------------------------------------------------------- /src/book.cpp: -------------------------------------------------------------------------------- 1 | 2 | // book.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "board.h" 12 | #include "book.h" 13 | #include "move.h" 14 | #include "move_legal.h" 15 | #include "san.h" 16 | #include "util.h" 17 | 18 | // types 19 | 20 | struct entry_t { 21 | uint64 key; 22 | uint16 move; 23 | uint16 count; 24 | uint16 n; 25 | uint16 sum; 26 | }; 27 | 28 | // variables 29 | 30 | static FILE * BookFile; 31 | static int BookSize; 32 | 33 | // prototypes 34 | 35 | static int find_pos (uint64 key); 36 | 37 | static void read_entry (entry_t * entry, int n); 38 | static void write_entry (const entry_t * entry, int n); 39 | 40 | static uint64 read_integer (FILE * file, int size); 41 | static void write_integer (FILE * file, int size, uint64 n); 42 | 43 | // functions 44 | 45 | // book_clear() 46 | 47 | void book_clear() { 48 | 49 | BookFile = NULL; 50 | BookSize = 0; 51 | } 52 | 53 | // book_open() 54 | 55 | void book_open(const char file_name[]) { 56 | 57 | ASSERT(file_name!=NULL); 58 | 59 | BookFile = fopen(file_name,"rb+"); 60 | if (BookFile == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); 61 | 62 | if (fseek(BookFile,0,SEEK_END) == -1) { 63 | my_fatal("book_open(): fseek(): %s\n",strerror(errno)); 64 | } 65 | 66 | BookSize = ftell(BookFile) / 16; 67 | if (BookSize == 0) my_fatal("book_open(): empty file\n"); 68 | } 69 | 70 | // book_close() 71 | 72 | void book_close() { 73 | 74 | if (fclose(BookFile) == EOF) { 75 | my_fatal("book_close(): fclose(): %s\n",strerror(errno)); 76 | } 77 | } 78 | 79 | // is_in_book() 80 | 81 | bool is_in_book(const board_t * board) { 82 | 83 | int pos; 84 | entry_t entry[1]; 85 | 86 | ASSERT(board!=NULL); 87 | 88 | for (pos = find_pos(board->key); pos < BookSize; pos++) { 89 | read_entry(entry,pos); 90 | if (entry->key == board->key) return true; 91 | } 92 | 93 | return false; 94 | } 95 | 96 | // book_move() 97 | 98 | int book_move(const board_t * board, bool random) { 99 | 100 | int best_move; 101 | int best_score; 102 | int pos; 103 | entry_t entry[1]; 104 | int move; 105 | int score; 106 | 107 | ASSERT(board!=NULL); 108 | ASSERT(random==true||random==false); 109 | 110 | best_move = MoveNone; 111 | best_score = 0; 112 | 113 | for (pos = find_pos(board->key); pos < BookSize; pos++) { 114 | 115 | read_entry(entry,pos); 116 | if (entry->key != board->key) break; 117 | 118 | move = entry->move; 119 | score = entry->count; 120 | 121 | if (move != MoveNone && move_is_legal(move,board)) { 122 | 123 | // pick this move? 124 | 125 | ASSERT(score>0); 126 | 127 | if (random) { 128 | best_score += score; 129 | if (my_random_int(best_score) < score) best_move = move; 130 | } else { 131 | if (score > best_score) { 132 | best_move = move; 133 | best_score = score; 134 | } 135 | } 136 | 137 | } else { 138 | 139 | ASSERT(false); 140 | } 141 | } 142 | 143 | return best_move; 144 | } 145 | 146 | // book_disp() 147 | 148 | void book_disp(const board_t * board) { 149 | 150 | int first_pos; 151 | int sum; 152 | int pos; 153 | entry_t entry[1]; 154 | int move; 155 | int score; 156 | char move_string[256]; 157 | 158 | ASSERT(board!=NULL); 159 | 160 | first_pos = find_pos(board->key); 161 | 162 | // sum 163 | 164 | sum = 0; 165 | 166 | for (pos = first_pos; pos < BookSize; pos++) { 167 | 168 | read_entry(entry,pos); 169 | if (entry->key != board->key) break; 170 | 171 | sum += entry->count; 172 | } 173 | 174 | // disp 175 | 176 | for (pos = first_pos; pos < BookSize; pos++) { 177 | 178 | read_entry(entry,pos); 179 | if (entry->key != board->key) break; 180 | 181 | move = entry->move; 182 | score = entry->count; 183 | 184 | if (score > 0 && move != MoveNone && move_is_legal(move,board)) { 185 | move_to_san(move,board,move_string,256); 186 | printf(" %s (%.0f%%)\n",move_string,(double(score)/double(sum))*100.0); 187 | } 188 | } 189 | 190 | printf("\n"); 191 | } 192 | 193 | // book_learn_move() 194 | 195 | void book_learn_move(const board_t * board, int move, int result) { 196 | 197 | int pos; 198 | entry_t entry[1]; 199 | 200 | ASSERT(board!=NULL); 201 | ASSERT(move_is_ok(move)); 202 | ASSERT(result>=-1&&result<=+1); 203 | 204 | ASSERT(move_is_legal(move,board)); 205 | 206 | for (pos = find_pos(board->key); pos < BookSize; pos++) { 207 | 208 | read_entry(entry,pos); 209 | if (entry->key != board->key) break; 210 | 211 | if (entry->move == move) { 212 | 213 | entry->n++; 214 | entry->sum += result+1; 215 | 216 | write_entry(entry,pos); 217 | 218 | break; 219 | } 220 | } 221 | } 222 | 223 | // book_flush() 224 | 225 | void book_flush() { 226 | 227 | if (fflush(BookFile) == EOF) { 228 | my_fatal("book_flush(): fflush(): %s\n",strerror(errno)); 229 | } 230 | } 231 | 232 | // find_pos() 233 | 234 | static int find_pos(uint64 key) { 235 | 236 | int left, right, mid; 237 | entry_t entry[1]; 238 | 239 | // binary search (finds the leftmost entry) 240 | 241 | left = 0; 242 | right = BookSize-1; 243 | 244 | ASSERT(left<=right); 245 | 246 | while (left < right) { 247 | 248 | mid = (left + right) / 2; 249 | ASSERT(mid>=left&&midkey) { 254 | right = mid; 255 | } else { 256 | left = mid+1; 257 | } 258 | } 259 | 260 | ASSERT(left==right); 261 | 262 | read_entry(entry,left); 263 | 264 | return (entry->key == key) ? left : BookSize; 265 | } 266 | 267 | // read_entry() 268 | 269 | static void read_entry(entry_t * entry, int n) { 270 | 271 | ASSERT(entry!=NULL); 272 | ASSERT(n>=0&&nkey = read_integer(BookFile,8); 279 | entry->move = read_integer(BookFile,2); 280 | entry->count = read_integer(BookFile,2); 281 | entry->n = read_integer(BookFile,2); 282 | entry->sum = read_integer(BookFile,2); 283 | } 284 | 285 | // write_entry() 286 | 287 | static void write_entry(const entry_t * entry, int n) { 288 | 289 | ASSERT(entry!=NULL); 290 | ASSERT(n>=0&&nkey); 297 | write_integer(BookFile,2,entry->move); 298 | write_integer(BookFile,2,entry->count); 299 | write_integer(BookFile,2,entry->n); 300 | write_integer(BookFile,2,entry->sum); 301 | } 302 | 303 | // read_integer() 304 | 305 | static uint64 read_integer(FILE * file, int size) { 306 | 307 | uint64 n; 308 | int i; 309 | int b; 310 | 311 | ASSERT(file!=NULL); 312 | ASSERT(size>0&&size<=8); 313 | 314 | n = 0; 315 | 316 | for (i = 0; i < size; i++) { 317 | 318 | b = fgetc(file); 319 | 320 | if (b == EOF) { 321 | if (feof(file)) { 322 | my_fatal("read_integer(): fgetc(): EOF reached\n"); 323 | } else { // error 324 | my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); 325 | } 326 | } 327 | 328 | ASSERT(b>=0&&b<256); 329 | n = (n << 8) | b; 330 | } 331 | 332 | return n; 333 | } 334 | 335 | // write_integer() 336 | 337 | static void write_integer(FILE * file, int size, uint64 n) { 338 | 339 | int i; 340 | int b; 341 | 342 | ASSERT(file!=NULL); 343 | ASSERT(size>0&&size<=8); 344 | ASSERT(size==8||n>>(size*8)==0); 345 | 346 | for (i = size-1; i >= 0; i--) { 347 | 348 | b = (n >> (i*8)) & 0xFF; 349 | ASSERT(b>=0&&b<256); 350 | 351 | if (fputc(b,file) == EOF) { 352 | my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); 353 | } 354 | } 355 | } 356 | 357 | // end of book.cpp 358 | 359 | -------------------------------------------------------------------------------- /src/book.h: -------------------------------------------------------------------------------- 1 | 2 | // book.h 3 | 4 | #ifndef BOOK_H 5 | #define BOOK_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // functions 13 | 14 | extern void book_clear (); 15 | 16 | extern void book_open (const char file_name[]); 17 | extern void book_close (); 18 | 19 | extern bool is_in_book (const board_t * board); 20 | extern int book_move (const board_t * board, bool random); 21 | extern void book_disp (const board_t * board); 22 | 23 | extern void book_learn_move (const board_t * board, int move, int result); 24 | extern void book_flush (); 25 | 26 | #endif // !defined BOOK_H 27 | 28 | // end of book.h 29 | 30 | -------------------------------------------------------------------------------- /src/book_make.h: -------------------------------------------------------------------------------- 1 | 2 | // book_make.h 3 | 4 | #ifndef BOOK_MAKE_H 5 | #define BOOK_MAKE_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | #include "leveldb/db.h" 11 | #include "leveldb/slice.h" 12 | 13 | 14 | 15 | // functions 16 | 17 | extern void book_make (int argc, char * argv[]); 18 | 19 | #endif // !defined BOOK_MAKE_H 20 | 21 | // end of book_make.h 22 | 23 | -------------------------------------------------------------------------------- /src/book_merge.cpp: -------------------------------------------------------------------------------- 1 | 2 | // book_merge.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "book_merge.h" 12 | #include "util.h" 13 | 14 | // types 15 | 16 | struct book_t { 17 | FILE * file; 18 | int size; 19 | }; 20 | 21 | struct entry_t { 22 | uint64 key; 23 | uint16 move; 24 | uint16 count; 25 | uint16 n; 26 | uint16 sum; 27 | }; 28 | 29 | // variables 30 | 31 | static book_t In1[1]; 32 | static book_t In2[1]; 33 | static book_t Out[1]; 34 | 35 | // prototypes 36 | 37 | static void book_clear (book_t * book); 38 | 39 | static void book_open (book_t * book, const char file_name[], const char mode[]); 40 | static void book_close (book_t * book); 41 | 42 | static bool read_entry (book_t * book, entry_t * entry, int n); 43 | static void write_entry (book_t * book, const entry_t * entry); 44 | 45 | static uint64 read_integer (FILE * file, int size); 46 | static void write_integer (FILE * file, int size, uint64 n); 47 | 48 | // functions 49 | 50 | // book_merge() 51 | 52 | void book_merge(int argc, char * argv[]) { 53 | 54 | int i; 55 | const char * in_file_1; 56 | const char * in_file_2; 57 | const char * out_file; 58 | int i1, i2; 59 | bool b1, b2; 60 | entry_t e1[1], e2[1]; 61 | int skip; 62 | 63 | in_file_1 = NULL; 64 | my_string_clear(&in_file_1); 65 | 66 | in_file_2 = NULL; 67 | my_string_clear(&in_file_2); 68 | 69 | out_file = NULL; 70 | my_string_set(&out_file,"out.bin"); 71 | 72 | for (i = 1; i < argc; i++) { 73 | 74 | if (false) { 75 | 76 | } else if (my_string_equal(argv[i],"merge-book")) { 77 | 78 | // skip 79 | 80 | } else if (my_string_equal(argv[i],"-in1")) { 81 | 82 | i++; 83 | if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); 84 | 85 | my_string_set(&in_file_1,argv[i]); 86 | 87 | } else if (my_string_equal(argv[i],"-in2")) { 88 | 89 | i++; 90 | if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); 91 | 92 | my_string_set(&in_file_2,argv[i]); 93 | 94 | } else if (my_string_equal(argv[i],"-out")) { 95 | 96 | i++; 97 | if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n"); 98 | 99 | my_string_set(&out_file,argv[i]); 100 | 101 | } else { 102 | 103 | my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]); 104 | } 105 | } 106 | 107 | book_clear(In1); 108 | book_clear(In2); 109 | book_clear(Out); 110 | 111 | book_open(In1,in_file_1,"rb"); 112 | book_open(In2,in_file_2,"rb"); 113 | book_open(Out,out_file,"wb"); 114 | 115 | skip = 0; 116 | 117 | i1 = 0; 118 | i2 = 0; 119 | 120 | while (true) { 121 | 122 | b1 = read_entry(In1,e1,i1); 123 | b2 = read_entry(In2,e2,i2); 124 | 125 | if (false) { 126 | 127 | } else if (!b1 && !b2) { 128 | 129 | break; 130 | 131 | } else if (b1 && !b2) { 132 | 133 | write_entry(Out,e1); 134 | i1++; 135 | 136 | } else if (b2 && !b1) { 137 | 138 | write_entry(Out,e2); 139 | i2++; 140 | 141 | } else { 142 | 143 | ASSERT(b1); 144 | ASSERT(b2); 145 | 146 | if (false) { 147 | } else if (e1->key < e2->key) { 148 | write_entry(Out,e1); 149 | i1++; 150 | } else if (e1->key > e2->key) { 151 | write_entry(Out,e2); 152 | i2++; 153 | } else { 154 | ASSERT(e1->key==e2->key); 155 | skip++; 156 | i2++; 157 | } 158 | } 159 | } 160 | 161 | book_close(In1); 162 | book_close(In2); 163 | book_close(Out); 164 | 165 | if (skip != 0) { 166 | printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y"); 167 | } 168 | 169 | printf("done!\n"); 170 | } 171 | 172 | // book_clear() 173 | 174 | static void book_clear(book_t * book) { 175 | 176 | ASSERT(book!=NULL); 177 | 178 | book->file = NULL; 179 | book->size = 0; 180 | } 181 | 182 | // book_open() 183 | 184 | static void book_open(book_t * book, const char file_name[], const char mode[]) { 185 | 186 | ASSERT(book!=NULL); 187 | ASSERT(file_name!=NULL); 188 | ASSERT(mode!=NULL); 189 | 190 | book->file = fopen(file_name,mode); 191 | if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno)); 192 | 193 | if (fseek(book->file,0,SEEK_END) == -1) { 194 | my_fatal("book_open(): fseek(): %s\n",strerror(errno)); 195 | } 196 | 197 | book->size = ftell(book->file) / 16; 198 | } 199 | 200 | // book_close() 201 | 202 | static void book_close(book_t * book) { 203 | 204 | ASSERT(book!=NULL); 205 | 206 | if (fclose(book->file) == EOF) { 207 | my_fatal("book_close(): fclose(): %s\n",strerror(errno)); 208 | } 209 | } 210 | 211 | // read_entry() 212 | 213 | static bool read_entry(book_t * book, entry_t * entry, int n) { 214 | 215 | ASSERT(book!=NULL); 216 | ASSERT(entry!=NULL); 217 | 218 | if (n < 0 || n >= book->size) return false; 219 | 220 | ASSERT(n>=0&&nsize); 221 | 222 | if (fseek(book->file,n*16,SEEK_SET) == -1) { 223 | my_fatal("read_entry(): fseek(): %s\n",strerror(errno)); 224 | } 225 | 226 | entry->key = read_integer(book->file,8); 227 | entry->move = read_integer(book->file,2); 228 | entry->count = read_integer(book->file,2); 229 | entry->n = read_integer(book->file,2); 230 | entry->sum = read_integer(book->file,2); 231 | 232 | return true; 233 | } 234 | 235 | // write_entry() 236 | 237 | static void write_entry(book_t * book, const entry_t * entry) { 238 | 239 | ASSERT(book!=NULL); 240 | ASSERT(entry!=NULL); 241 | 242 | write_integer(book->file,8,entry->key); 243 | write_integer(book->file,2,entry->move); 244 | write_integer(book->file,2,entry->count); 245 | write_integer(book->file,2,entry->n); 246 | write_integer(book->file,2,entry->sum); 247 | } 248 | 249 | // read_integer() 250 | 251 | static uint64 read_integer(FILE * file, int size) { 252 | 253 | uint64 n; 254 | int i; 255 | int b; 256 | 257 | ASSERT(file!=NULL); 258 | ASSERT(size>0&&size<=8); 259 | 260 | n = 0; 261 | 262 | for (i = 0; i < size; i++) { 263 | 264 | b = fgetc(file); 265 | 266 | if (b == EOF) { 267 | if (feof(file)) { 268 | my_fatal("read_integer(): fgetc(): EOF reached\n"); 269 | } else { // error 270 | my_fatal("read_integer(): fgetc(): %s\n",strerror(errno)); 271 | } 272 | } 273 | 274 | ASSERT(b>=0&&b<256); 275 | n = (n << 8) | b; 276 | } 277 | 278 | return n; 279 | } 280 | 281 | // write_integer() 282 | 283 | static void write_integer(FILE * file, int size, uint64 n) { 284 | 285 | int i; 286 | int b; 287 | 288 | ASSERT(file!=NULL); 289 | ASSERT(size>0&&size<=8); 290 | ASSERT(size==8||n>>(size*8)==0); 291 | 292 | for (i = size-1; i >= 0; i--) { 293 | 294 | b = (n >> (i*8)) & 0xFF; 295 | ASSERT(b>=0&&b<256); 296 | 297 | if (fputc(b,file) == EOF) { 298 | my_fatal("write_integer(): fputc(): %s\n",strerror(errno)); 299 | } 300 | } 301 | } 302 | 303 | // end of book_merge.cpp 304 | 305 | -------------------------------------------------------------------------------- /src/book_merge.h: -------------------------------------------------------------------------------- 1 | 2 | // book_merge.h 3 | 4 | #ifndef BOOK_MERGE_H 5 | #define BOOK_MERGE_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern void book_merge (int argc, char * argv[]); 14 | 15 | #endif // !defined BOOK_MERGE_H 16 | 17 | // end of book_merge.h 18 | 19 | -------------------------------------------------------------------------------- /src/colour.cpp: -------------------------------------------------------------------------------- 1 | 2 | // colour.cpp 3 | 4 | // includes 5 | 6 | #include "colour.h" 7 | #include "util.h" 8 | 9 | // functions 10 | 11 | // colour_is_ok() 12 | 13 | bool colour_is_ok(int colour) { 14 | 15 | return colour == Black || colour == White; 16 | } 17 | 18 | // colour_is_white() 19 | 20 | bool colour_is_white(int colour) { 21 | 22 | ASSERT(colour_is_ok(colour)); 23 | 24 | return colour == White; 25 | } 26 | 27 | // colour_is_black() 28 | 29 | bool colour_is_black(int colour) { 30 | 31 | ASSERT(colour_is_ok(colour)); 32 | 33 | return colour == Black; 34 | } 35 | 36 | // colour_equal() 37 | 38 | bool colour_equal(int colour_1, int colour_2) { 39 | 40 | ASSERT(colour_is_ok(colour_2)); 41 | 42 | return (colour_1 & colour_2) != 0; 43 | } 44 | 45 | // colour_opp() 46 | 47 | int colour_opp(int colour) { 48 | 49 | ASSERT(colour_is_ok(colour)); 50 | 51 | return colour ^ (BlackFlag^WhiteFlag); 52 | } 53 | 54 | // end of colour.cpp 55 | 56 | -------------------------------------------------------------------------------- /src/colour.h: -------------------------------------------------------------------------------- 1 | 2 | // colour.h 3 | 4 | #ifndef COLOUR_H 5 | #define COLOUR_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | const int BlackFlag = 1 << 0; 14 | const int WhiteFlag = 1 << 1; 15 | 16 | const int ColourNone = 0; 17 | const int Black = BlackFlag; 18 | const int White = WhiteFlag; 19 | const int ColourNb = 3; 20 | 21 | // functions 22 | 23 | extern bool colour_is_ok (int colour); 24 | 25 | extern bool colour_is_white (int colour); 26 | extern bool colour_is_black (int colour); 27 | extern bool colour_equal (int colour_1, int colour_2); 28 | 29 | extern int colour_opp (int colour); 30 | 31 | #endif // !defined COLOUR_H 32 | 33 | // end of colour.h 34 | 35 | -------------------------------------------------------------------------------- /src/engine.cpp: -------------------------------------------------------------------------------- 1 | 2 | // engine.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "engine.h" 16 | #include "io.h" 17 | #include "option.h" 18 | #include "util.h" 19 | 20 | // constants 21 | 22 | static const bool UseNice = false; 23 | 24 | static const int StringSize = 4096; 25 | 26 | // variables 27 | 28 | engine_t Engine[1]; 29 | 30 | // prototypes 31 | 32 | static void my_close (int fd); 33 | static void my_dup2 (int old_fd, int new_fd); 34 | 35 | // functions 36 | 37 | // engine_is_ok() 38 | 39 | bool engine_is_ok(const engine_t * engine) { 40 | 41 | if (engine == NULL) return false; 42 | 43 | if (!io_is_ok(engine->io)) return false; 44 | 45 | return true; 46 | } 47 | 48 | // engine_open() 49 | 50 | void engine_open(engine_t * engine) { 51 | 52 | const char * dir, * command; 53 | char string[StringSize]; 54 | int argc; 55 | char * ptr; 56 | char * argv[256]; 57 | int from_engine[2], to_engine[2]; 58 | pid_t pid; 59 | 60 | ASSERT(engine!=NULL); 61 | 62 | // init 63 | 64 | dir = option_get_string("EngineDir"); 65 | my_log("POLYGLOT Dir \"%s\"\n",dir); 66 | 67 | command = option_get_string("EngineCommand"); 68 | my_log("POLYGLOT Command \"%s\"\n",command); 69 | 70 | // parse the command line and create the argument list 71 | 72 | if (strlen(command) >= StringSize) my_fatal("engine_open(): buffer overflow\n"); 73 | strcpy(string,command); 74 | 75 | argc = 0; 76 | 77 | for (ptr = strtok(string," "); ptr != NULL; ptr = strtok(NULL," ")) { 78 | argv[argc++] = ptr; 79 | } 80 | 81 | argv[argc] = NULL; 82 | 83 | // create the pipes 84 | 85 | if (pipe(from_engine) == -1) { 86 | my_fatal("engine_open(): pipe(): %s\n",strerror(errno)); 87 | } 88 | 89 | if (pipe(to_engine) == -1) { 90 | my_fatal("engine_open(): pipe(): %s\n",strerror(errno)); 91 | } 92 | 93 | // create the child process 94 | 95 | pid = fork(); 96 | 97 | if (pid == -1) { 98 | 99 | my_fatal("engine_open(): fork(): %s\n",strerror(errno)); 100 | 101 | } else if (pid == 0) { 102 | 103 | // child = engine 104 | 105 | // close unused pipe descriptors to avoid deadlocks 106 | 107 | my_close(from_engine[0]); 108 | my_close(to_engine[1]); 109 | 110 | // attach the pipe to standard input 111 | 112 | my_dup2(to_engine[0],STDIN_FILENO); 113 | my_close(to_engine[0]); 114 | 115 | // attach the pipe to standard output 116 | 117 | my_dup2(from_engine[1],STDOUT_FILENO); 118 | my_close(from_engine[1]); 119 | 120 | // attach standard error to standard output 121 | 122 | my_dup2(STDOUT_FILENO,STDERR_FILENO); 123 | 124 | // set a low priority 125 | 126 | if (UseNice) nice(+20); 127 | 128 | // change the current directory 129 | 130 | if (dir[0] != '\0' && chdir(dir) == -1) { 131 | my_fatal("engine_open(): chdir(): %s\n",strerror(errno)); 132 | } 133 | 134 | // launch the new executable file 135 | 136 | execvp(argv[0],&argv[0]); 137 | 138 | // execvp() only returns when an error has occured 139 | 140 | my_fatal("engine_open(): execvp(): %s\n",strerror(errno)); 141 | 142 | } else { // pid > 0 143 | 144 | ASSERT(pid>0); 145 | 146 | // parent = PolyGlot 147 | 148 | // close unused pipe descriptors to avoid deadlocks 149 | 150 | my_close(from_engine[1]); 151 | my_close(to_engine[0]); 152 | 153 | // fill in the engine struct 154 | 155 | engine->io->in_fd = from_engine[0]; 156 | engine->io->out_fd = to_engine[1]; 157 | engine->io->name = "ENGINE"; 158 | 159 | io_init(engine->io); 160 | } 161 | } 162 | 163 | // engine_close() 164 | 165 | void engine_close(engine_t * engine) { 166 | 167 | ASSERT(engine_is_ok(engine)); 168 | 169 | io_close(engine->io); 170 | } 171 | 172 | // engine_get() 173 | 174 | void engine_get(engine_t * engine, char string[], int size) { 175 | 176 | ASSERT(engine_is_ok(engine)); 177 | ASSERT(string!=NULL); 178 | ASSERT(size>=256); 179 | 180 | while (!io_line_ready(engine->io)) { 181 | io_get_update(engine->io); 182 | } 183 | 184 | if (!io_get_line(engine->io,string,size)) { // EOF 185 | exit(EXIT_SUCCESS); 186 | } 187 | } 188 | 189 | // engine_send() 190 | 191 | void engine_send(engine_t * engine, const char format[], ...) { 192 | 193 | va_list arg_list; 194 | char string[StringSize]; 195 | 196 | ASSERT(engine_is_ok(engine)); 197 | ASSERT(format!=NULL); 198 | 199 | // format 200 | 201 | va_start(arg_list,format); 202 | vsprintf(string,format,arg_list); 203 | va_end(arg_list); 204 | 205 | // send 206 | 207 | io_send(engine->io,"%s",string); 208 | } 209 | 210 | // engine_send_queue() 211 | 212 | void engine_send_queue(engine_t * engine, const char format[], ...) { 213 | 214 | va_list arg_list; 215 | char string[StringSize]; 216 | 217 | ASSERT(engine_is_ok(engine)); 218 | ASSERT(format!=NULL); 219 | 220 | // format 221 | 222 | va_start(arg_list,format); 223 | vsprintf(string,format,arg_list); 224 | va_end(arg_list); 225 | 226 | // send 227 | 228 | io_send_queue(engine->io,"%s",string); 229 | } 230 | 231 | // my_close() 232 | 233 | static void my_close(int fd) { 234 | 235 | ASSERT(fd>=0); 236 | 237 | if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno)); 238 | } 239 | 240 | // my_dup2() 241 | 242 | static void my_dup2(int old_fd, int new_fd) { 243 | 244 | ASSERT(old_fd>=0); 245 | ASSERT(new_fd>=0); 246 | 247 | if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno)); 248 | } 249 | 250 | // end of engine.cpp 251 | 252 | -------------------------------------------------------------------------------- /src/engine.h: -------------------------------------------------------------------------------- 1 | 2 | // engine.h 3 | 4 | #ifndef ENGINE_H 5 | #define ENGINE_H 6 | 7 | // includes 8 | 9 | #include "io.h" 10 | #include "util.h" 11 | 12 | // types 13 | 14 | struct engine_t { 15 | io_t io[1]; 16 | }; 17 | 18 | // variables 19 | 20 | extern engine_t Engine[1]; 21 | 22 | // functions 23 | 24 | extern bool engine_is_ok (const engine_t * engine); 25 | 26 | extern void engine_open (engine_t * engine); 27 | extern void engine_close (engine_t * engine); 28 | 29 | extern void engine_get (engine_t * engine, char string[], int size); 30 | 31 | extern void engine_send (engine_t * engine, const char format[], ...); 32 | extern void engine_send_queue (engine_t * engine, const char format[], ...); 33 | 34 | #endif // !defined ENGINE_H 35 | 36 | // end of engine.h 37 | 38 | -------------------------------------------------------------------------------- /src/epd.cpp: -------------------------------------------------------------------------------- 1 | 2 | // epd.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "board.h" 12 | #include "engine.h" 13 | #include "epd.h" 14 | #include "fen.h" 15 | #include "line.h" 16 | #include "move.h" 17 | #include "move_legal.h" 18 | #include "option.h" 19 | #include "parse.h" 20 | #include "san.h" 21 | #include "uci.h" 22 | #include "util.h" 23 | 24 | // constants 25 | 26 | static const bool UseDebug = false; 27 | static const bool UseTrace = false; 28 | 29 | static const int StringSize = 4096; 30 | 31 | // variables 32 | 33 | static int MinDepth; 34 | static int MaxDepth; 35 | 36 | static double MaxTime; 37 | static double MinTime; 38 | 39 | static int DepthDelta; 40 | 41 | static int FirstMove; 42 | static int FirstDepth; 43 | static int FirstSelDepth; 44 | static int FirstScore; 45 | static double FirstTime; 46 | static sint64 FirstNodeNb; 47 | static move_t FirstPV[LineSize]; 48 | 49 | static int LastMove; 50 | static int LastDepth; 51 | static int LastSelDepth; 52 | static int LastScore; 53 | static double LastTime; 54 | static sint64 LastNodeNb; 55 | static move_t LastPV[LineSize]; 56 | 57 | // prototypes 58 | 59 | static void epd_test_file (const char file_name[]); 60 | 61 | static bool is_solution (int move, const board_t * board, const char bm[], const char am[]); 62 | static bool string_contain (const char string[], const char substring[]); 63 | 64 | static bool engine_step (); 65 | 66 | // functions 67 | 68 | // epd_test() 69 | 70 | void epd_test(int argc, char * argv[]) { 71 | 72 | int i; 73 | const char * epd_file; 74 | 75 | epd_file = NULL; 76 | my_string_set(&epd_file,"wac.epd"); 77 | 78 | MinDepth = 8; 79 | MaxDepth = 63; 80 | 81 | MinTime = 1.0; 82 | MaxTime = 5.0; 83 | 84 | DepthDelta = 3; 85 | 86 | for (i = 1; i < argc; i++) { 87 | 88 | if (false) { 89 | 90 | } else if (my_string_equal(argv[i],"epd-test")) { 91 | 92 | // skip 93 | 94 | } else if (my_string_equal(argv[i],"-epd")) { 95 | 96 | i++; 97 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 98 | 99 | my_string_set(&epd_file,argv[i]); 100 | 101 | } else if (my_string_equal(argv[i],"-min-depth")) { 102 | 103 | i++; 104 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 105 | 106 | MinDepth = atoi(argv[i]); 107 | 108 | } else if (my_string_equal(argv[i],"-max-depth")) { 109 | 110 | i++; 111 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 112 | 113 | MaxDepth = atoi(argv[i]); 114 | 115 | } else if (my_string_equal(argv[i],"-min-time")) { 116 | 117 | i++; 118 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 119 | 120 | MinTime = atof(argv[i]); 121 | 122 | } else if (my_string_equal(argv[i],"-max-time")) { 123 | 124 | i++; 125 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 126 | 127 | MaxTime = atof(argv[i]); 128 | 129 | } else if (my_string_equal(argv[i],"-depth-delta")) { 130 | 131 | i++; 132 | if (argv[i] == NULL) my_fatal("epd_test(): missing argument\n"); 133 | 134 | DepthDelta = atoi(argv[i]); 135 | 136 | } else { 137 | 138 | my_fatal("epd_test(): unknown option \"%s\"\n",argv[i]); 139 | } 140 | } 141 | 142 | epd_test_file(epd_file); 143 | } 144 | 145 | // epd_test_file() 146 | 147 | static void epd_test_file(const char file_name[]) { 148 | 149 | FILE * file; 150 | int hit, tot; 151 | char epd[StringSize]; 152 | char am[StringSize], bm[StringSize], id[StringSize]; 153 | board_t board[1]; 154 | char string[StringSize]; 155 | int move; 156 | char pv_string[StringSize]; 157 | bool correct; 158 | double depth_tot, time_tot, node_tot; 159 | 160 | ASSERT(file_name!=NULL); 161 | 162 | // init 163 | 164 | file = fopen(file_name,"r"); 165 | if (file == NULL) my_fatal("epd_test_file(): can't open file \"%s\": %s\n",file_name,strerror(errno)); 166 | 167 | hit = 0; 168 | tot = 0; 169 | 170 | depth_tot = 0.0; 171 | time_tot = 0.0; 172 | node_tot = 0.0; 173 | 174 | // loop 175 | 176 | while (my_file_read_line(file,epd,StringSize)) { 177 | 178 | if (UseTrace) printf("%s\n",epd); 179 | 180 | if (!epd_get_op(epd,"am",am,StringSize)) strcpy(am,""); 181 | if (!epd_get_op(epd,"bm",bm,StringSize)) strcpy(bm,""); 182 | if (!epd_get_op(epd,"id",id,StringSize)) strcpy(id,""); 183 | 184 | if (my_string_empty(am) && my_string_empty(bm)) { 185 | my_fatal("epd_test(): no am or bm field in EPD\n"); 186 | } 187 | 188 | // init 189 | 190 | uci_send_ucinewgame(Uci); 191 | uci_send_isready_sync(Uci); 192 | 193 | ASSERT(!Uci->searching); 194 | 195 | // position 196 | 197 | if (!board_from_fen(board,epd)) ASSERT(false); 198 | if (!board_to_fen(board,string,StringSize)) ASSERT(false); 199 | 200 | engine_send(Engine,"position fen %s",string); 201 | 202 | // search 203 | 204 | engine_send(Engine,"go movetime %.0f depth %d",MaxTime*1000.0,MaxDepth); 205 | // engine_send(Engine,"go infinite"); 206 | 207 | // engine data 208 | 209 | board_copy(Uci->board,board); 210 | 211 | uci_clear(Uci); 212 | Uci->searching = true; 213 | Uci->pending_nb++; 214 | 215 | FirstMove = MoveNone; 216 | FirstDepth = 0; 217 | FirstSelDepth = 0; 218 | FirstScore = 0; 219 | FirstTime = 0.0; 220 | FirstNodeNb = 0; 221 | line_clear(FirstPV); 222 | 223 | LastMove = MoveNone; 224 | LastDepth = 0; 225 | LastSelDepth = 0; 226 | LastScore = 0; 227 | LastTime = 0.0; 228 | LastNodeNb = 0; 229 | line_clear(LastPV); 230 | 231 | // parse engine output 232 | 233 | while (engine_step()) { 234 | 235 | // stop search? 236 | 237 | if (Uci->depth > MaxDepth 238 | || Uci->time >= MaxTime 239 | || (Uci->depth - FirstDepth >= DepthDelta 240 | && Uci->depth > MinDepth 241 | && Uci->time >= MinTime 242 | && is_solution(FirstMove,board,bm,am))) { 243 | engine_send(Engine,"stop"); 244 | } 245 | } 246 | 247 | move = FirstMove; 248 | correct = is_solution(move,board,bm,am); 249 | 250 | if (correct) hit++; 251 | tot++; 252 | 253 | if (correct) { 254 | depth_tot += double(FirstDepth); 255 | time_tot += FirstTime; 256 | node_tot += double(FirstNodeNb); 257 | } 258 | 259 | printf("%s %d %4d %4d",id,correct,hit,tot); 260 | 261 | if (!line_to_san(LastPV,Uci->board,pv_string,StringSize)) ASSERT(false); 262 | printf(" - %2d %6.2f %9lld %+6.2f %s\n",FirstDepth,FirstTime,FirstNodeNb,double(LastScore)/100.0,pv_string); 263 | } 264 | 265 | printf("%d/%d",hit,tot); 266 | 267 | if (hit != 0) { 268 | 269 | depth_tot /= double(hit); 270 | time_tot /= double(hit); 271 | node_tot /= double(hit); 272 | 273 | printf(" - %.1f %.2f %.0f",depth_tot,time_tot,node_tot); 274 | } 275 | 276 | printf("\n"); 277 | 278 | fclose(file); 279 | } 280 | 281 | // is_solution() 282 | 283 | static bool is_solution(int move, const board_t * board, const char bm[], const char am[]) { 284 | 285 | char move_string[256]; 286 | bool correct; 287 | 288 | ASSERT(move!=MoveNone); 289 | ASSERT(bm!=NULL); 290 | ASSERT(am!=NULL); 291 | 292 | if (!move_is_legal(move,board)) { 293 | board_disp(board); 294 | move_disp(move,board); 295 | printf("\n\n"); 296 | } 297 | 298 | ASSERT(move_is_legal(move,board)); 299 | 300 | if (!move_to_san(move,board,move_string,256)) ASSERT(false); 301 | 302 | correct = false; 303 | if (!my_string_empty(bm)) { 304 | correct = string_contain(bm,move_string); 305 | } else if (!my_string_empty(am)) { 306 | correct = !string_contain(am,move_string); 307 | } else { 308 | ASSERT(false); 309 | } 310 | 311 | return correct; 312 | } 313 | 314 | // epd_get_op() 315 | 316 | bool epd_get_op(const char record[], const char opcode[], char string[], int size) { 317 | 318 | char op[256]; 319 | int len; 320 | const char *p_start, *p_end; 321 | 322 | ASSERT(record!=NULL); 323 | ASSERT(opcode!=NULL); 324 | ASSERT(string!=NULL); 325 | ASSERT(size>0); 326 | 327 | // find the opcode 328 | 329 | sprintf(op," %s ",opcode); 330 | 331 | p_start = strstr(record,op); 332 | if (p_start == NULL) return false; 333 | 334 | // skip the opcode 335 | 336 | p_start += strlen(op); 337 | 338 | // find the end 339 | 340 | p_end = strchr(p_start,';'); 341 | if (p_end == NULL) return false; 342 | 343 | // calculate the length 344 | 345 | len = p_end - p_start; 346 | if (size < len+1) my_fatal("epd_get_op(): size < len+1\n"); 347 | 348 | strncpy(string,p_start,len); 349 | string[len] = '\0'; 350 | 351 | return true; 352 | } 353 | 354 | // string_contain() 355 | 356 | static bool string_contain(const char string[], const char substring[]) { 357 | 358 | char new_string[StringSize], *p; 359 | 360 | strcpy(new_string,string); // HACK 361 | 362 | for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { 363 | if (my_string_equal(p,substring)) return true; 364 | } 365 | 366 | return false; 367 | } 368 | 369 | // engine_step() 370 | 371 | static bool engine_step() { 372 | 373 | char string[StringSize]; 374 | int event; 375 | 376 | engine_get(Engine,string,StringSize); 377 | event = uci_parse(Uci,string); 378 | 379 | if ((event & EVENT_MOVE) != 0) { 380 | 381 | return false; 382 | } 383 | 384 | if ((event & EVENT_PV) != 0) { 385 | 386 | LastMove = Uci->best_pv[0]; 387 | LastDepth = Uci->best_depth; 388 | LastSelDepth = Uci->best_sel_depth; 389 | LastScore = Uci->best_score; 390 | LastTime = Uci->time; 391 | LastNodeNb = Uci->node_nb; 392 | line_copy(LastPV,Uci->best_pv); 393 | 394 | if (LastMove != FirstMove) { 395 | FirstMove = LastMove; 396 | FirstDepth = LastDepth; 397 | FirstSelDepth = LastSelDepth; 398 | FirstScore = LastScore; 399 | FirstTime = LastTime; 400 | FirstNodeNb = LastNodeNb; 401 | line_copy(FirstPV,LastPV); 402 | } 403 | } 404 | 405 | return true; 406 | } 407 | 408 | // end of epd.cpp 409 | 410 | -------------------------------------------------------------------------------- /src/epd.h: -------------------------------------------------------------------------------- 1 | 2 | // epd.h 3 | 4 | #ifndef EPD_H 5 | #define EPD_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern void epd_test (int argc, char * argv[]); 14 | 15 | extern bool epd_get_op (const char record[], const char opcode[], char string[], int size); 16 | 17 | #endif // !defined EPD_H 18 | 19 | // end of epd.h 20 | 21 | -------------------------------------------------------------------------------- /src/fen.cpp: -------------------------------------------------------------------------------- 1 | 2 | // fen.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "board.h" 11 | #include "colour.h" 12 | #include "fen.h" 13 | #include "option.h" 14 | #include "piece.h" 15 | #include "square.h" 16 | #include "util.h" 17 | 18 | // "constants" 19 | 20 | // const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1"; 21 | const char * StartFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; 22 | 23 | // variables 24 | 25 | static const bool Strict = false; 26 | 27 | // functions 28 | 29 | // board_from_fen() 30 | 31 | bool board_from_fen(board_t * board, const char string[]) { 32 | 33 | int pos; 34 | int file, rank, sq; 35 | int c; 36 | int i, len; 37 | int piece; 38 | int king_pos[ColourNb]; 39 | 40 | ASSERT(board!=NULL); 41 | ASSERT(string!=NULL); 42 | 43 | board_clear(board); 44 | 45 | king_pos[White] = SquareNone; 46 | king_pos[Black] = SquareNone; 47 | 48 | pos = 0; 49 | c = string[pos]; 50 | 51 | // piece placement 52 | 53 | for (rank = 7; rank >= 0; rank--) { 54 | 55 | for (file = 0; file < 8;) { 56 | 57 | sq = square_make(file,rank); 58 | 59 | if (c >= '1' && c <= '8') { // empty square(s) 60 | 61 | len = c - '0'; 62 | if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 63 | 64 | for (i = 0; i < len; i++) { 65 | board->square[sq++] = Empty; 66 | file++; 67 | } 68 | 69 | } else { // piece 70 | 71 | piece = piece_from_char(c); 72 | if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 73 | 74 | if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq; 75 | 76 | board->square[sq++] = piece; 77 | file++; 78 | } 79 | 80 | c = string[++pos]; 81 | } 82 | 83 | if (rank > 0) { 84 | if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 85 | c = string[++pos]; 86 | } 87 | } 88 | 89 | // active colour 90 | 91 | if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 92 | c = string[++pos]; 93 | 94 | switch (c) { 95 | case 'w': 96 | board->turn = White; 97 | break; 98 | case 'b': 99 | board->turn = Black; 100 | break; 101 | default: 102 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 103 | break; 104 | } 105 | 106 | c = string[++pos]; 107 | 108 | // castling 109 | 110 | if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 111 | c = string[++pos]; 112 | 113 | board->castle[White][SideH] = SquareNone; 114 | board->castle[White][SideA] = SquareNone; 115 | board->castle[Black][SideH] = SquareNone; 116 | board->castle[Black][SideA] = SquareNone; 117 | 118 | if (c == '-') { // no castling rights 119 | 120 | c = string[++pos]; 121 | 122 | } else { 123 | 124 | // TODO: filter out illegal rights 125 | 126 | do { 127 | 128 | if (false) { 129 | 130 | } else if (c == 'K') { 131 | 132 | for (sq = H1; sq > king_pos[White]; sq--) { 133 | if (board->square[sq] == WhiteRook256) { 134 | board->castle[White][SideH] = sq; 135 | break; 136 | } 137 | } 138 | 139 | } else if (c == 'Q') { 140 | 141 | for (sq = A1; sq < king_pos[White]; sq++) { 142 | if (board->square[sq] == WhiteRook256) { 143 | board->castle[White][SideA] = sq; 144 | break; 145 | } 146 | } 147 | 148 | } else if (c == 'k') { 149 | 150 | for (sq = H8; sq > king_pos[Black]; sq--) { 151 | if (board->square[sq] == BlackRook256) { 152 | board->castle[Black][SideH] = sq; 153 | break; 154 | } 155 | } 156 | 157 | } else if (c == 'q') { 158 | 159 | for (sq = A8; sq < king_pos[Black]; sq++) { 160 | if (board->square[sq] == BlackRook256) { 161 | board->castle[Black][SideA] = sq; 162 | break; 163 | } 164 | } 165 | 166 | } else if (c >= 'A' && c <= 'H') { 167 | 168 | // white castling right 169 | 170 | sq = square_make(file_from_char(tolower(c)),Rank1); 171 | 172 | if (sq > king_pos[White]) { // h side 173 | board->castle[White][SideH] = sq; 174 | } else { // a side 175 | board->castle[White][SideA] = sq; 176 | } 177 | 178 | } else if (c >= 'a' && c <= 'h') { 179 | 180 | // black castling right 181 | 182 | sq = square_make(file_from_char(tolower(c)),Rank8); 183 | 184 | if (sq > king_pos[Black]) { // h side 185 | board->castle[Black][SideH] = sq; 186 | } else { // a side 187 | board->castle[Black][SideA] = sq; 188 | } 189 | 190 | } else { 191 | 192 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 193 | } 194 | 195 | c = string[++pos]; 196 | 197 | } while (c != ' '); 198 | } 199 | 200 | // en-passant 201 | 202 | if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 203 | c = string[++pos]; 204 | 205 | if (c == '-') { // no en-passant 206 | 207 | sq = SquareNone; 208 | c = string[++pos]; 209 | 210 | } else { 211 | 212 | if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 213 | file = file_from_char(c); 214 | c = string[++pos]; 215 | 216 | if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 217 | rank = rank_from_char(c); 218 | c = string[++pos]; 219 | 220 | sq = square_make(file,rank); 221 | } 222 | 223 | board->ep_square = sq; 224 | 225 | // halfmove clock 226 | 227 | board->ply_nb = 0; 228 | board->move_nb = 0; // HACK, in case of broken syntax 229 | 230 | if (c != ' ') { 231 | if (!Strict) goto update; 232 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 233 | } 234 | c = string[++pos]; 235 | 236 | if (!isdigit(c)) { 237 | if (!Strict) goto update; 238 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 239 | } 240 | 241 | board->ply_nb = atoi(&string[pos]); 242 | do c = string[++pos]; while (isdigit(c)); 243 | 244 | // fullmove number 245 | 246 | board->move_nb = 0; 247 | 248 | if (c != ' ') { 249 | if (!Strict) goto update; 250 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 251 | } 252 | c = string[++pos]; 253 | 254 | if (!isdigit(c)) { 255 | if (!Strict) goto update; 256 | my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); 257 | } 258 | 259 | board->move_nb = atoi(&string[pos]) - 1; 260 | do c = string[++pos]; while (isdigit(c)); 261 | 262 | // board update 263 | 264 | update: 265 | board_init_list(board); 266 | 267 | return true; 268 | } 269 | 270 | // board_to_fen() 271 | 272 | bool board_to_fen(const board_t * board, char string[], int size) { 273 | 274 | int pos; 275 | int file, rank; 276 | int sq, piece; 277 | int c; 278 | int len; 279 | int old_pos; 280 | 281 | ASSERT(board_is_ok(board)); 282 | ASSERT(string!=NULL); 283 | ASSERT(size>=92); 284 | 285 | // init 286 | 287 | if (size < 92) return false; 288 | 289 | pos = 0; 290 | 291 | // piece placement 292 | 293 | for (rank = 7; rank >= 0; rank--) { 294 | 295 | for (file = 0; file < 8;) { 296 | 297 | sq = square_make(file,rank); 298 | piece = board->square[sq]; 299 | ASSERT(piece==Empty||piece_is_ok(piece)); 300 | 301 | if (piece == Empty) { 302 | 303 | len = 0; 304 | for (; file < 8 && board->square[square_make(file,rank)] == Empty; file++) { 305 | len++; 306 | } 307 | 308 | ASSERT(len>=1&&len<=8); 309 | c = '0' + len; 310 | 311 | } else { 312 | 313 | c = piece_to_char(piece); 314 | file++; 315 | } 316 | 317 | string[pos++] = c; 318 | } 319 | 320 | string[pos++] = '/'; 321 | } 322 | 323 | string[pos-1] = ' '; // HACK: remove the last '/' 324 | 325 | // active colour 326 | 327 | string[pos++] = (colour_is_white(board->turn)) ? 'w' : 'b'; 328 | string[pos++] = ' '; 329 | 330 | // castling 331 | 332 | old_pos = pos; 333 | 334 | if (option_get_bool("Chess960")) { 335 | 336 | // FEN-960 337 | 338 | if (board->castle[White][SideH] != SquareNone) { 339 | string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideH]))); 340 | } 341 | 342 | if (board->castle[White][SideA] != SquareNone) { 343 | string[pos++] = toupper(file_to_char(square_file(board->castle[White][SideA]))); 344 | } 345 | 346 | if (board->castle[Black][SideH] != SquareNone) { 347 | string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideH]))); 348 | } 349 | 350 | if (board->castle[Black][SideA] != SquareNone) { 351 | string[pos++] = tolower(file_to_char(square_file(board->castle[Black][SideA]))); 352 | } 353 | 354 | } else { 355 | 356 | // FEN 357 | 358 | if (board->castle[White][SideH] != SquareNone) string[pos++] = 'K'; 359 | if (board->castle[White][SideA] != SquareNone) string[pos++] = 'Q'; 360 | if (board->castle[Black][SideH] != SquareNone) string[pos++] = 'k'; 361 | if (board->castle[Black][SideA] != SquareNone) string[pos++] = 'q'; 362 | } 363 | 364 | if (pos == old_pos) string[pos++] = '-'; 365 | 366 | string[pos++] = ' '; 367 | 368 | // en-passant 369 | 370 | if (board->ep_square == SquareNone) { 371 | string[pos++] = '-'; 372 | } else { 373 | if (!square_to_string(board->ep_square,&string[pos],3)) return false; 374 | pos += 2; 375 | } 376 | 377 | string[pos++] = ' '; 378 | 379 | // halfmove clock and fullmove number 380 | 381 | sprintf(&string[pos],"%d %d",board->ply_nb,board->move_nb+1); 382 | 383 | return true; 384 | } 385 | 386 | // end of fen.cpp 387 | 388 | -------------------------------------------------------------------------------- /src/fen.h: -------------------------------------------------------------------------------- 1 | 2 | // fen.h 3 | 4 | #ifndef FEN_H 5 | #define FEN_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // "constants" 13 | 14 | extern const char * StartFen; 15 | 16 | // functions 17 | 18 | extern bool board_from_fen (board_t * board, const char string[]); 19 | extern bool board_to_fen (const board_t * board, char string[], int size); 20 | 21 | #endif // !defined FEN_H 22 | 23 | // end of fen.h 24 | 25 | -------------------------------------------------------------------------------- /src/game.cpp: -------------------------------------------------------------------------------- 1 | 2 | // game.cpp 3 | 4 | // includes 5 | 6 | #include "attack.h" 7 | #include "board.h" 8 | #include "fen.h" 9 | #include "game.h" 10 | #include "list.h" 11 | #include "move.h" 12 | #include "move_do.h" 13 | #include "move_legal.h" 14 | #include "piece.h" 15 | #include "square.h" 16 | #include "util.h" 17 | 18 | // constants 19 | 20 | static const bool UseSlowDebug = false; 21 | 22 | // variables 23 | 24 | game_t Game[1]; 25 | 26 | // prototypes 27 | 28 | static void game_update (game_t * game); 29 | static int game_comp_status (const game_t * game); 30 | 31 | // functions 32 | 33 | // game_is_ok() 34 | 35 | bool game_is_ok(const game_t * game) { 36 | 37 | board_t board[1]; 38 | int pos, move; 39 | 40 | if (game == NULL) return false; 41 | 42 | if (game->size < 0 || game->size > GameSize) return false; 43 | if (game->pos < 0 || game->pos > game->size) return false; 44 | 45 | // optional heavy DEBUG mode 46 | 47 | if (!UseSlowDebug) return true; 48 | 49 | if (!board_is_ok(game->start_board)) return false; 50 | 51 | board_copy(board,game->start_board); 52 | 53 | for (pos = 0; pos <= game->size; pos++) { 54 | 55 | if (pos == game->pos) { 56 | if (!board_equal(game->board,board)) return false; 57 | } 58 | 59 | if (pos >= game->size) break; 60 | 61 | if (game->key[pos] != board->key) return false; 62 | 63 | move = game->move[pos]; 64 | if (!move_is_legal(move,board)) 65 | ; 66 | 67 | move_do(board,move); 68 | } 69 | 70 | if (game->status != game_comp_status(game)) return false; 71 | 72 | return true; 73 | } 74 | 75 | // game_clear() 76 | 77 | void game_clear(game_t * game) { 78 | 79 | ASSERT(game!=NULL); 80 | 81 | game_init(game,StartFen); 82 | } 83 | 84 | // game_init() 85 | 86 | bool game_init(game_t * game, const char fen[]) { 87 | 88 | ASSERT(game!=NULL); 89 | ASSERT(fen!=NULL); 90 | 91 | if (!board_from_fen(game->start_board,fen)) return false; 92 | 93 | game->size = 0; 94 | 95 | board_copy(game->board,game->start_board); 96 | game->pos = 0; 97 | 98 | game_update(game); 99 | 100 | return true; 101 | } 102 | 103 | // game_status() 104 | 105 | int game_status(const game_t * game) { 106 | 107 | ASSERT(game!=NULL); 108 | 109 | return game->status; 110 | } 111 | 112 | // game_size() 113 | 114 | int game_size(const game_t * game) { 115 | 116 | ASSERT(game!=NULL); 117 | 118 | return game->size; 119 | } 120 | 121 | // game_pos() 122 | 123 | int game_pos(const game_t * game) { 124 | 125 | ASSERT(game!=NULL); 126 | 127 | return game->pos; 128 | } 129 | 130 | // game_move() 131 | 132 | int game_move(const game_t * game, int pos) { 133 | 134 | ASSERT(game!=NULL); 135 | ASSERT(pos>=0&&pospos); 136 | 137 | return game->move[pos]; 138 | } 139 | 140 | // game_get_board() 141 | 142 | void game_get_board(const game_t * game, board_t * board, int pos) { 143 | 144 | int start; 145 | int i; 146 | 147 | ASSERT(game!=NULL); 148 | ASSERT(board!=NULL); 149 | ASSERT(pos==-1||(pos>=0&&pos<=game->size)); // HACK 150 | 151 | if (pos < 0) pos = game->pos; 152 | 153 | if (pos >= game->pos) { // forward from current position 154 | start = game->pos; 155 | board_copy(board,game->board); 156 | } else { // backward => replay the whole game 157 | start = 0; 158 | board_copy(board,game->start_board); 159 | } 160 | 161 | for (i = start; i < pos; i++) move_do(board,game->move[i]); 162 | } 163 | 164 | // game_turn() 165 | 166 | int game_turn(const game_t * game) { 167 | 168 | ASSERT(game!=NULL); 169 | 170 | return game->board->turn; 171 | } 172 | 173 | // game_move_nb() 174 | 175 | int game_move_nb(const game_t * game) { 176 | 177 | ASSERT(game!=NULL); 178 | 179 | return game->board->move_nb; 180 | } 181 | 182 | // game_add_move() 183 | 184 | void game_add_move(game_t * game, int move) { 185 | 186 | ASSERT(game!=NULL); 187 | ASSERT(move_is_ok(move)); 188 | 189 | ASSERT(move_is_legal(move,game->board)); 190 | 191 | if (game->pos >= GameSize) my_fatal("game_add_move(): game overflow\n"); 192 | 193 | game->move[game->pos] = move; 194 | game->key[game->pos] = game->board->key; 195 | 196 | move_do(game->board,move); 197 | game->pos++; 198 | 199 | game->size = game->pos; // truncate game, HACK: before calling game_is_ok() in game_update() 200 | 201 | game_update(game); 202 | } 203 | 204 | // game_rem_move() 205 | 206 | void game_rem_move(game_t * game) { 207 | 208 | ASSERT(game!=NULL); 209 | 210 | game_goto(game,game->pos-1); 211 | 212 | game->size = game->pos; // truncate game 213 | } 214 | 215 | // game_goto() 216 | 217 | void game_goto(game_t * game, int pos) { 218 | 219 | int i; 220 | 221 | ASSERT(game!=NULL); 222 | ASSERT(pos>=0&&pos<=game->size); 223 | 224 | if (pos < game->pos) { // going backward => replay the whole game 225 | board_copy(game->board,game->start_board); 226 | game->pos = 0; 227 | } 228 | 229 | for (i = game->pos; i < pos; i++) move_do(game->board,game->move[i]); 230 | ASSERT(i==pos); 231 | 232 | game->pos = pos; 233 | 234 | game_update(game); 235 | } 236 | 237 | // game_disp() 238 | 239 | void game_disp(const game_t * game) { 240 | 241 | board_t board[1]; 242 | int i, move; 243 | 244 | ASSERT(game_is_ok(game)); 245 | 246 | board_copy(board,game->start_board); 247 | 248 | board_disp(board); 249 | 250 | for (i = 0; i < game->pos; i++) { 251 | 252 | move = game->move[i]; 253 | move_disp(move,board); 254 | 255 | move_do(board,move); 256 | } 257 | 258 | my_log("POLYGLOT\n"); 259 | 260 | board_disp(board); 261 | } 262 | 263 | // game_update() 264 | 265 | static void game_update(game_t * game) { 266 | 267 | ASSERT(game!=NULL); 268 | 269 | game->status = game_comp_status(game); 270 | 271 | ASSERT(game_is_ok(game)); 272 | } 273 | 274 | // game_comp_status() 275 | 276 | static int game_comp_status(const game_t * game) { 277 | 278 | int i, n; 279 | int wb, bb; 280 | const board_t * board; 281 | uint64 key; 282 | int start; 283 | 284 | ASSERT(game!=NULL); 285 | 286 | // init 287 | 288 | board = game->board; 289 | 290 | // mate and stalemate 291 | 292 | if (!board_can_play(board)) { 293 | if (false) { 294 | } else if (is_in_check(board,Black)) { // HACK 295 | return WHITE_MATES; 296 | } else if (is_in_check(board,White)) { // HACK 297 | return BLACK_MATES; 298 | } else { 299 | return STALEMATE; 300 | } 301 | } 302 | 303 | // insufficient material 304 | 305 | if (board->number[WhitePawn12] == 0 306 | && board->number[BlackPawn12] == 0 307 | && board->number[WhiteQueen12] == 0 308 | && board->number[BlackQueen12] == 0 309 | && board->number[WhiteRook12] == 0 310 | && board->number[BlackRook12] == 0) { 311 | 312 | if (board->number[WhiteBishop12] 313 | + board->number[BlackBishop12] 314 | + board->number[WhiteKnight12] 315 | + board->number[BlackKnight12] <= 1) { // KK, KBK and KNK 316 | 317 | return DRAW_MATERIAL; 318 | 319 | } else if (board->number[WhiteBishop12] == 1 320 | && board->number[BlackBishop12] == 1 321 | && board->number[WhiteKnight12] == 0 322 | && board->number[BlackKnight12] == 0) { 323 | 324 | wb = board->list[White][1]; // HACK 325 | bb = board->list[Black][1]; // HACK 326 | 327 | if (square_colour(wb) == square_colour(bb)) { // KBKB 328 | return DRAW_MATERIAL; 329 | } 330 | } 331 | } 332 | 333 | // 50-move rule 334 | 335 | if (board->ply_nb >= 100) return DRAW_FIFTY; 336 | 337 | // position repetition 338 | 339 | key = board->key; 340 | n = 0; 341 | 342 | start = game->pos - board->ply_nb; 343 | if (start < 0) start = 0; 344 | 345 | for (i = game->pos-4; i >= start; i -= 2) { 346 | if (game->key[i] == key) { 347 | if (++n == 2) return DRAW_REPETITION; 348 | } 349 | } 350 | 351 | return PLAYING; 352 | } 353 | 354 | // end of game.cpp 355 | 356 | -------------------------------------------------------------------------------- /src/game.h: -------------------------------------------------------------------------------- 1 | 2 | // game.h 3 | 4 | #ifndef GAME_H 5 | #define GAME_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "move.h" 11 | #include "util.h" 12 | 13 | // constants 14 | 15 | const int GameSize = 4096; 16 | 17 | enum status_t { 18 | PLAYING, 19 | WHITE_MATES, 20 | BLACK_MATES, 21 | STALEMATE, 22 | DRAW_MATERIAL, 23 | DRAW_FIFTY, 24 | DRAW_REPETITION 25 | }; 26 | 27 | // types 28 | 29 | struct game_t { 30 | board_t start_board[1]; 31 | board_t board[1]; 32 | sint16 size; 33 | sint16 pos; 34 | sint8 status; 35 | move_t move[GameSize]; 36 | uint64 key[GameSize]; 37 | }; 38 | 39 | // variables 40 | 41 | extern game_t Game[1]; 42 | 43 | // functions 44 | 45 | extern bool game_is_ok (const game_t * game); 46 | 47 | extern void game_clear (game_t * game); 48 | extern bool game_init (game_t * game, const char fen[]); 49 | 50 | extern int game_status (const game_t * game); 51 | 52 | extern int game_size (const game_t * game); 53 | extern int game_pos (const game_t * game); 54 | extern int game_move (const game_t * game, int pos); 55 | 56 | extern void game_get_board (const game_t * game, board_t * board, int pos = -1); 57 | extern int game_turn (const game_t * game); 58 | extern int game_move_nb (const game_t * game); 59 | 60 | extern void game_add_move (game_t * game, int move); 61 | extern void game_rem_move (game_t * game); 62 | 63 | extern void game_goto (game_t * game, int pos); 64 | 65 | extern void game_disp (const game_t * game); 66 | 67 | #endif // !defined GAME_H 68 | 69 | // end of game.h 70 | 71 | -------------------------------------------------------------------------------- /src/hash.cpp: -------------------------------------------------------------------------------- 1 | 2 | // hash.cpp 3 | 4 | // includes 5 | 6 | #include "board.h" 7 | #include "hash.h" 8 | #include "piece.h" 9 | #include "random.h" 10 | #include "square.h" 11 | #include "util.h" 12 | 13 | // variables 14 | 15 | static uint64 Castle64[16]; 16 | 17 | // prototypes 18 | 19 | static uint64 hash_castle_key_debug (int flags); 20 | 21 | // functions 22 | 23 | // hash_init() 24 | 25 | void hash_init() { 26 | 27 | int i; 28 | 29 | for (i = 0; i < 16; i++) Castle64[i] = hash_castle_key_debug(i); 30 | } 31 | 32 | // hash_key() 33 | 34 | uint64 hash_key(const board_t * board) { 35 | 36 | uint64 key; 37 | int colour; 38 | const uint8 * ptr; 39 | int sq, piece; 40 | 41 | ASSERT(board_is_ok(board)); 42 | 43 | // init 44 | 45 | key = 0; 46 | 47 | // pieces 48 | 49 | for (colour = 1; colour <= 2; colour++) { // HACK 50 | for (ptr = board->list[colour]; (sq=*ptr) != SquareNone; ptr++) { 51 | piece = board->square[sq]; 52 | key ^= hash_piece_key(piece,sq); 53 | } 54 | } 55 | 56 | // castle flags 57 | 58 | key ^= hash_castle_key(board_flags(board)); 59 | 60 | // en-passant square 61 | 62 | sq = board->ep_square; 63 | if (sq != SquareNone) key ^= hash_ep_key(sq); 64 | 65 | // turn 66 | 67 | key ^= hash_turn_key(board->turn); 68 | 69 | return key; 70 | } 71 | 72 | // hash_piece_key() 73 | 74 | uint64 hash_piece_key(int piece, int square) { 75 | 76 | ASSERT(piece_is_ok(piece)); 77 | ASSERT(square_is_ok(square)); 78 | 79 | return random_64(RandomPiece+piece_to_12(piece)*64+square_to_64(square)); 80 | } 81 | 82 | // hash_castle_key() 83 | 84 | uint64 hash_castle_key(int flags) { 85 | 86 | ASSERT((flags&~0xF)==0); 87 | 88 | return Castle64[flags]; 89 | } 90 | 91 | // hash_castle_key_debug() 92 | 93 | static uint64 hash_castle_key_debug(int flags) { 94 | 95 | uint64 key; 96 | int i; 97 | 98 | ASSERT((flags&~0xF)==0); 99 | 100 | key = 0; 101 | 102 | for (i = 0; i < 4; i++) { 103 | if ((flags & (1< 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "io.h" 16 | #include "util.h" 17 | 18 | // constants 19 | 20 | static const bool UseDebug = false; 21 | static const bool UseCR = false; // true on Windows 22 | 23 | static const int StringSize = 4096; 24 | 25 | static const char LF = '\n'; 26 | static const char CR = '\r'; 27 | 28 | // prototypes 29 | 30 | static int my_read (int fd, char string[], int size); 31 | static void my_write (int fd, const char string[], int size); 32 | 33 | // functions 34 | 35 | // io_is_ok() 36 | 37 | bool io_is_ok(const io_t * io) { 38 | 39 | if (io == NULL) return false; 40 | 41 | if (io->name == NULL) return false; 42 | 43 | if (io->in_eof != true && io->in_eof != false) return false; 44 | 45 | if (io->in_size < 0 || io->in_size > BufferSize) return false; 46 | if (io->out_size < 0 || io->out_size > BufferSize) return false; 47 | 48 | return true; 49 | } 50 | 51 | // io_init() 52 | 53 | void io_init(io_t * io) { 54 | 55 | ASSERT(io!=NULL); 56 | 57 | io->in_eof = false; 58 | 59 | io->in_size = 0; 60 | io->out_size = 0; 61 | 62 | ASSERT(io_is_ok(io)); 63 | } 64 | 65 | // io_close() 66 | 67 | void io_close(io_t * io) { 68 | 69 | ASSERT(io_is_ok(io)); 70 | 71 | ASSERT(io->out_fd>=0); 72 | 73 | my_log("> %s EOF\n",io->name); 74 | 75 | if (close(io->out_fd) == -1) { 76 | my_fatal("io_close(): close(): %s\n",strerror(errno)); 77 | } 78 | 79 | io->out_fd = -1; 80 | } 81 | 82 | // io_get_update() 83 | 84 | void io_get_update(io_t * io) { 85 | 86 | int pos, size; 87 | int n; 88 | 89 | ASSERT(io_is_ok(io)); 90 | 91 | ASSERT(io->in_fd>=0); 92 | ASSERT(!io->in_eof); 93 | 94 | // init 95 | 96 | pos = io->in_size; 97 | 98 | size = BufferSize - pos; 99 | if (size <= 0) my_fatal("io_get_update(): buffer overflow\n"); 100 | 101 | // read as many data as possible 102 | 103 | n = my_read(io->in_fd,&io->in_buffer[pos],size); 104 | if (UseDebug) my_log("POLYGLOT read %d byte%s from %s\n",n,(n>1)?"s":"",io->name); 105 | 106 | if (n > 0) { // at least one character was read 107 | 108 | // update buffer size 109 | 110 | ASSERT(n>=1&&n<=size); 111 | 112 | io->in_size += n; 113 | ASSERT(io->in_size>=0&&io->in_size<=BufferSize); 114 | 115 | } else { // EOF 116 | 117 | ASSERT(n==0); 118 | 119 | io->in_eof = true; 120 | } 121 | } 122 | 123 | // io_line_ready() 124 | 125 | bool io_line_ready(const io_t * io) { 126 | 127 | ASSERT(io_is_ok(io)); 128 | 129 | if (io->in_eof) return true; 130 | 131 | if (memchr(io->in_buffer,LF,io->in_size) != NULL) return true; // buffer contains LF 132 | 133 | return false; 134 | } 135 | 136 | // io_get_line() 137 | 138 | bool io_get_line(io_t * io, char string[], int size) { 139 | 140 | int src, dst; 141 | int c; 142 | 143 | ASSERT(io_is_ok(io)); 144 | ASSERT(string!=NULL); 145 | ASSERT(size>=256); 146 | 147 | src = 0; 148 | dst = 0; 149 | 150 | while (true) { 151 | 152 | // test for end of buffer 153 | 154 | if (src >= io->in_size) { 155 | if (io->in_eof) { 156 | my_log("< %s EOF\n",io->name); 157 | return false; 158 | } else { 159 | my_fatal("io_get_line(): no EOL in buffer\n"); 160 | } 161 | } 162 | 163 | // test for end of string 164 | 165 | if (dst >= size) my_fatal("io_get_line(): buffer overflow\n"); 166 | 167 | // copy the next character 168 | 169 | c = io->in_buffer[src++]; 170 | 171 | if (c == LF) { // LF => line complete 172 | string[dst] = '\0'; 173 | break; 174 | } else if (c != CR) { // skip CRs 175 | string[dst++] = c; 176 | } 177 | } 178 | 179 | // shift the buffer 180 | 181 | ASSERT(src>0); 182 | 183 | io->in_size -= src; 184 | ASSERT(io->in_size>=0); 185 | 186 | if (io->in_size > 0) memmove(&io->in_buffer[0],&io->in_buffer[src],io->in_size); 187 | 188 | // return 189 | 190 | my_log("< %s %s\n",io->name,string); 191 | 192 | return true; 193 | } 194 | 195 | // io_send() 196 | 197 | void io_send(io_t * io, const char format[], ...) { 198 | 199 | va_list arg_list; 200 | char string[StringSize]; 201 | int len; 202 | 203 | ASSERT(io_is_ok(io)); 204 | ASSERT(format!=NULL); 205 | 206 | ASSERT(io->out_fd>=0); 207 | 208 | // format 209 | 210 | va_start(arg_list,format); 211 | vsprintf(string,format,arg_list); 212 | va_end(arg_list); 213 | 214 | // append string to buffer 215 | 216 | len = strlen(string); 217 | if (io->out_size + len > BufferSize-2) my_fatal("io_send(): buffer overflow\n"); 218 | 219 | memcpy(&io->out_buffer[io->out_size],string,len); 220 | io->out_size += len; 221 | 222 | ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2); 223 | 224 | // log 225 | 226 | io->out_buffer[io->out_size] = '\0'; 227 | my_log("> %s %s\n",io->name,io->out_buffer); 228 | 229 | // append EOL to buffer 230 | 231 | if (UseCR) io->out_buffer[io->out_size++] = CR; 232 | io->out_buffer[io->out_size++] = LF; 233 | 234 | ASSERT(io->out_size>=0&&io->out_size<=BufferSize); 235 | 236 | // flush buffer 237 | 238 | if (UseDebug) my_log("POLYGLOT writing %d byte%s to %s\n",io->out_size,(io->out_size>1)?"s":"",io->name); 239 | my_write(io->out_fd,io->out_buffer,io->out_size); 240 | 241 | io->out_size = 0; 242 | } 243 | 244 | // io_send_queue() 245 | 246 | void io_send_queue(io_t * io, const char format[], ...) { 247 | 248 | va_list arg_list; 249 | char string[StringSize]; 250 | int len; 251 | 252 | ASSERT(io_is_ok(io)); 253 | ASSERT(format!=NULL); 254 | 255 | ASSERT(io->out_fd>=0); 256 | 257 | // format 258 | 259 | va_start(arg_list,format); 260 | vsprintf(string,format,arg_list); 261 | va_end(arg_list); 262 | 263 | // append string to buffer 264 | 265 | len = strlen(string); 266 | if (io->out_size + len > BufferSize-2) my_fatal("io_send_queue(): buffer overflow\n"); 267 | 268 | memcpy(&io->out_buffer[io->out_size],string,len); 269 | io->out_size += len; 270 | 271 | ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2); 272 | } 273 | 274 | // my_read() 275 | 276 | static int my_read(int fd, char string[], int size) { 277 | 278 | int n; 279 | 280 | ASSERT(fd>=0); 281 | ASSERT(string!=NULL); 282 | ASSERT(size>0); 283 | 284 | do { 285 | n = read(fd,string,size); 286 | } while (n == -1 && errno == EINTR); 287 | 288 | if (n == -1) my_fatal("my_read(): read(): %s\n",strerror(errno)); 289 | 290 | ASSERT(n>=0); 291 | 292 | return n; 293 | } 294 | 295 | // my_write() 296 | 297 | static void my_write(int fd, const char string[], int size) { 298 | 299 | int n; 300 | 301 | ASSERT(fd>=0); 302 | ASSERT(string!=NULL); 303 | ASSERT(size>0); 304 | 305 | do { 306 | 307 | n = write(fd,string,size); 308 | 309 | // if (n == -1 && errno != EINTR && errno != EPIPE) my_fatal("my_write(): write(): %s\n",strerror(errno)); 310 | 311 | if (n == -1) { 312 | if (false) { 313 | } else if (errno == EINTR) { 314 | n = 0; // nothing has been written 315 | } else if (errno == EPIPE) { 316 | n = size; // pretend everything has been written 317 | } else { 318 | my_fatal("my_write(): write(): %s\n",strerror(errno)); 319 | } 320 | } 321 | 322 | ASSERT(n>=0); 323 | 324 | string += n; 325 | size -= n; 326 | 327 | } while (size > 0); 328 | 329 | ASSERT(size==0); 330 | } 331 | 332 | // end of io.cpp 333 | 334 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | 2 | // io.h 3 | 4 | #ifndef IO_H 5 | #define IO_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | const int BufferSize = 16384; 14 | 15 | // types 16 | 17 | struct io_t { 18 | 19 | int in_fd; 20 | int out_fd; 21 | 22 | const char * name; 23 | 24 | bool in_eof; 25 | 26 | sint32 in_size; 27 | sint32 out_size; 28 | 29 | char in_buffer[BufferSize]; 30 | char out_buffer[BufferSize]; 31 | }; 32 | 33 | // functions 34 | 35 | extern bool io_is_ok (const io_t * io); 36 | 37 | extern void io_init (io_t * io); 38 | extern void io_close (io_t * io); 39 | 40 | extern void io_get_update (io_t * io); 41 | 42 | extern bool io_line_ready (const io_t * io); 43 | extern bool io_get_line (io_t * io, char string[], int size); 44 | 45 | extern void io_send (io_t * io, const char format[], ...); 46 | extern void io_send_queue (io_t * io, const char format[], ...); 47 | 48 | #endif // !defined IO_H 49 | 50 | // end of io.h 51 | 52 | -------------------------------------------------------------------------------- /src/line.cpp: -------------------------------------------------------------------------------- 1 | 2 | // line.cpp 3 | 4 | // includes 5 | 6 | #include 7 | 8 | #include "board.h" 9 | #include "line.h" 10 | #include "move.h" 11 | #include "move_do.h" 12 | #include "move_legal.h" 13 | #include "san.h" 14 | #include "util.h" 15 | 16 | // constants 17 | 18 | static const bool Strict = false; // false 19 | static const bool UseDebug = false; // false 20 | 21 | static const int StringSize = 1024; 22 | 23 | // functions 24 | 25 | // line_is_ok() 26 | 27 | bool line_is_ok(const move_t line[]) { 28 | 29 | int move; 30 | 31 | if (line == NULL) return false; 32 | 33 | while ((move = *line++) != MoveNone) { 34 | if (!move_is_ok(move)) return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | // line_clear() 41 | 42 | void line_clear(move_t line[]) { 43 | 44 | ASSERT(line!=NULL); 45 | 46 | *line = MoveNone; 47 | } 48 | 49 | // line_copy() 50 | 51 | void line_copy(move_t dst[], const move_t src[]) { 52 | 53 | ASSERT(dst!=NULL); 54 | ASSERT(src!=NULL); 55 | 56 | ASSERT(dst!=src); 57 | 58 | while ((*dst++ = *src++) != MoveNone) 59 | ; 60 | } 61 | 62 | // line_from_can() 63 | 64 | bool line_from_can (move_t line[], const board_t * board, const char string[], int size) { 65 | 66 | int pos; 67 | char new_string[StringSize], *p; 68 | int move; 69 | board_t new_board[1]; 70 | 71 | ASSERT(line!=NULL); 72 | ASSERT(board_is_ok(board)); 73 | ASSERT(string!=NULL); 74 | ASSERT(size>=LineSize); 75 | 76 | // init 77 | 78 | pos = 0; 79 | board_copy(new_board,board); 80 | 81 | // loop 82 | 83 | strcpy(new_string,string); // HACK 84 | 85 | for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) { 86 | 87 | move = move_from_can(p,new_board); 88 | 89 | ASSERT(move!=MoveNone); 90 | ASSERT(move_is_legal(move,new_board)); 91 | 92 | if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves 93 | 94 | if (pos >= size) return false; 95 | line[pos++] = move; 96 | 97 | move_do(new_board,move); 98 | } 99 | 100 | if (pos >= size) return false; 101 | line[pos] = MoveNone; 102 | 103 | return true; 104 | } 105 | 106 | // line_to_can() 107 | 108 | bool line_to_can(const move_t line[], const board_t * board, char string[], int size) { 109 | 110 | board_t new_board[1]; 111 | int pos; 112 | int move; 113 | 114 | ASSERT(line_is_ok(line)); 115 | ASSERT(board_is_ok(board)); 116 | ASSERT(string!=NULL); 117 | ASSERT(size>=StringSize); 118 | 119 | // init 120 | 121 | if (size < StringSize) return false; 122 | 123 | board_copy(new_board,board); 124 | pos = 0; 125 | 126 | // loop 127 | 128 | while ((move = *line++) != MoveNone) { 129 | 130 | if (pos != 0) { 131 | if (pos >= size) return false; 132 | string[pos++] = ' '; 133 | } 134 | 135 | if (!move_to_can(move,new_board,&string[pos],size-pos)) return false; 136 | pos += strlen(&string[pos]); 137 | 138 | move_do(new_board,move); 139 | } 140 | 141 | if (pos >= size) return false; 142 | string[pos] = '\0'; 143 | 144 | return true; 145 | } 146 | 147 | // line_to_san() 148 | 149 | bool line_to_san(const move_t line[], const board_t * board, char string[], int size) { 150 | 151 | board_t new_board[1]; 152 | int pos; 153 | int move; 154 | char move_string[256]; 155 | 156 | ASSERT(line_is_ok(line)); 157 | ASSERT(board_is_ok(board)); 158 | ASSERT(string!=NULL); 159 | ASSERT(size>=StringSize); 160 | 161 | // init 162 | 163 | if (size < StringSize) return false; 164 | 165 | board_copy(new_board,board); 166 | pos = 0; 167 | 168 | // loop 169 | 170 | while ((move = *line++) != MoveNone) { 171 | 172 | if (pos != 0) { 173 | if (pos >= size) return false; 174 | string[pos++] = ' '; 175 | } 176 | 177 | if (!move_is_legal(move,new_board) 178 | || !move_to_san(move,new_board,&string[pos],size-pos)) { 179 | 180 | if (Strict || UseDebug) { 181 | 182 | move_to_can(move,new_board,move_string,256); 183 | my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string); 184 | 185 | board_disp(new_board); 186 | } 187 | 188 | if (Strict) my_fatal("line_to_san(): illegal move\n"); 189 | 190 | break; 191 | } 192 | 193 | pos += strlen(&string[pos]); 194 | 195 | move_do(new_board,move); 196 | } 197 | 198 | if (pos >= size) return false; 199 | string[pos] = '\0'; 200 | 201 | return true; 202 | } 203 | 204 | // end of line.cpp 205 | 206 | -------------------------------------------------------------------------------- /src/line.h: -------------------------------------------------------------------------------- 1 | 2 | // line.h 3 | 4 | #ifndef LINE_H 5 | #define LINE_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "move.h" 11 | #include "util.h" 12 | 13 | // constants 14 | 15 | const int LineSize = 256; 16 | 17 | // functions 18 | 19 | extern bool line_is_ok (const move_t line[]); 20 | 21 | extern void line_clear (move_t line[]); 22 | extern void line_copy (move_t dst[], const move_t src[]); 23 | 24 | extern bool line_from_can (move_t line[], const board_t * board, const char string[], int size); 25 | 26 | extern bool line_to_can (const move_t line[], const board_t * board, char string[], int size); 27 | extern bool line_to_san (const move_t line[], const board_t * board, char string[], int size); 28 | 29 | #endif // !defined LINE_H 30 | 31 | // end of line.h 32 | 33 | -------------------------------------------------------------------------------- /src/list.cpp: -------------------------------------------------------------------------------- 1 | 2 | // list.cpp 3 | 4 | // includes 5 | 6 | #include "board.h" 7 | #include "list.h" 8 | #include "move.h" 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | // list_is_ok() 14 | 15 | bool list_is_ok(const list_t * list) { 16 | 17 | if (list == NULL) return false; 18 | 19 | if (list->size >= ListSize) return false; 20 | 21 | return true; 22 | } 23 | 24 | // list_clear() 25 | 26 | void list_clear(list_t * list) { 27 | 28 | ASSERT(list!=NULL); 29 | 30 | list->size = 0; 31 | } 32 | 33 | // list_add() 34 | 35 | void list_add(list_t * list, int move, int value) { 36 | 37 | ASSERT(list_is_ok(list)); 38 | ASSERT(move_is_ok(move)); 39 | ASSERT(value>=-32767&&value<=+32767); 40 | 41 | ASSERT(list->sizemove[list->size] = move; 44 | list->value[list->size] = value; 45 | list->size++; 46 | } 47 | 48 | // list_remove() 49 | 50 | void list_remove(list_t * list, int index) { 51 | 52 | int i; 53 | 54 | ASSERT(list_is_ok(list)); 55 | ASSERT(index>=0&&indexsize); 56 | 57 | for (i = index; i < list->size-1; i++) { 58 | list->move[i] = list->move[i+1]; 59 | list->value[i] = list->value[i+1]; 60 | } 61 | 62 | list->size--; 63 | } 64 | 65 | // list_is_empty() 66 | 67 | bool list_is_empty(const list_t * list) { 68 | 69 | ASSERT(list_is_ok(list)); 70 | 71 | return list->size == 0; 72 | } 73 | 74 | // list_size() 75 | 76 | int list_size(const list_t * list) { 77 | 78 | ASSERT(list_is_ok(list)); 79 | 80 | return list->size; 81 | } 82 | 83 | // list_move() 84 | 85 | int list_move(const list_t * list, int index) { 86 | 87 | ASSERT(list_is_ok(list)); 88 | ASSERT(index>=0&&indexsize); 89 | 90 | return list->move[index]; 91 | } 92 | 93 | // list_value() 94 | 95 | int list_value(const list_t * list, int index) { 96 | 97 | ASSERT(list_is_ok(list)); 98 | ASSERT(index>=0&&indexsize); 99 | 100 | return list->value[index]; 101 | } 102 | 103 | // list_copy() 104 | 105 | void list_copy(list_t * dst, const list_t * src) { 106 | 107 | int i; 108 | 109 | ASSERT(dst!=NULL); 110 | ASSERT(list_is_ok(src)); 111 | 112 | dst->size = src->size; 113 | 114 | for (i = 0; i < src->size; i++) { 115 | dst->move[i] = src->move[i]; 116 | dst->value[i] = src->value[i]; 117 | } 118 | } 119 | 120 | // list_move_to_front() 121 | 122 | void list_move_to_front(list_t * list, int index) { 123 | 124 | int i; 125 | int move, value; 126 | 127 | ASSERT(list_is_ok(list)); 128 | ASSERT(index>=0&&indexsize); 129 | 130 | if (index != 0) { 131 | 132 | move = list->move[index]; 133 | value = list->value[index]; 134 | 135 | for (i = index; i > 0; i--) { 136 | list->move[i] = list->move[i-1]; 137 | list->value[i] = list->value[i-1]; 138 | } 139 | 140 | list->move[0] = move; 141 | list->value[0] = value; 142 | } 143 | } 144 | 145 | // list_note() 146 | 147 | void list_note(list_t * list) { 148 | 149 | int i, move; 150 | 151 | ASSERT(list_is_ok(list)); 152 | 153 | for (i = 0; i < list->size; i++) { 154 | move = list->move[i]; 155 | ASSERT(move_is_ok(move)); 156 | list->value[i] = -move_order(move); 157 | } 158 | } 159 | 160 | // list_sort() 161 | 162 | void list_sort(list_t * list) { 163 | 164 | int i, j; 165 | int best_index, best_move, best_value; 166 | 167 | ASSERT(list_is_ok(list)); 168 | 169 | for (i = 0; i < list->size-1; i++) { 170 | 171 | best_index = i; 172 | best_value = list->value[i]; 173 | 174 | for (j = i+1; j < list->size; j++) { 175 | if (list->value[j] > best_value) { 176 | best_index = j; 177 | best_value = list->value[j]; 178 | } 179 | } 180 | 181 | if (best_index != i) { 182 | 183 | best_move = list->move[best_index]; 184 | ASSERT(best_value==list->value[best_index]); 185 | 186 | for (j = best_index; j > i; j--) { 187 | list->move[j] = list->move[j-1]; 188 | list->value[j] = list->value[j-1]; 189 | } 190 | 191 | list->move[i] = best_move; 192 | list->value[i] = best_value; 193 | } 194 | } 195 | 196 | if (DEBUG) { 197 | for (i = 0; i < list->size-1; i++) { 198 | ASSERT(list->value[i]>=list->value[i+1]); 199 | } 200 | } 201 | } 202 | 203 | // list_contain() 204 | 205 | bool list_contain(const list_t * list, int move) { 206 | 207 | int i; 208 | 209 | ASSERT(list_is_ok(list)); 210 | ASSERT(move_is_ok(move)); 211 | 212 | for (i = 0; i < list->size; i++) { 213 | if (list->move[i] == move) return true; 214 | } 215 | 216 | return false; 217 | } 218 | 219 | // list_equal() 220 | 221 | bool list_equal(list_t * list_1, list_t * list_2) { 222 | 223 | list_t copy_1[1], copy_2[1]; 224 | int i; 225 | 226 | ASSERT(list_is_ok(list_1)); 227 | ASSERT(list_is_ok(list_2)); 228 | 229 | if (list_1->size != list_2->size) return false; 230 | 231 | list_copy(copy_1,list_1); 232 | list_note(copy_1); 233 | list_sort(copy_1); 234 | 235 | list_copy(copy_2,list_2); 236 | list_note(copy_2); 237 | list_sort(copy_2); 238 | 239 | for (i = 0; i < copy_1->size; i++) { 240 | if (copy_1->move[i] != copy_2->move[i]) return false; 241 | } 242 | 243 | return true; 244 | } 245 | 246 | // list_disp() 247 | 248 | void list_disp(const list_t * list, const board_t * board) { 249 | 250 | int i, move, value; 251 | char string[256]; 252 | 253 | ASSERT(list_is_ok(list)); 254 | ASSERT(board_is_ok(board)); 255 | 256 | for (i = 0; i < list->size; i++) { 257 | 258 | move = list->move[i]; 259 | value = list->value[i]; 260 | 261 | if (!move_to_can(move,board,string,256)) ASSERT(false); 262 | my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); 263 | } 264 | 265 | my_log("POLYGLOT\n"); 266 | } 267 | 268 | // end of list.cpp 269 | 270 | -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | 2 | // list.h 3 | 4 | #ifndef LIST_H 5 | #define LIST_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "move.h" 11 | #include "util.h" 12 | 13 | // constants 14 | 15 | const int ListSize = 256; 16 | 17 | // types 18 | 19 | struct list_t { 20 | sint16 size; 21 | move_t move[ListSize]; 22 | sint16 value[ListSize]; 23 | }; 24 | 25 | // functions 26 | 27 | extern bool list_is_ok (const list_t * list); 28 | 29 | extern void list_clear (list_t * list); 30 | extern void list_add (list_t * list, int move, int value = 0); 31 | extern void list_remove (list_t * list, int index); 32 | 33 | extern bool list_is_empty (const list_t * list); 34 | extern int list_size (const list_t * list); 35 | 36 | extern int list_move (const list_t * list, int index); 37 | extern int list_value (const list_t * list, int index); 38 | 39 | extern void list_copy (list_t * dst, const list_t * src); 40 | 41 | extern void list_note (list_t * list); 42 | extern void list_sort (list_t * list); 43 | 44 | extern bool list_contain (const list_t * list, int move); 45 | extern bool list_equal (list_t * list_1, list_t * list_2); 46 | 47 | extern void list_disp (const list_t * list, const board_t * board); 48 | 49 | #endif // !defined LIST_H 50 | 51 | // end of list.h 52 | 53 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | // main.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "adapter.h" 13 | #include "attack.h" 14 | #include "board.h" 15 | #include "book.h" 16 | #include "book_make.h" 17 | #include "book_merge.h" 18 | #include "engine.h" 19 | #include "epd.h" 20 | #include "fen.h" 21 | #include "hash.h" 22 | #include "list.h" 23 | #include "main.h" 24 | #include "move.h" 25 | #include "move_gen.h" 26 | #include "option.h" 27 | #include "piece.h" 28 | #include "search.h" 29 | #include "square.h" 30 | #include "uci.h" 31 | #include "util.h" 32 | 33 | // constants 34 | 35 | static const char * const Version = "1.4"; 36 | 37 | static const bool BlockSignal = false; // true on Windows 38 | 39 | static const int SearchDepth = 63; 40 | static const double SearchTime = 3600.0; 41 | 42 | static const int StringSize = 4096; 43 | 44 | // variables 45 | 46 | static bool Init; 47 | 48 | // prototypes 49 | 50 | static void parse_option (); 51 | static bool parse_line (char line[], char * * name_ptr, char * * value_ptr); 52 | 53 | static void stop_search (); 54 | 55 | // functions 56 | 57 | // main() 58 | 59 | int main(int argc, char * argv[]) { 60 | 61 | board_t board[1]; 62 | 63 | // init 64 | 65 | Init = false; 66 | 67 | if (BlockSignal) { 68 | signal(SIGINT,SIG_IGN); 69 | signal(SIGTERM,SIG_IGN); 70 | signal(SIGPIPE,SIG_IGN); 71 | } 72 | 73 | util_init(); 74 | printf("PolyGlot %s by Fabien Letouzey\n",Version); 75 | 76 | option_init(); 77 | 78 | square_init(); 79 | piece_init(); 80 | attack_init(); 81 | 82 | hash_init(); 83 | 84 | my_random_init(); 85 | 86 | // build book 87 | 88 | if (argc >= 2 && my_string_equal(argv[1],"make-book")) { 89 | book_make(argc,argv); 90 | return EXIT_SUCCESS; 91 | } 92 | 93 | if (argc >= 2 && my_string_equal(argv[1],"merge-book")) { 94 | book_merge(argc,argv); 95 | return EXIT_SUCCESS; 96 | } 97 | 98 | // read options 99 | 100 | if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility 101 | 102 | parse_option(); // HACK: also launches the engine 103 | 104 | // EPD test 105 | 106 | if (argc >= 2 && my_string_equal(argv[1],"epd-test")) { 107 | epd_test(argc,argv); 108 | return EXIT_SUCCESS; 109 | } 110 | 111 | // opening book 112 | 113 | book_clear(); 114 | if (option_get_bool("Book")) book_open(option_get_string("BookFile")); 115 | 116 | // adapter 117 | 118 | adapter_loop(); 119 | 120 | engine_send(Engine,"quit"); 121 | engine_close(Engine); 122 | 123 | return EXIT_SUCCESS; 124 | } 125 | 126 | // parse_option() 127 | 128 | static void parse_option() { 129 | 130 | const char * file_name; 131 | FILE * file; 132 | char line[256]; 133 | char * name, * value; 134 | 135 | file_name = option_get_string("OptionFile"); 136 | 137 | file = fopen(file_name,"r"); 138 | if (file == NULL) my_fatal("Can't open file \"%s\": %s\n",file_name,strerror(errno)); 139 | 140 | // PolyGlot options (assumed first) 141 | 142 | while (true) { 143 | 144 | if (!my_file_read_line(file,line,256)) { 145 | my_fatal("parse_option(): missing [Engine] section\n"); 146 | } 147 | 148 | if (my_string_case_equal(line,"[engine]")) break; 149 | 150 | if (parse_line(line,&name,&value)) option_set(name,value); 151 | } 152 | 153 | if (option_get_bool("Log")) { 154 | my_log_open(option_get_string("LogFile")); 155 | } 156 | 157 | my_log("POLYGLOT *** START ***\n"); 158 | my_log("POLYGLOT INI file \"%s\"\n",file_name); 159 | 160 | // engine options (assumed second and last) 161 | 162 | engine_open(Engine); 163 | Init = true; // engine has been launched 164 | uci_open(Uci,Engine); 165 | 166 | while (my_file_read_line(file,line,256)) { 167 | 168 | if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line); 169 | 170 | if (parse_line(line,&name,&value)) { 171 | uci_send_option(Uci,name,"%s",value); 172 | } 173 | } 174 | 175 | uci_send_isready(Uci); 176 | 177 | fclose(file); 178 | 179 | if (my_string_equal(option_get_string("EngineName"),"")) { 180 | option_set("EngineName",Uci->name); 181 | } 182 | } 183 | 184 | // parse_line() 185 | 186 | static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) { 187 | 188 | char * ptr; 189 | char * name, * value; 190 | 191 | ASSERT(line!=NULL); 192 | ASSERT(name_ptr!=NULL); 193 | ASSERT(value_ptr!=NULL); 194 | 195 | // remove comments 196 | 197 | ptr = strchr(line,';'); 198 | if (ptr != NULL) *ptr = '\0'; 199 | 200 | ptr = strchr(line,'#'); 201 | if (ptr != NULL) *ptr = '\0'; 202 | 203 | // split at '=' 204 | 205 | ptr = strchr(line,'='); 206 | if (ptr == NULL) return false; 207 | 208 | name = line; 209 | value = ptr+1; 210 | 211 | // cleanup name 212 | 213 | while (*name == ' ') name++; // remove leading spaces 214 | 215 | while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces 216 | *ptr = '\0'; 217 | 218 | if (*name == '\0') return false; 219 | 220 | // cleanup value 221 | 222 | ptr = &value[strlen(value)]; // pointer to string terminator 223 | 224 | while (*value == ' ') value++; // remove leading spaces 225 | 226 | while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces 227 | *ptr = '\0'; 228 | 229 | if (*value == '\0') return false; 230 | 231 | // end 232 | 233 | *name_ptr = name; 234 | *value_ptr = value; 235 | 236 | return true; 237 | } 238 | 239 | // quit() 240 | 241 | void quit() { 242 | 243 | char string[StringSize]; 244 | 245 | my_log("POLYGLOT *** QUIT ***\n"); 246 | 247 | if (Init) { 248 | 249 | stop_search(); 250 | engine_send(Engine,"quit"); 251 | 252 | // wait for the engine to quit 253 | 254 | while (true) { 255 | engine_get(Engine,string,StringSize); // HACK: calls exit() on receiving EOF 256 | } 257 | 258 | uci_close(Uci); 259 | } 260 | 261 | exit(EXIT_SUCCESS); 262 | } 263 | 264 | // stop_search() 265 | 266 | static void stop_search() { 267 | 268 | if (Init && Uci->searching) { 269 | 270 | ASSERT(Uci->searching); 271 | ASSERT(Uci->pending_nb>=1); 272 | 273 | my_log("POLYGLOT STOP SEARCH\n"); 274 | 275 | /* 276 | engine_send(Engine,"stop"); 277 | Uci->searching = false; 278 | */ 279 | 280 | if (option_get_bool("SyncStop")) { 281 | uci_send_stop_sync(Uci); 282 | } else { 283 | uci_send_stop(Uci); 284 | } 285 | } 286 | } 287 | 288 | // end of main.cpp 289 | 290 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | 2 | // main.h 3 | 4 | #ifndef MAIN_H 5 | #define MAIN_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern void quit (); 14 | 15 | #endif // !defined MAIN_H 16 | 17 | // end of main.h 18 | 19 | -------------------------------------------------------------------------------- /src/move.cpp: -------------------------------------------------------------------------------- 1 | 2 | // move.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | 9 | #include "attack.h" 10 | #include "colour.h" 11 | #include "list.h" 12 | #include "move.h" 13 | #include "move_do.h" 14 | #include "move_gen.h" 15 | #include "move_legal.h" 16 | #include "option.h" 17 | #include "piece.h" 18 | #include "square.h" 19 | #include "util.h" 20 | 21 | // "constants" 22 | 23 | static const uint8 PromotePiece[5] = { PieceNone64, Knight64, Bishop64, Rook64, Queen64 }; 24 | 25 | // functions 26 | 27 | // move_is_ok() 28 | 29 | bool move_is_ok(int move) { 30 | 31 | if (move < 0 || move >= 65536) return false; 32 | 33 | if (move == MoveNone) return false; 34 | 35 | return true; 36 | } 37 | 38 | // move_make() 39 | 40 | int move_make(int from, int to) { 41 | 42 | ASSERT(square_is_ok(from)); 43 | ASSERT(square_is_ok(to)); 44 | 45 | return (square_to_64(from) << 6) | square_to_64(to); 46 | } 47 | 48 | // move_make_flags() 49 | 50 | int move_make_flags(int from, int to, int flags) { 51 | 52 | ASSERT(square_is_ok(from)); 53 | ASSERT(square_is_ok(to)); 54 | ASSERT((flags&~0xF000)==0); 55 | 56 | ASSERT(to!=from); 57 | 58 | return (square_to_64(from) << 6) | square_to_64(to) | flags; 59 | } 60 | 61 | // move_from() 62 | 63 | int move_from(int move) { 64 | 65 | int from_64; 66 | 67 | ASSERT(move_is_ok(move)); 68 | 69 | from_64 = (move >> 6) & 077; 70 | 71 | return square_from_64(from_64); 72 | } 73 | 74 | // move_to() 75 | 76 | int move_to(int move) { 77 | 78 | int to_64; 79 | 80 | ASSERT(move_is_ok(move)); 81 | 82 | to_64 = move & 077; 83 | 84 | return square_from_64(to_64); 85 | } 86 | 87 | // move_promote_hack() 88 | 89 | int move_promote_hack(int move) { 90 | 91 | int code; 92 | 93 | ASSERT(move_is_ok(move)); 94 | 95 | ASSERT(move_is_promote(move)); 96 | 97 | code = move >> 12; 98 | ASSERT(code>=1&&code<=4); 99 | 100 | return PromotePiece[code]; 101 | } 102 | 103 | // move_is_capture() 104 | 105 | bool move_is_capture(int move, const board_t * board) { 106 | 107 | ASSERT(move_is_ok(move)); 108 | ASSERT(board_is_ok(board)); 109 | 110 | if (move_is_en_passant(move,board)) return true; 111 | if (board->square[move_to(move)] != Empty) return true; 112 | 113 | return false; 114 | } 115 | 116 | // move_is_promote() 117 | 118 | bool move_is_promote(int move) { 119 | 120 | ASSERT(move_is_ok(move)); 121 | 122 | return (move & MoveFlags) != 0; 123 | } 124 | 125 | // move_is_en_passant() 126 | 127 | bool move_is_en_passant(int move, const board_t * board) { 128 | 129 | ASSERT(move_is_ok(move)); 130 | ASSERT(board_is_ok(board)); 131 | 132 | return piece_is_pawn(move_piece(move,board)) 133 | && move_to(move) == board->ep_square; 134 | } 135 | 136 | // move_is_castle() 137 | 138 | bool move_is_castle(int move, const board_t * board) { 139 | 140 | ASSERT(move_is_ok(move)); 141 | ASSERT(board_is_ok(board)); 142 | 143 | return colour_equal(board->square[move_to(move)],board->turn); 144 | } 145 | 146 | // move_piece() 147 | 148 | int move_piece(int move, const board_t * board) { 149 | 150 | ASSERT(move_is_ok(move)); 151 | ASSERT(board_is_ok(board)); 152 | 153 | return board->square[move_from(move)]; 154 | } 155 | 156 | // move_capture() 157 | 158 | int move_capture(int move, const board_t * board) { 159 | 160 | ASSERT(move_is_ok(move)); 161 | ASSERT(board_is_ok(board)); 162 | 163 | if (move_is_en_passant(move,board)) { 164 | return piece_pawn_opp(move_piece(move,board)); 165 | } 166 | 167 | return board->square[move_to(move)]; 168 | } 169 | 170 | // move_promote() 171 | 172 | int move_promote(int move, const board_t * board) { 173 | 174 | int code; 175 | 176 | ASSERT(move_is_ok(move)); 177 | ASSERT(board_is_ok(board)); 178 | 179 | if (move_is_promote(move)) { 180 | code = move >> 12; 181 | ASSERT(code>=1&&code<=4); 182 | return PromotePiece[code] | board->turn; 183 | } 184 | 185 | return Empty; 186 | } 187 | 188 | // move_is_check() 189 | 190 | bool move_is_check(int move, const board_t * board) { 191 | 192 | board_t new_board[1]; 193 | 194 | ASSERT(move_is_ok(move)); 195 | ASSERT(board_is_ok(board)); 196 | 197 | board_copy(new_board,board); 198 | move_do(new_board,move); 199 | ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); 200 | 201 | return board_is_check(new_board); 202 | } 203 | 204 | // move_is_mate() 205 | 206 | bool move_is_mate(int move, const board_t * board) { 207 | 208 | board_t new_board[1]; 209 | 210 | ASSERT(move_is_ok(move)); 211 | ASSERT(board_is_ok(board)); 212 | 213 | board_copy(new_board,board); 214 | move_do(new_board,move); 215 | ASSERT(!is_in_check(new_board,colour_opp(new_board->turn))); 216 | 217 | return board_is_mate(new_board); 218 | } 219 | 220 | // move_to_can() 221 | 222 | bool move_to_can(int move, const board_t * board, char string[], int size) { 223 | 224 | int from, to; 225 | 226 | ASSERT(move_is_ok(move)); 227 | ASSERT(board_is_ok(board)); 228 | ASSERT(string!=NULL); 229 | ASSERT(size>=6); 230 | 231 | ASSERT(move_is_legal(move,board)); 232 | 233 | if (size < 6) return false; 234 | 235 | // init 236 | 237 | from = move_from(move); 238 | to = move_to(move); 239 | 240 | // king-slide castling 241 | 242 | if (move_is_castle(move,board) && !option_get_bool("Chess960")) { 243 | if (false) { 244 | } else if (from == E1 && to == H1) { 245 | to = G1; 246 | } else if (from == E1 && to == A1) { 247 | to = C1; 248 | } else if (from == E8 && to == H8) { 249 | to = G8; 250 | } else if (from == E8 && to == A8) { 251 | to = C8; 252 | } 253 | } 254 | 255 | // normal moves 256 | 257 | if (!square_to_string(from,&string[0],3)) ASSERT(false); 258 | if (!square_to_string(to,&string[2],3)) ASSERT(false); 259 | ASSERT(strlen(string)==4); 260 | 261 | // promotes 262 | 263 | if (move_is_promote(move)) { 264 | string[4] = piece_to_char(move_promote_hack(move)|Black); // HACK: black => lower-case 265 | string[5] = '\0'; 266 | } 267 | 268 | // debug 269 | 270 | ASSERT(move_from_can(string,board)==move); 271 | 272 | return true; 273 | } 274 | 275 | // move_from_can() 276 | 277 | int move_from_can(const char string[], const board_t * board) { 278 | 279 | char tmp_string[256]; 280 | int from, to; 281 | int side; 282 | int move; 283 | 284 | ASSERT(string!=NULL); 285 | ASSERT(board_is_ok(board)); 286 | 287 | // from 288 | 289 | tmp_string[0] = string[0]; 290 | tmp_string[1] = string[1]; 291 | tmp_string[2] = '\0'; 292 | 293 | from = square_from_string(tmp_string); 294 | if (from == SquareNone) return MoveNone; 295 | 296 | // to 297 | 298 | tmp_string[0] = string[2]; 299 | tmp_string[1] = string[3]; 300 | tmp_string[2] = '\0'; 301 | 302 | to = square_from_string(tmp_string); 303 | if (to == SquareNone) return MoveNone; 304 | 305 | // convert "king slide" castling to KxR 306 | 307 | if (piece_is_king(board->square[from]) 308 | && square_rank(to) == square_rank(from) 309 | && abs(to-from) > 1) { 310 | side = (to > from) ? SideH : SideA; 311 | to = board->castle[board->turn][side]; 312 | if (to == SquareNone) return MoveNone; 313 | } 314 | 315 | // move 316 | 317 | move = move_make(from,to); 318 | 319 | // promote 320 | 321 | switch (string[4]) { 322 | case '\0': // not a promotion 323 | if (piece_is_pawn(board->square[from]) 324 | && square_side_rank(to,board->turn) == Rank8 325 | && option_get_bool("PromoteWorkAround")) { 326 | move |= MovePromoteQueen; 327 | } 328 | break; 329 | case 'N': 330 | case 'n': 331 | move |= MovePromoteKnight; 332 | break; 333 | case 'B': 334 | case 'b': 335 | move |= MovePromoteBishop; 336 | break; 337 | case 'R': 338 | case 'r': 339 | move |= MovePromoteRook; 340 | break; 341 | case 'Q': 342 | case 'q': 343 | move |= MovePromoteQueen; 344 | break; 345 | default: 346 | return MoveNone; 347 | break; 348 | } 349 | 350 | // debug 351 | 352 | ASSERT(move_is_legal(move,board)); 353 | 354 | return move; 355 | } 356 | 357 | // move_order() 358 | 359 | int move_order(int move) { 360 | 361 | ASSERT(move_is_ok(move)); 362 | 363 | return ((move & 07777) << 3) | (move >> 12); // from, to, promote 364 | } 365 | 366 | // move_disp() 367 | 368 | void move_disp(int move, const board_t * board) { 369 | 370 | char string[256]; 371 | 372 | ASSERT(move_is_ok(move)); 373 | ASSERT(board_is_ok(board)); 374 | 375 | if (!move_to_can(move,board,string,256)) ASSERT(false); 376 | my_log("POLYGLOT %s\n",string); 377 | } 378 | 379 | // end of move.cpp 380 | 381 | -------------------------------------------------------------------------------- /src/move.h: -------------------------------------------------------------------------------- 1 | 2 | // move.h 3 | 4 | #ifndef MOVE_H 5 | #define MOVE_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // constants 13 | 14 | const int MoveNone = 0; // HACK: a1a1 cannot be a legal move 15 | 16 | const int MovePromoteKnight = 1 << 12; 17 | const int MovePromoteBishop = 2 << 12; 18 | const int MovePromoteRook = 3 << 12; 19 | const int MovePromoteQueen = 4 << 12; 20 | const int MoveFlags = 7 << 12; 21 | 22 | // types 23 | 24 | typedef uint16 move_t; 25 | 26 | // functions 27 | 28 | extern bool move_is_ok (int move); 29 | 30 | extern int move_make (int from, int to); 31 | extern int move_make_flags (int from, int to, int flags); 32 | 33 | extern int move_from (int move); 34 | extern int move_to (int move); 35 | extern int move_promote_hack (int move); 36 | 37 | extern bool move_is_capture (int move, const board_t * board); 38 | extern bool move_is_promote (int move); 39 | extern bool move_is_en_passant (int move, const board_t * board); 40 | extern bool move_is_castle (int move, const board_t * board); 41 | 42 | extern int move_piece (int move, const board_t * board); 43 | extern int move_capture (int move, const board_t * board); 44 | extern int move_promote (int move, const board_t * board); 45 | 46 | extern bool move_is_check (int move, const board_t * board); 47 | extern bool move_is_mate (int move, const board_t * board); 48 | 49 | extern int move_order (int move); 50 | 51 | extern bool move_to_can (int move, const board_t * board, char string[], int size); 52 | extern int move_from_can (const char string[], const board_t * board); 53 | 54 | extern void move_disp (int move, const board_t * board); 55 | 56 | #endif // !defined MOVE_H 57 | 58 | // end of move.h 59 | 60 | -------------------------------------------------------------------------------- /src/move_do.cpp: -------------------------------------------------------------------------------- 1 | 2 | // move_do.cpp 3 | 4 | // includes 5 | 6 | #include 7 | 8 | #include "board.h" 9 | #include "colour.h" 10 | #include "hash.h" 11 | #include "move.h" 12 | #include "move_do.h" 13 | #include "move_legal.h" 14 | #include "piece.h" 15 | #include "random.h" 16 | #include "util.h" 17 | 18 | // prototypes 19 | 20 | static void square_clear (board_t * board, int square, int piece); 21 | static void square_set (board_t * board, int square, int piece, int pos); 22 | static void square_move (board_t * board, int from, int to, int piece); 23 | 24 | // functions 25 | 26 | // move_do() 27 | 28 | void move_do(board_t * board, int move) { 29 | 30 | int me, opp; 31 | int from, to; 32 | int piece, pos, capture; 33 | int old_flags, new_flags; 34 | int sq, ep_square; 35 | int pawn; 36 | 37 | ASSERT(board_is_ok(board)); 38 | ASSERT(move_is_ok(move)); 39 | 40 | ASSERT(move_is_pseudo(move,board)); 41 | 42 | // init 43 | 44 | me = board->turn; 45 | opp = colour_opp(me); 46 | 47 | from = move_from(move); 48 | to = move_to(move); 49 | 50 | piece = board->square[from]; 51 | ASSERT(colour_equal(piece,me)); 52 | 53 | pos = board->pos[from]; 54 | ASSERT(pos>=0); 55 | 56 | // update turn 57 | 58 | board->turn = opp; 59 | board->key ^= random_64(RandomTurn); 60 | 61 | // update castling rights 62 | 63 | old_flags = board_flags(board); 64 | 65 | if (piece_is_king(piece)) { 66 | board->castle[me][SideH] = SquareNone; 67 | board->castle[me][SideA] = SquareNone; 68 | } 69 | 70 | if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone; 71 | if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone; 72 | 73 | if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone; 74 | if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone; 75 | 76 | new_flags = board_flags(board); 77 | 78 | board->key ^= hash_castle_key(new_flags^old_flags); // HACK 79 | 80 | // update en-passant square 81 | 82 | ep_square = sq = board->ep_square; 83 | if (sq != SquareNone) { 84 | board->key ^= random_64(RandomEnPassant+square_file(sq)); 85 | board->ep_square = SquareNone; 86 | } 87 | 88 | if (piece_is_pawn(piece) && abs(to-from) == 32) { 89 | pawn = piece_make_pawn(opp); 90 | if (board->square[to-1] == pawn || board->square[to+1] == pawn) { 91 | board->ep_square = sq = (from + to) / 2; 92 | board->key ^= random_64(RandomEnPassant+square_file(sq)); 93 | } 94 | } 95 | 96 | // update ply number (captures are handled later) 97 | 98 | board->ply_nb++; 99 | if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion 100 | 101 | // update move number 102 | 103 | if (me == Black) board->move_nb++; 104 | 105 | // castle 106 | 107 | if (colour_equal(board->square[to],me)) { 108 | 109 | int rank; 110 | int king_from, king_to; 111 | int rook_from, rook_to; 112 | int rook; 113 | 114 | rank = colour_is_white(me) ? Rank1 : Rank8; 115 | 116 | king_from = from; 117 | rook_from = to; 118 | 119 | if (to > from) { // h side 120 | king_to = square_make(FileG,rank); 121 | rook_to = square_make(FileF,rank); 122 | } else { // a side 123 | king_to = square_make(FileC,rank); 124 | rook_to = square_make(FileD,rank); 125 | } 126 | 127 | // remove the rook 128 | 129 | pos = board->pos[rook_from]; 130 | ASSERT(pos>=0); 131 | 132 | rook = Rook64 | me; // HACK 133 | 134 | square_clear(board,rook_from,rook); 135 | 136 | // move the king 137 | 138 | square_move(board,king_from,king_to,piece); 139 | 140 | // put the rook back 141 | 142 | square_set(board,rook_to,rook,pos); 143 | 144 | ASSERT(board->key==hash_key(board)); 145 | 146 | return; 147 | } 148 | 149 | // remove the captured piece 150 | 151 | if (piece_is_pawn(piece) && to == ep_square) { 152 | 153 | // en-passant capture 154 | 155 | sq = square_ep_dual(to); 156 | capture = board->square[sq]; 157 | ASSERT(capture==piece_make_pawn(opp)); 158 | 159 | square_clear(board,sq,capture); 160 | 161 | board->ply_nb = 0; // conversion 162 | 163 | } else { 164 | 165 | capture = board->square[to]; 166 | 167 | if (capture != Empty) { 168 | 169 | // normal capture 170 | 171 | ASSERT(colour_equal(capture,opp)); 172 | ASSERT(!piece_is_king(capture)); 173 | 174 | square_clear(board,to,capture); 175 | 176 | board->ply_nb = 0; // conversion 177 | } 178 | } 179 | 180 | // move the piece 181 | 182 | if (move_is_promote(move)) { 183 | 184 | // promote 185 | 186 | square_clear(board,from,piece); 187 | piece = move_promote_hack(move) | me; // HACK 188 | square_set(board,to,piece,pos); 189 | 190 | } else { 191 | 192 | // normal move 193 | 194 | square_move(board,from,to,piece); 195 | } 196 | 197 | ASSERT(board->key==hash_key(board)); 198 | } 199 | 200 | // square_clear() 201 | 202 | static void square_clear(board_t * board, int square, int piece) { 203 | 204 | int pos, piece_12, colour; 205 | int sq, size; 206 | 207 | ASSERT(board!=NULL); 208 | ASSERT(square_is_ok(square)); 209 | ASSERT(piece_is_ok(piece)); 210 | 211 | // init 212 | 213 | pos = board->pos[square]; 214 | ASSERT(pos>=0); 215 | 216 | colour = piece_colour(piece); 217 | piece_12 = piece_to_12(piece); 218 | 219 | // square 220 | 221 | ASSERT(board->square[square]==piece); 222 | board->square[square] = Empty; 223 | 224 | ASSERT(board->pos[square]==pos); 225 | board->pos[square] = -1; // not needed 226 | 227 | // piece list 228 | 229 | ASSERT(board->list_size[colour]>=2); 230 | size = --board->list_size[colour]; 231 | ASSERT(pos<=size); 232 | 233 | if (pos != size) { 234 | 235 | sq = board->list[colour][size]; 236 | ASSERT(square_is_ok(sq)); 237 | ASSERT(sq!=square); 238 | 239 | ASSERT(board->pos[sq]==size); 240 | board->pos[sq] = pos; 241 | 242 | ASSERT(board->list[colour][pos]==square); 243 | board->list[colour][pos] = sq; 244 | } 245 | 246 | board->list[colour][size] = SquareNone; 247 | 248 | // material 249 | 250 | ASSERT(board->number[piece_12]>=1); 251 | board->number[piece_12]--; 252 | 253 | // hash key 254 | 255 | board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); 256 | } 257 | 258 | // square_set() 259 | 260 | static void square_set(board_t * board, int square, int piece, int pos) { 261 | 262 | int piece_12, colour; 263 | int sq, size; 264 | 265 | ASSERT(board!=NULL); 266 | ASSERT(square_is_ok(square)); 267 | ASSERT(piece_is_ok(piece)); 268 | ASSERT(pos>=0); 269 | 270 | // init 271 | 272 | colour = piece_colour(piece); 273 | piece_12 = piece_to_12(piece); 274 | 275 | // square 276 | 277 | ASSERT(board->square[square]==Empty); 278 | board->square[square] = piece; 279 | 280 | ASSERT(board->pos[square]==-1); 281 | board->pos[square] = pos; 282 | 283 | // piece list 284 | 285 | size = board->list_size[colour]++; 286 | ASSERT(board->list[colour][size]==SquareNone); 287 | ASSERT(pos<=size); 288 | 289 | if (pos != size) { 290 | 291 | sq = board->list[colour][pos]; 292 | ASSERT(square_is_ok(sq)); 293 | ASSERT(sq!=square); 294 | 295 | ASSERT(board->pos[sq]==pos); 296 | board->pos[sq] = size; 297 | 298 | ASSERT(board->list[colour][size]==SquareNone); 299 | board->list[colour][size] = sq; 300 | } 301 | 302 | board->list[colour][pos] = square; 303 | 304 | // material 305 | 306 | ASSERT(board->number[piece_12]<=8); 307 | board->number[piece_12]++; 308 | 309 | // hash key 310 | 311 | board->key ^= random_64(RandomPiece+piece_12*64+square_to_64(square)); 312 | } 313 | 314 | // square_move() 315 | 316 | static void square_move(board_t * board, int from, int to, int piece) { 317 | 318 | int colour, pos; 319 | int piece_index; 320 | 321 | ASSERT(board!=NULL); 322 | ASSERT(square_is_ok(from)); 323 | ASSERT(square_is_ok(to)); 324 | ASSERT(piece_is_ok(piece)); 325 | 326 | // init 327 | 328 | colour = piece_colour(piece); 329 | 330 | pos = board->pos[from]; 331 | ASSERT(pos>=0); 332 | 333 | // from 334 | 335 | ASSERT(board->square[from]==piece); 336 | board->square[from] = Empty; 337 | 338 | ASSERT(board->pos[from]==pos); 339 | board->pos[from] = -1; // not needed 340 | 341 | // to 342 | 343 | ASSERT(board->square[to]==Empty); 344 | board->square[to] = piece; 345 | 346 | ASSERT(board->pos[to]==-1); 347 | board->pos[to] = pos; 348 | 349 | // piece list 350 | 351 | ASSERT(board->list[colour][pos]==from); 352 | board->list[colour][pos] = to; 353 | 354 | // hash key 355 | 356 | piece_index = RandomPiece + piece_to_12(piece) * 64; 357 | 358 | board->key ^= random_64(piece_index+square_to_64(from)) 359 | ^ random_64(piece_index+square_to_64(to)); 360 | } 361 | 362 | // end of move_do.cpp 363 | 364 | -------------------------------------------------------------------------------- /src/move_do.h: -------------------------------------------------------------------------------- 1 | 2 | // move_do.h 3 | 4 | #ifndef MOVE_DO_H 5 | #define MOVE_DO_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // functions 13 | 14 | extern void move_do (board_t * board, int move); 15 | 16 | #endif // !defined MOVE_DO_H 17 | 18 | // end of move_do.h 19 | 20 | -------------------------------------------------------------------------------- /src/move_gen.cpp: -------------------------------------------------------------------------------- 1 | 2 | // move_gen.cpp 3 | 4 | // includes 5 | 6 | #include "attack.h" 7 | #include "board.h" 8 | #include "colour.h" 9 | #include "list.h" 10 | #include "move.h" 11 | #include "move_gen.h" 12 | #include "move_legal.h" 13 | #include "piece.h" 14 | #include "util.h" 15 | 16 | // prototypes 17 | 18 | static void add_all_moves (list_t * list, const board_t * board); 19 | static void add_castle_moves (list_t * list, const board_t * board); 20 | 21 | static void add_pawn_move (list_t * list, int from, int to); 22 | 23 | // functions 24 | 25 | // gen_legal_moves() 26 | 27 | void gen_legal_moves(list_t * list, const board_t * board) { 28 | 29 | ASSERT(list!=NULL); 30 | ASSERT(board_is_ok(board)); 31 | 32 | gen_moves(list,board); 33 | filter_legal(list,board); 34 | } 35 | 36 | // gen_moves() 37 | 38 | void gen_moves(list_t * list, const board_t * board) { 39 | 40 | ASSERT(list!=NULL); 41 | ASSERT(board_is_ok(board)); 42 | 43 | list_clear(list); 44 | 45 | add_all_moves(list,board); 46 | if (!is_in_check(board,board->turn)) add_castle_moves(list,board); 47 | } 48 | 49 | // add_all_moves() 50 | 51 | static void add_all_moves(list_t * list, const board_t * board) { 52 | 53 | int me, opp; 54 | const uint8 * ptr; 55 | const sint8 * ptr_inc; 56 | int from, to; 57 | int inc; 58 | int piece, capture; 59 | 60 | ASSERT(list_is_ok(list)); 61 | ASSERT(board_is_ok(board)); 62 | 63 | me = board->turn; 64 | opp = colour_opp(me); 65 | 66 | for (ptr = board->list[me]; (from=*ptr) != SquareNone; ptr++) { 67 | 68 | piece = board->square[from]; 69 | ASSERT(colour_equal(piece,me)); 70 | 71 | switch (piece_type(piece)) { 72 | 73 | case WhitePawn64: 74 | 75 | to = from + 15; 76 | if (to == board->ep_square || colour_equal(board->square[to],opp)) { 77 | add_pawn_move(list,from,to); 78 | } 79 | 80 | to = from + 17; 81 | if (to == board->ep_square || colour_equal(board->square[to],opp)) { 82 | add_pawn_move(list,from,to); 83 | } 84 | 85 | to = from + 16; 86 | if (board->square[to] == Empty) { 87 | add_pawn_move(list,from,to); 88 | if (square_rank(from) == Rank2) { 89 | to = from + 32; 90 | if (board->square[to] == Empty) { 91 | ASSERT(!square_is_promote(to)); 92 | list_add(list,move_make(from,to)); 93 | } 94 | } 95 | } 96 | 97 | break; 98 | 99 | case BlackPawn64: 100 | 101 | to = from - 17; 102 | if (to == board->ep_square || colour_equal(board->square[to],opp)) { 103 | add_pawn_move(list,from,to); 104 | } 105 | 106 | to = from - 15; 107 | if (to == board->ep_square || colour_equal(board->square[to],opp)) { 108 | add_pawn_move(list,from,to); 109 | } 110 | 111 | to = from - 16; 112 | if (board->square[to] == Empty) { 113 | add_pawn_move(list,from,to); 114 | if (square_rank(from) == Rank7) { 115 | to = from - 32; 116 | if (board->square[to] == Empty) { 117 | ASSERT(!square_is_promote(to)); 118 | list_add(list,move_make(from,to)); 119 | } 120 | } 121 | } 122 | 123 | break; 124 | 125 | case Knight64: 126 | 127 | for (ptr_inc = KnightInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { 128 | to = from + inc; 129 | capture = board->square[to]; 130 | if (capture == Empty || colour_equal(capture,opp)) { 131 | list_add(list,move_make(from,to)); 132 | } 133 | } 134 | 135 | break; 136 | 137 | case Bishop64: 138 | 139 | for (ptr_inc = BishopInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { 140 | for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { 141 | list_add(list,move_make(from,to)); 142 | } 143 | if (colour_equal(capture,opp)) { 144 | list_add(list,move_make(from,to)); 145 | } 146 | } 147 | 148 | break; 149 | 150 | case Rook64: 151 | 152 | for (ptr_inc = RookInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { 153 | for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { 154 | list_add(list,move_make(from,to)); 155 | } 156 | if (colour_equal(capture,opp)) { 157 | list_add(list,move_make(from,to)); 158 | } 159 | } 160 | 161 | break; 162 | 163 | case Queen64: 164 | 165 | for (ptr_inc = QueenInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { 166 | for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) { 167 | list_add(list,move_make(from,to)); 168 | } 169 | if (colour_equal(capture,opp)) { 170 | list_add(list,move_make(from,to)); 171 | } 172 | } 173 | 174 | break; 175 | 176 | case King64: 177 | 178 | for (ptr_inc = KingInc; (inc=*ptr_inc) != IncNone; ptr_inc++) { 179 | to = from + inc; 180 | capture = board->square[to]; 181 | if (capture == Empty || colour_equal(capture,opp)) { 182 | list_add(list,move_make(from,to)); 183 | } 184 | } 185 | 186 | break; 187 | 188 | default: 189 | 190 | ASSERT(false); 191 | break; 192 | } 193 | } 194 | } 195 | 196 | // add_castle_moves() 197 | 198 | static void add_castle_moves(list_t * list, const board_t * board) { 199 | 200 | int me, opp; 201 | int rank; 202 | int king_from, king_to; 203 | int rook_from, rook_to; 204 | bool legal; 205 | int inc; 206 | int sq; 207 | 208 | ASSERT(list_is_ok(list)); 209 | ASSERT(board_is_ok(board)); 210 | 211 | ASSERT(!is_in_check(board,board->turn)); 212 | 213 | me = board->turn; 214 | opp = colour_opp(me); 215 | 216 | rank = colour_is_white(me) ? Rank1 : Rank8; 217 | 218 | // h-side castling 219 | 220 | if (board->castle[me][SideH] != SquareNone) { 221 | 222 | king_from = king_pos(board,me); 223 | king_to = square_make(FileG,rank); 224 | rook_from = board->castle[me][SideH]; 225 | rook_to = square_make(FileF,rank); 226 | 227 | ASSERT(square_rank(king_from)==rank); 228 | ASSERT(square_rank(rook_from)==rank); 229 | ASSERT(board->square[king_from]==(King64|me)); // HACK 230 | ASSERT(board->square[rook_from]==(Rook64|me)); // HACK 231 | ASSERT(rook_from>king_from); 232 | 233 | legal = true; 234 | 235 | if (king_to != king_from) { 236 | 237 | inc = (king_to > king_from) ? +1 : -1; 238 | 239 | for (sq = king_from+inc; true; sq += inc) { 240 | 241 | if (sq != rook_from && board->square[sq] != Empty) legal = false; 242 | if (is_attacked(board,sq,opp)) legal = false; 243 | 244 | if (sq == king_to) break; 245 | } 246 | } 247 | 248 | if (rook_to != rook_from) { 249 | 250 | inc = (rook_to > rook_from) ? +1 : -1; 251 | 252 | for (sq = rook_from+inc; true; sq += inc) { 253 | if (sq != king_from && board->square[sq] != Empty) legal = false; 254 | if (sq == rook_to) break; 255 | } 256 | } 257 | 258 | if (legal) list_add(list,move_make(king_from,rook_from)); 259 | } 260 | 261 | // a-side castling 262 | 263 | if (board->castle[me][SideA] != SquareNone) { 264 | 265 | king_from = king_pos(board,me); 266 | king_to = square_make(FileC,rank); 267 | rook_from = board->castle[me][SideA]; 268 | rook_to = square_make(FileD,rank); 269 | 270 | ASSERT(square_rank(king_from)==rank); 271 | ASSERT(square_rank(rook_from)==rank); 272 | ASSERT(board->square[king_from]==(King64|me)); // HACK 273 | ASSERT(board->square[rook_from]==(Rook64|me)); // HACK 274 | ASSERT(rook_from king_from) ? +1 : -1; 281 | 282 | for (sq = king_from+inc; true; sq += inc) { 283 | 284 | if (sq != rook_from && board->square[sq] != Empty) legal = false; 285 | if (is_attacked(board,sq,opp)) legal = false; 286 | 287 | if (sq == king_to) break; 288 | } 289 | } 290 | 291 | if (rook_to != rook_from) { 292 | 293 | inc = (rook_to > rook_from) ? +1 : -1; 294 | 295 | for (sq = rook_from+inc; true; sq += inc) { 296 | if (sq != king_from && board->square[sq] != Empty) legal = false; 297 | if (sq == rook_to) break; 298 | } 299 | } 300 | 301 | if (legal) list_add(list,move_make(king_from,rook_from)); 302 | } 303 | } 304 | 305 | // add_pawn_move() 306 | 307 | static void add_pawn_move(list_t * list, int from, int to) { 308 | 309 | int move; 310 | 311 | ASSERT(list_is_ok(list)); 312 | ASSERT(square_is_ok(from)); 313 | ASSERT(square_is_ok(to)); 314 | 315 | move = move_make(from,to); 316 | 317 | if (square_is_promote(to)) { 318 | list_add(list,move|MovePromoteKnight); 319 | list_add(list,move|MovePromoteBishop); 320 | list_add(list,move|MovePromoteRook); 321 | list_add(list,move|MovePromoteQueen); 322 | } else { 323 | list_add(list,move); 324 | } 325 | } 326 | 327 | // end of move_gen.cpp 328 | 329 | -------------------------------------------------------------------------------- /src/move_gen.h: -------------------------------------------------------------------------------- 1 | 2 | // move_gen.h 3 | 4 | #ifndef MOVE_GEN_H 5 | #define MOVE_GEN_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "list.h" 11 | #include "util.h" 12 | 13 | // functions 14 | 15 | extern void gen_legal_moves (list_t * list, const board_t * board); 16 | extern void gen_moves (list_t * list, const board_t * board); 17 | 18 | #endif // !defined MOVE_GEN_H 19 | 20 | // end of move_gen.h 21 | 22 | -------------------------------------------------------------------------------- /src/move_legal.cpp: -------------------------------------------------------------------------------- 1 | 2 | // move_legal.cpp 3 | 4 | // includes 5 | 6 | #include "attack.h" 7 | #include "colour.h" 8 | #include "fen.h" 9 | #include "list.h" 10 | #include "move.h" 11 | #include "move_do.h" 12 | #include "move_gen.h" 13 | #include "move_legal.h" 14 | #include "piece.h" 15 | #include "square.h" 16 | #include "util.h" 17 | 18 | // prototypes 19 | 20 | static bool move_is_legal_debug (int move, const board_t * board); 21 | 22 | // functions 23 | 24 | // move_is_pseudo() 25 | 26 | bool move_is_pseudo(int move, const board_t * board) { 27 | 28 | list_t list[1]; 29 | 30 | ASSERT(move_is_ok(move)); 31 | ASSERT(board_is_ok(board)); 32 | 33 | gen_moves(list,board); 34 | 35 | return list_contain(list,move); 36 | } 37 | 38 | // pseudo_is_legal() 39 | 40 | bool pseudo_is_legal(int move, const board_t * board) { 41 | 42 | board_t new_board[1]; 43 | 44 | ASSERT(move_is_ok(move)); 45 | ASSERT(board_is_ok(board)); 46 | 47 | ASSERT(move_is_pseudo(move,board)); 48 | 49 | board_copy(new_board,board); 50 | move_do(new_board,move); 51 | 52 | return !is_in_check(new_board,colour_opp(new_board->turn)); 53 | } 54 | 55 | // move_is_legal() 56 | 57 | bool move_is_legal(int move, const board_t * board) { 58 | 59 | bool legal; 60 | 61 | ASSERT(move_is_ok(move)); 62 | ASSERT(board_is_ok(board)); 63 | 64 | legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board); 65 | ASSERT(legal==move_is_legal_debug(move,board)); 66 | 67 | return legal; 68 | } 69 | 70 | // filter_legal() 71 | 72 | void filter_legal(list_t * list, const board_t * board) { 73 | 74 | int pos; 75 | int i, move, value; 76 | 77 | ASSERT(list_is_ok(list)); 78 | ASSERT(board_is_ok(board)); 79 | 80 | pos = 0; 81 | 82 | for (i = 0; i < list_size(list); i++) { 83 | 84 | ASSERT(pos>=0&&pos<=i); 85 | 86 | move = list_move(list,i); 87 | value = list_value(list,i); 88 | 89 | if (pseudo_is_legal(move,board)) { 90 | list->move[pos] = move; 91 | list->value[pos] = value; 92 | pos++; 93 | } 94 | } 95 | 96 | ASSERT(pos>=0&&pos<=list_size(list)); 97 | list->size = pos; 98 | } 99 | 100 | // move_is_legal_debug() 101 | 102 | static bool move_is_legal_debug(int move, const board_t * board) { 103 | 104 | list_t list[1]; 105 | 106 | ASSERT(move_is_ok(move)); 107 | ASSERT(board_is_ok(board)); 108 | 109 | gen_legal_moves(list,board); 110 | 111 | return list_contain(list,move); 112 | } 113 | 114 | // end of move_legal.cpp 115 | 116 | -------------------------------------------------------------------------------- /src/move_legal.h: -------------------------------------------------------------------------------- 1 | 2 | // move_legal.h 3 | 4 | #ifndef MOVE_LEGAL_H 5 | #define MOVE_LEGAL_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "list.h" 11 | #include "util.h" 12 | 13 | // functions 14 | 15 | extern bool move_is_pseudo (int move, const board_t * board); 16 | extern bool pseudo_is_legal (int move, const board_t * board); 17 | extern bool move_is_legal (int move, const board_t * board); 18 | 19 | extern void filter_legal (list_t * list, const board_t * board); 20 | 21 | #endif // !defined MOVE_LEGAL_H 22 | 23 | // end of move_legal.h 24 | 25 | -------------------------------------------------------------------------------- /src/option.cpp: -------------------------------------------------------------------------------- 1 | 2 | // option.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | 9 | #include "option.h" 10 | #include "util.h" 11 | 12 | // constants 13 | 14 | static const bool UseDebug = false; 15 | 16 | // types 17 | 18 | struct option_t { 19 | const char * var; 20 | const char * val; 21 | }; 22 | 23 | // variables 24 | 25 | static option_t Option[] = { 26 | 27 | { "OptionFile", NULL, }, // string 28 | 29 | // options 30 | 31 | { "EngineName", NULL, }, // string 32 | { "EngineDir", NULL, }, // string 33 | { "EngineCommand", NULL, }, // string 34 | 35 | { "Log", NULL, }, // true/false 36 | { "LogFile", NULL, }, // string 37 | 38 | { "Chess960", NULL, }, // true/false 39 | 40 | { "Resign", NULL, }, // true/false 41 | { "ResignMoves", NULL, }, // move number 42 | { "ResignScore", NULL, }, // centipawns 43 | 44 | { "MateScore", NULL, }, // centipawns 45 | 46 | { "Book", NULL, }, // true/false 47 | { "BookFile", NULL, }, // string 48 | 49 | { "BookRandom", NULL, }, // true/false 50 | { "BookLearn", NULL, }, // true/false 51 | 52 | { "KibitzMove", NULL, }, // true/false 53 | { "KibitzPV", NULL, }, // true/false 54 | 55 | { "KibitzCommand", NULL, }, // string 56 | { "KibitzDelay", NULL, }, // seconds 57 | 58 | { "ShowPonder", NULL, }, // true/false 59 | 60 | // work-arounds 61 | 62 | { "UCIVersion", NULL, }, // 1- 63 | { "CanPonder", NULL, }, // true/false 64 | { "SyncStop", NULL, }, // true/false 65 | { "PromoteWorkAround", NULL, }, // true/false 66 | 67 | // { "", NULL, }, 68 | 69 | { NULL, NULL, }, 70 | }; 71 | 72 | // prototypes 73 | 74 | static option_t * option_find (const char var[]); 75 | 76 | // functions 77 | 78 | // option_init() 79 | 80 | void option_init() { 81 | 82 | option_set("OptionFile","polyglot.ini"); 83 | 84 | // options 85 | 86 | option_set("EngineName",""); 87 | option_set("EngineDir","."); 88 | option_set("EngineCommand",""); 89 | 90 | option_set("Log","false"); 91 | option_set("LogFile","polyglot.log"); 92 | 93 | option_set("Chess960","false"); 94 | 95 | option_set("Resign","false"); 96 | option_set("ResignMoves","3"); 97 | option_set("ResignScore","600"); 98 | 99 | option_set("MateScore","10000"); 100 | 101 | option_set("Book","false"); 102 | option_set("BookFile","book.bin"); 103 | 104 | option_set("BookRandom","true"); 105 | option_set("BookLearn","false"); 106 | 107 | option_set("KibitzMove","false"); 108 | option_set("KibitzPV","false"); 109 | 110 | option_set("KibitzCommand","tellall"); 111 | option_set("KibitzDelay","5"); 112 | 113 | option_set("ShowPonder","true"); 114 | 115 | // work-arounds 116 | 117 | option_set("UCIVersion","2"); 118 | option_set("CanPonder","false"); 119 | option_set("SyncStop","false"); 120 | option_set("PromoteWorkAround","false"); 121 | 122 | // option_set("",""); 123 | } 124 | 125 | // option_set() 126 | 127 | bool option_set(const char var[], const char val[]) { 128 | 129 | option_t * opt; 130 | 131 | ASSERT(var!=NULL); 132 | ASSERT(val!=NULL); 133 | 134 | opt = option_find(var); 135 | if (opt == NULL) return false; 136 | 137 | my_string_set(&opt->val,val); 138 | 139 | if (UseDebug) my_log("POLYGLOT OPTION SET \"%s\" -> \"%s\"\n",opt->var,opt->val); 140 | 141 | return true; 142 | } 143 | 144 | // option_get() 145 | 146 | const char * option_get(const char var[]) { 147 | 148 | option_t * opt; 149 | 150 | ASSERT(var!=NULL); 151 | 152 | opt = option_find(var); 153 | if (opt == NULL) my_fatal("option_get(): unknown option \"%s\"\n",var); 154 | 155 | if (UseDebug) my_log("POLYGLOT OPTION GET \"%s\" -> \"%s\"\n",opt->var,opt->val); 156 | 157 | return opt->val; 158 | } 159 | 160 | // option_get_bool() 161 | 162 | bool option_get_bool(const char var[]) { 163 | 164 | const char * val; 165 | 166 | val = option_get(var); 167 | 168 | if (false) { 169 | } else if (my_string_case_equal(val,"true") || my_string_case_equal(val,"yes") || my_string_equal(val,"1")) { 170 | return true; 171 | } else if (my_string_case_equal(val,"false") || my_string_case_equal(val,"no") || my_string_equal(val,"0")) { 172 | return false; 173 | } 174 | 175 | ASSERT(false); 176 | 177 | return false; 178 | } 179 | 180 | // option_get_double() 181 | 182 | double option_get_double(const char var[]) { 183 | 184 | const char * val; 185 | 186 | val = option_get(var); 187 | 188 | return atof(val); 189 | } 190 | 191 | // option_get_int() 192 | 193 | int option_get_int(const char var[]) { 194 | 195 | const char * val; 196 | 197 | val = option_get(var); 198 | 199 | return atoi(val); 200 | } 201 | 202 | // option_get_string() 203 | 204 | const char * option_get_string(const char var[]) { 205 | 206 | const char * val; 207 | 208 | val = option_get(var); 209 | 210 | return val; 211 | } 212 | 213 | // option_find() 214 | 215 | static option_t * option_find(const char var[]) { 216 | 217 | option_t * opt; 218 | 219 | ASSERT(var!=NULL); 220 | 221 | for (opt = &Option[0]; opt->var != NULL; opt++) { 222 | if (my_string_case_equal(opt->var,var)) return opt; 223 | } 224 | 225 | return NULL; 226 | } 227 | 228 | // end of option.cpp 229 | 230 | -------------------------------------------------------------------------------- /src/option.h: -------------------------------------------------------------------------------- 1 | 2 | // option.h 3 | 4 | #ifndef OPTION_H 5 | #define OPTION_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern void option_init (); 14 | 15 | extern bool option_set (const char var[], const char val[]); 16 | extern const char * option_get (const char var[]); 17 | 18 | extern bool option_get_bool (const char var[]); 19 | extern double option_get_double (const char var[]); 20 | extern int option_get_int (const char var[]); 21 | extern const char * option_get_string (const char var[]); 22 | 23 | #endif // !defined OPTION_H 24 | 25 | // end of option.h 26 | 27 | -------------------------------------------------------------------------------- /src/parse.cpp: -------------------------------------------------------------------------------- 1 | 2 | // parse.cpp 3 | 4 | // includes 5 | 6 | #include 7 | 8 | #include "parse.h" 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | static const int StringSize = 256; 14 | 15 | // variables 16 | 17 | char * Star[STAR_NUMBER]; 18 | 19 | // prototypes 20 | 21 | static bool match_rec (char string[], const char pattern[], char * star[]); 22 | 23 | // functions 24 | 25 | // match() 26 | 27 | bool match(char string[], const char pattern[]) { 28 | 29 | ASSERT(string!=NULL); 30 | ASSERT(pattern!=NULL); 31 | 32 | ASSERT(strstr(pattern,"**")==NULL); 33 | 34 | return match_rec(string,pattern,Star); 35 | } 36 | 37 | // match_rec() 38 | 39 | static bool match_rec(char string[], const char pattern[], char * star[]) { 40 | 41 | int c; 42 | 43 | ASSERT(string!=NULL); 44 | ASSERT(pattern!=NULL); 45 | ASSERT(star!=NULL); 46 | 47 | // iterative matches 48 | 49 | while ((c=*pattern++) != '*') { 50 | if (false) { 51 | } else if (c == '\0') { // end of pattern 52 | while (*string == ' ') string++; // skip trailing spaces 53 | return *string == '\0'; 54 | } else if (c == ' ') { // spaces 55 | if (*string++ != ' ') return false; // mismatch 56 | while (*string == ' ') string++; // skip trailing spaces 57 | } else { // normal character 58 | if (*string++ != c) return false; // mismatch 59 | } 60 | } 61 | 62 | // recursive wildcard match 63 | 64 | ASSERT(c=='*'); 65 | 66 | while (*string == ' ') string++; // skip leading spaces 67 | *star++ = string; // remember beginning of star 68 | 69 | while ((c=*string++) != '\0') { // reject empty-string match 70 | if (c != ' ' && match_rec(string,pattern,star)) { // shortest match 71 | ASSERT(string>star[-1]); 72 | *string = '\0'; // truncate star 73 | return true; 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | 80 | // parse_is_ok() 81 | 82 | bool parse_is_ok(const parse_t * parse) { 83 | 84 | if (parse == NULL) return false; 85 | if (parse->string == NULL) return false; 86 | if (parse->pos < 0 || parse->pos > strlen(parse->string)) return false; 87 | if (parse->keyword_nb < 0 || parse->keyword_nb >= KEYWORD_NUMBER) return false; 88 | 89 | return true; 90 | } 91 | 92 | // parse_open() 93 | 94 | void parse_open(parse_t * parse, const char string[]) { 95 | 96 | ASSERT(parse!=NULL); 97 | ASSERT(string!=NULL); 98 | 99 | parse->string = string; 100 | parse->pos = 0; 101 | parse->keyword_nb = 0; 102 | } 103 | 104 | // parse_close() 105 | 106 | void parse_close(parse_t * parse) { 107 | 108 | int i; 109 | 110 | ASSERT(parse_is_ok(parse)); 111 | 112 | parse->string = NULL; 113 | parse->pos = 0; 114 | 115 | for (i = 0; i < parse->keyword_nb; i++) { 116 | my_string_clear(&parse->keyword[i]); 117 | } 118 | 119 | parse->keyword_nb = 0; 120 | } 121 | 122 | // parse_add_keyword() 123 | 124 | void parse_add_keyword(parse_t * parse, const char keyword[]) { 125 | 126 | const char * * string; 127 | 128 | ASSERT(parse_is_ok(parse)); 129 | ASSERT(keyword!=NULL); 130 | 131 | if (parse->keyword_nb < KEYWORD_NUMBER) { 132 | 133 | string = &parse->keyword[parse->keyword_nb]; 134 | parse->keyword_nb++; 135 | 136 | *string = NULL; 137 | my_string_set(string,keyword); 138 | } 139 | } 140 | 141 | // parse_get_word() 142 | 143 | bool parse_get_word(parse_t * parse, char string[], int size) { 144 | 145 | int pos; 146 | int c; 147 | 148 | ASSERT(parse!=NULL); 149 | ASSERT(string!=NULL); 150 | ASSERT(size>=256); 151 | 152 | // skip blanks 153 | 154 | for (; parse->string[parse->pos] == ' '; parse->pos++) 155 | ; 156 | 157 | ASSERT(parse->string[parse->pos]!=' '); 158 | 159 | // copy word 160 | 161 | pos = 0; 162 | 163 | while (true) { 164 | 165 | c = parse->string[parse->pos]; 166 | if (c == ' ' || pos >= size-1) c = '\0'; 167 | 168 | string[pos] = c; 169 | if (c == '\0') break; 170 | 171 | parse->pos++; 172 | pos++; 173 | } 174 | 175 | ASSERT(strchr(string,' ')==NULL); 176 | 177 | return pos > 0; // non-empty word? 178 | } 179 | 180 | // parse_get_string() 181 | 182 | bool parse_get_string(parse_t * parse, char string[], int size) { 183 | 184 | int pos; 185 | parse_t parse_2[1]; 186 | char word[StringSize]; 187 | int i; 188 | int c; 189 | 190 | ASSERT(parse!=NULL); 191 | ASSERT(string!=NULL); 192 | ASSERT(size>=256); 193 | 194 | // skip blanks 195 | 196 | for (; parse->string[parse->pos] == ' '; parse->pos++) 197 | ; 198 | 199 | ASSERT(parse->string[parse->pos]!=' '); 200 | 201 | // copy string 202 | 203 | pos = 0; 204 | 205 | while (true) { 206 | 207 | parse_open(parse_2,&parse->string[parse->pos]); 208 | 209 | if (!parse_get_word(parse_2,word,StringSize)) { 210 | string[pos] = '\0'; 211 | parse_close(parse_2); 212 | goto finished; 213 | } 214 | 215 | for (i = 0; i < parse->keyword_nb; i++) { 216 | if (my_string_equal(parse->keyword[i],word)) { 217 | string[pos] = '\0'; 218 | parse_close(parse_2); 219 | goto finished; 220 | } 221 | } 222 | 223 | parse_close(parse_2); 224 | 225 | // copy spaces 226 | 227 | while (true) { 228 | 229 | c = parse->string[parse->pos]; 230 | if (c != ' ') break; 231 | 232 | if (pos >= size-1) c = '\0'; 233 | 234 | string[pos] = c; 235 | if (c == '\0') break; 236 | 237 | parse->pos++; 238 | pos++; 239 | } 240 | 241 | // copy non spaces 242 | 243 | while (true) { 244 | 245 | c = parse->string[parse->pos]; 246 | if (c == ' ' || pos >= size-1) c = '\0'; 247 | 248 | string[pos] = c; 249 | if (c == '\0') break; 250 | 251 | parse->pos++; 252 | pos++; 253 | } 254 | 255 | string[pos] = '\0'; 256 | } 257 | 258 | finished: ; 259 | 260 | return pos > 0; // non-empty string? 261 | } 262 | 263 | // end of parse.cpp 264 | 265 | -------------------------------------------------------------------------------- /src/parse.h: -------------------------------------------------------------------------------- 1 | 2 | // parse.h 3 | 4 | #ifndef PARSE_H 5 | #define PARSE_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | const int STAR_NUMBER = 16; 14 | const int KEYWORD_NUMBER = 256; 15 | 16 | // types 17 | 18 | struct parse_t { 19 | const char * string; 20 | int pos; 21 | int keyword_nb; 22 | const char * keyword[KEYWORD_NUMBER]; 23 | }; 24 | 25 | // variables 26 | 27 | extern char * Star[STAR_NUMBER]; 28 | 29 | // functions 30 | 31 | extern bool match (char string[], const char pattern[]); 32 | 33 | extern void parse_open (parse_t * parse, const char string[]); 34 | extern void parse_close (parse_t * parse); 35 | 36 | extern void parse_add_keyword (parse_t * parse, const char keyword[]); 37 | 38 | extern bool parse_get_word (parse_t * parse, char string[], int size); 39 | extern bool parse_get_string (parse_t * parse, char string[], int size); 40 | 41 | #endif // !defined PARSE_H 42 | 43 | // end of parse.h 44 | 45 | -------------------------------------------------------------------------------- /src/pgn.h: -------------------------------------------------------------------------------- 1 | 2 | // pgn.h 3 | 4 | #ifndef PGN_H 5 | #define PGN_H 6 | 7 | // includes 8 | 9 | #include 10 | 11 | #include "util.h" 12 | 13 | // constants 14 | 15 | const int PGN_STRING_SIZE = 256; 16 | 17 | // types 18 | 19 | struct pgn_t { 20 | 21 | FILE * file; 22 | 23 | int char_hack; 24 | int char_line; 25 | int char_column; 26 | bool char_unread; 27 | bool char_first; 28 | 29 | int token_type; 30 | char token_string[PGN_STRING_SIZE]; 31 | int token_length; 32 | int token_line; 33 | int token_column; 34 | bool token_unread; 35 | bool token_first; 36 | 37 | long int last_stream_pos; 38 | 39 | char result[PGN_STRING_SIZE]; 40 | char fen[PGN_STRING_SIZE]; 41 | char white[PGN_STRING_SIZE]; 42 | char whiteelo[PGN_STRING_SIZE]; 43 | char black[PGN_STRING_SIZE]; 44 | char blackelo[PGN_STRING_SIZE]; 45 | char date[PGN_STRING_SIZE]; 46 | char event[PGN_STRING_SIZE]; 47 | char site[PGN_STRING_SIZE]; 48 | char eco[PGN_STRING_SIZE]; 49 | 50 | char plycount[PGN_STRING_SIZE]; 51 | char eventdate[PGN_STRING_SIZE]; 52 | char eventtype[PGN_STRING_SIZE]; 53 | 54 | int move_line; 55 | int move_column; 56 | }; 57 | 58 | // functions 59 | 60 | extern void pgn_open (pgn_t * pgn, const char file_name[]); 61 | extern void pgn_close (pgn_t * pgn); 62 | 63 | extern bool pgn_next_game (pgn_t * pgn); 64 | extern bool pgn_next_move (pgn_t * pgn, char string[], int size); 65 | 66 | #endif // !defined PGN_H 67 | 68 | // end of pgn.h 69 | 70 | -------------------------------------------------------------------------------- /src/piece.cpp: -------------------------------------------------------------------------------- 1 | 2 | // piece.cpp 3 | 4 | // includes 5 | 6 | #include 7 | 8 | #include "colour.h" 9 | #include "piece.h" 10 | #include "util.h" 11 | 12 | // "constants" 13 | 14 | static const uint8 MakePawn[ColourNb] = { PieceNone256, BlackPawn256, WhitePawn256 }; // -BW 15 | 16 | static const uint8 PieceFrom12[12] = { 17 | BlackPawn256, WhitePawn256, 18 | BlackKnight256, WhiteKnight256, 19 | BlackBishop256, WhiteBishop256, 20 | BlackRook256, WhiteRook256, 21 | BlackQueen256, WhiteQueen256, 22 | BlackKing256, WhiteKing256, 23 | }; 24 | 25 | static const char PieceString[12+1] = "pPnNbBrRqQkK"; 26 | 27 | // variables 28 | 29 | static sint8 PieceTo12[256]; 30 | 31 | // functions 32 | 33 | // piece_init() 34 | 35 | void piece_init() { 36 | 37 | int piece; 38 | 39 | for (piece = 0; piece < 256; piece++) PieceTo12[piece] = -1; 40 | 41 | for (piece = 0; piece < 12; piece++) { 42 | PieceTo12[PieceFrom12[piece]] = piece; 43 | } 44 | } 45 | 46 | // piece_is_ok() 47 | 48 | bool piece_is_ok(int piece) { 49 | 50 | if (piece < 0 || piece >= 256) return false; 51 | 52 | if (PieceTo12[piece] < 0) return false; 53 | 54 | return true; 55 | } 56 | 57 | // piece_make_pawn() 58 | 59 | int piece_make_pawn(int colour) { 60 | 61 | ASSERT(colour_is_ok(colour)); 62 | 63 | return MakePawn[colour]; 64 | } 65 | 66 | // piece_pawn_opp() 67 | 68 | int piece_pawn_opp(int piece) { 69 | 70 | ASSERT(piece==BlackPawn256||piece==WhitePawn256); 71 | 72 | return piece ^ 15; 73 | } 74 | 75 | // piece_colour() 76 | 77 | int piece_colour(int piece) { 78 | 79 | ASSERT(piece_is_ok(piece)); 80 | 81 | return piece & 3; 82 | } 83 | 84 | // piece_type() 85 | 86 | int piece_type(int piece) { 87 | 88 | ASSERT(piece_is_ok(piece)); 89 | 90 | return piece & ~3; 91 | } 92 | 93 | // piece_is_pawn() 94 | 95 | bool piece_is_pawn(int piece) { 96 | 97 | ASSERT(piece_is_ok(piece)); 98 | 99 | return (piece & PawnFlags) != 0; 100 | } 101 | 102 | // piece_is_knight() 103 | 104 | bool piece_is_knight(int piece) { 105 | 106 | ASSERT(piece_is_ok(piece)); 107 | 108 | return (piece & KnightFlag) != 0; 109 | } 110 | 111 | // piece_is_bishop() 112 | 113 | bool piece_is_bishop(int piece) { 114 | 115 | ASSERT(piece_is_ok(piece)); 116 | 117 | return (piece & QueenFlags) == BishopFlag; 118 | } 119 | 120 | // piece_is_rook() 121 | 122 | bool piece_is_rook(int piece) { 123 | 124 | ASSERT(piece_is_ok(piece)); 125 | 126 | return (piece & QueenFlags) == RookFlag; 127 | } 128 | 129 | // piece_is_queen() 130 | 131 | bool piece_is_queen(int piece) { 132 | 133 | ASSERT(piece_is_ok(piece)); 134 | 135 | return (piece & QueenFlags) == QueenFlags; 136 | } 137 | 138 | // piece_is_king() 139 | 140 | bool piece_is_king(int piece) { 141 | 142 | ASSERT(piece_is_ok(piece)); 143 | 144 | return (piece & KingFlag) != 0; 145 | } 146 | 147 | // piece_is_slider() 148 | 149 | bool piece_is_slider(int piece) { 150 | 151 | ASSERT(piece_is_ok(piece)); 152 | 153 | return (piece & QueenFlags) != 0; 154 | } 155 | 156 | // piece_to_12() 157 | 158 | int piece_to_12(int piece) { 159 | 160 | ASSERT(piece_is_ok(piece)); 161 | 162 | return PieceTo12[piece]; 163 | } 164 | 165 | // piece_from_12() 166 | 167 | int piece_from_12(int piece) { 168 | 169 | ASSERT(piece>=0&&piece<12); 170 | 171 | return PieceFrom12[piece]; 172 | } 173 | 174 | // piece_to_char() 175 | 176 | int piece_to_char(int piece) { 177 | 178 | ASSERT(piece_is_ok(piece)); 179 | 180 | return PieceString[piece_to_12(piece)]; 181 | } 182 | 183 | // piece_from_char() 184 | 185 | int piece_from_char(int c) { 186 | 187 | const char * ptr; 188 | 189 | ptr = strchr(PieceString,c); 190 | if (ptr == NULL) return PieceNone256; 191 | 192 | return piece_from_12(ptr-PieceString); 193 | } 194 | 195 | // char_is_piece() 196 | 197 | bool char_is_piece(int c) { 198 | 199 | return strchr("PNBRQK",c) != NULL; 200 | } 201 | 202 | // end of piece.cpp 203 | 204 | -------------------------------------------------------------------------------- /src/piece.h: -------------------------------------------------------------------------------- 1 | 2 | // piece.h 3 | 4 | #ifndef PIECE_H 5 | #define PIECE_H 6 | 7 | // includes 8 | 9 | #include "colour.h" 10 | #include "util.h" 11 | 12 | // constants 13 | 14 | const int BlackPawnFlag = 1 << 2; 15 | const int WhitePawnFlag = 1 << 3; 16 | const int KnightFlag = 1 << 4; 17 | const int BishopFlag = 1 << 5; 18 | const int RookFlag = 1 << 6; 19 | const int KingFlag = 1 << 7; 20 | 21 | const int PawnFlags = BlackPawnFlag | WhitePawnFlag; 22 | const int QueenFlags = BishopFlag | RookFlag; 23 | 24 | const int PieceNone64 = 0; 25 | const int BlackPawn64 = BlackPawnFlag; 26 | const int WhitePawn64 = WhitePawnFlag; 27 | const int Knight64 = KnightFlag; 28 | const int Bishop64 = BishopFlag; 29 | const int Rook64 = RookFlag; 30 | const int Queen64 = QueenFlags; 31 | const int King64 = KingFlag; 32 | 33 | const int PieceNone256 = 0; 34 | const int BlackPawn256 = BlackPawn64 | Black; 35 | const int WhitePawn256 = WhitePawn64 | White; 36 | const int BlackKnight256 = Knight64 | Black; 37 | const int WhiteKnight256 = Knight64 | White; 38 | const int BlackBishop256 = Bishop64 | Black; 39 | const int WhiteBishop256 = Bishop64 | White; 40 | const int BlackRook256 = Rook64 | Black; 41 | const int WhiteRook256 = Rook64 | White; 42 | const int BlackQueen256 = Queen64 | Black; 43 | const int WhiteQueen256 = Queen64 | White; 44 | const int BlackKing256 = King64 | Black; 45 | const int WhiteKing256 = King64 | White; 46 | 47 | const int BlackPawn12 = 0; 48 | const int WhitePawn12 = 1; 49 | const int BlackKnight12 = 2; 50 | const int WhiteKnight12 = 3; 51 | const int BlackBishop12 = 4; 52 | const int WhiteBishop12 = 5; 53 | const int BlackRook12 = 6; 54 | const int WhiteRook12 = 7; 55 | const int BlackQueen12 = 8; 56 | const int WhiteQueen12 = 9; 57 | const int BlackKing12 = 10; 58 | const int WhiteKing12 = 11; 59 | 60 | // functions 61 | 62 | extern void piece_init (); 63 | 64 | extern bool piece_is_ok (int piece); 65 | 66 | extern int piece_make_pawn (int colour); 67 | extern int piece_pawn_opp (int piece); 68 | 69 | extern int piece_colour (int piece); 70 | extern int piece_type (int piece); 71 | 72 | extern bool piece_is_pawn (int piece); 73 | extern bool piece_is_knight (int piece); 74 | extern bool piece_is_bishop (int piece); 75 | extern bool piece_is_rook (int piece); 76 | extern bool piece_is_queen (int piece); 77 | extern bool piece_is_king (int piece); 78 | 79 | extern bool piece_is_slider (int piece); 80 | 81 | extern int piece_to_12 (int piece); 82 | extern int piece_from_12 (int piece); 83 | 84 | extern int piece_to_char (int piece); 85 | extern int piece_from_char (int c); 86 | 87 | extern bool char_is_piece (int c); 88 | 89 | #endif // !defined PIECE_H 90 | 91 | // end of piece.h 92 | 93 | -------------------------------------------------------------------------------- /src/posix.cpp: -------------------------------------------------------------------------------- 1 | 2 | // posix.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include // Mac OS X needs this one first 12 | #include 13 | #include 14 | #include 15 | 16 | #include "posix.h" 17 | #include "util.h" 18 | 19 | // prototypes 20 | 21 | static double duration (const struct timeval *t); 22 | 23 | // functions 24 | 25 | // input_available() 26 | 27 | bool input_available() { 28 | 29 | int val; 30 | fd_set set[1]; 31 | struct timeval time_val[1]; 32 | 33 | FD_ZERO(set); 34 | FD_SET(STDIN_FILENO,set); 35 | 36 | time_val->tv_sec = 0; 37 | time_val->tv_usec = 0; 38 | 39 | val = select(STDIN_FILENO+1,set,NULL,NULL,time_val); 40 | if (val == -1) my_fatal("input_available(): select(): %s\n",strerror(errno)); 41 | 42 | return val != 0; 43 | } 44 | 45 | // now_real() 46 | 47 | double now_real() { 48 | 49 | struct timeval tv[1]; 50 | struct timezone tz[1]; 51 | 52 | tz->tz_minuteswest = 0; 53 | tz->tz_dsttime = 0; // DST_NONE not declared in linux 54 | 55 | if (gettimeofday(tv,tz) == -1) { 56 | my_fatal("now_real(): gettimeofday(): %s\n",strerror(errno)); 57 | } 58 | 59 | return duration(tv); 60 | } 61 | 62 | // now_cpu() 63 | 64 | double now_cpu() { 65 | 66 | struct rusage ru[1]; 67 | 68 | if (getrusage(RUSAGE_SELF,ru) == -1) { 69 | my_fatal("now_cpu(): getrusage(): %s\n",strerror(errno)); 70 | } 71 | 72 | return duration(&ru->ru_utime); 73 | } 74 | 75 | // duration() 76 | 77 | static double duration(const struct timeval *tv) { 78 | 79 | return tv->tv_sec + tv->tv_usec * 1E-6; 80 | } 81 | 82 | // end of posix.cpp 83 | 84 | -------------------------------------------------------------------------------- /src/posix.h: -------------------------------------------------------------------------------- 1 | 2 | // posix.h 3 | 4 | #ifndef POSIX_H 5 | #define POSIX_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // functions 12 | 13 | extern bool input_available (); 14 | 15 | extern double now_real (); 16 | extern double now_cpu (); 17 | 18 | #endif // !defined POSIX_H 19 | 20 | // end of posix.h 21 | 22 | -------------------------------------------------------------------------------- /src/random.h: -------------------------------------------------------------------------------- 1 | 2 | // random.h 3 | 4 | #ifndef RANDOM_H 5 | #define RANDOM_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | const int RandomNb = 781; 14 | 15 | // macros 16 | 17 | #define RANDOM_64(n) (Random64[(n)]) 18 | 19 | // "constants" 20 | 21 | extern const uint64 Random64[RandomNb]; 22 | 23 | // functions 24 | 25 | extern void random_init (); 26 | extern uint64 random_64 (int n); 27 | 28 | #endif // !defined RANDOM_H 29 | 30 | // end of random.h 31 | 32 | -------------------------------------------------------------------------------- /src/san.cpp: -------------------------------------------------------------------------------- 1 | 2 | // san.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "attack.h" 12 | #include "board.h" 13 | #include "list.h" 14 | #include "move.h" 15 | #include "move_gen.h" 16 | #include "move_legal.h" 17 | #include "piece.h" 18 | #include "san.h" 19 | #include "square.h" 20 | #include "util.h" 21 | 22 | // constants 23 | 24 | static const bool UseSlowDebug = false; 25 | 26 | enum ambiguity_t { 27 | AMBIGUITY_NONE, 28 | AMBIGUITY_FILE, 29 | AMBIGUITY_RANK, 30 | AMBIGUITY_SQUARE 31 | }; 32 | 33 | // functions 34 | 35 | static bool san_to_lan (const char san[], const board_t * board, char string[], int size); 36 | static int move_from_lan (const char string[], const board_t * board); 37 | 38 | static int ambiguity (int move, const board_t * board); 39 | 40 | // move_to_san() 41 | 42 | bool move_to_san(int move, const board_t * board, char string[], int size) { 43 | 44 | int from, to, piece; 45 | char tmp_string[256]; 46 | 47 | ASSERT(move_is_ok(move)); 48 | ASSERT(board_is_ok(board)); 49 | ASSERT(string!=NULL); 50 | ASSERT(size>=8); 51 | 52 | ASSERT(move_is_legal(move,board)); 53 | 54 | if (size < 8) return false; 55 | 56 | // init 57 | 58 | from = move_from(move); 59 | to = move_to(move); 60 | 61 | string[0] = '\0'; 62 | 63 | // castle 64 | 65 | if (move_is_castle(move,board)) { 66 | 67 | if (to > from) { 68 | strcat(string,"O-O"); 69 | } else { 70 | strcat(string,"O-O-O"); 71 | } 72 | 73 | goto check; 74 | } 75 | 76 | // from 77 | 78 | piece = board->square[from]; 79 | 80 | if (piece_is_pawn(piece)) { 81 | 82 | // pawn 83 | 84 | if (move_is_capture(move,board)) { 85 | sprintf(tmp_string,"%c",file_to_char(square_file(from))); 86 | strcat(string,tmp_string); 87 | } 88 | 89 | } else { 90 | 91 | // piece 92 | 93 | sprintf(tmp_string,"%c",toupper(piece_to_char(piece))); 94 | strcat(string,tmp_string); 95 | 96 | // ambiguity 97 | 98 | switch (ambiguity(move,board)) { 99 | case AMBIGUITY_NONE: 100 | break; 101 | case AMBIGUITY_FILE: 102 | sprintf(tmp_string,"%c",file_to_char(square_file(from))); 103 | strcat(string,tmp_string); 104 | break; 105 | case AMBIGUITY_RANK: 106 | sprintf(tmp_string,"%c",rank_to_char(square_rank(from))); 107 | strcat(string,tmp_string); 108 | break; 109 | case AMBIGUITY_SQUARE: 110 | if (!square_to_string(from,tmp_string,256)) return false; 111 | strcat(string,tmp_string); 112 | break; 113 | default: 114 | ASSERT(false); 115 | break; 116 | } 117 | } 118 | 119 | // capture 120 | 121 | if (move_is_capture(move,board)) strcat(string,"x"); 122 | 123 | // to 124 | 125 | if (!square_to_string(to,tmp_string,256)) return false; 126 | strcat(string,tmp_string); 127 | 128 | // promote 129 | 130 | if (move_is_promote(move)) { 131 | sprintf(tmp_string,"=%c",toupper(piece_to_char(move_promote(move,board)))); 132 | strcat(string,tmp_string); 133 | } 134 | 135 | // check 136 | 137 | check: 138 | 139 | if (move_is_mate(move,board)) { 140 | strcat(string,"#"); 141 | } else if (move_is_check(move,board)) { 142 | strcat(string,"+"); 143 | } 144 | 145 | return true; 146 | } 147 | 148 | // move_from_san() 149 | 150 | int move_from_san(const char string[], const board_t * board) { 151 | 152 | char s[256]; 153 | int move; 154 | 155 | ASSERT(string!=NULL); 156 | ASSERT(board_is_ok(board)); 157 | 158 | san_to_lan(string,board,s,256); 159 | move = move_from_lan(s,board); 160 | 161 | ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board)); 162 | 163 | return move; 164 | } 165 | 166 | // move_from_san_debug() 167 | 168 | int move_from_san_debug(const char string[], const board_t * board) { 169 | 170 | list_t list[1]; 171 | int i, move; 172 | char move_string[256]; 173 | 174 | ASSERT(string!=NULL); 175 | ASSERT(board_is_ok(board)); 176 | 177 | gen_legal_moves(list,board); 178 | 179 | for (i = 0; i < list_size(list); i++) { 180 | move = list_move(list,i); 181 | if (!move_to_san(move,board,move_string,256)) ASSERT(false); 182 | if (my_string_equal(move_string,string)) return move; 183 | } 184 | 185 | return MoveNone; 186 | } 187 | 188 | // san_to_lan() 189 | 190 | static bool san_to_lan(const char san[], const board_t * board, char string[], int size) { 191 | 192 | int len; 193 | int left, right; 194 | int c; 195 | int king, rook; 196 | char king_string[3], rook_string[3]; 197 | 198 | ASSERT(san!=NULL); 199 | ASSERT(board_is_ok(board)); 200 | ASSERT(string!=NULL); 201 | ASSERT(size>=8); 202 | 203 | // init 204 | 205 | if (size < 8) return false; 206 | strcpy(string,"???????"); 207 | 208 | len = strlen(san); 209 | 210 | left = 0; 211 | right = len; 212 | 213 | // skip trailing '+' or '#' 214 | 215 | if (left < right) { 216 | c = san[right-1]; 217 | if (c == '+' || c == '#') right--; 218 | } 219 | 220 | // castling 221 | 222 | ASSERT(left==0); 223 | 224 | if (false) { 225 | 226 | } else if (right == 3 && strncmp(san,"O-O",3) == 0) { 227 | 228 | if (board->castle[board->turn][SideH] == SquareNone) return false; 229 | 230 | king = king_pos(board,board->turn); 231 | rook = board->castle[board->turn][SideH]; 232 | 233 | square_to_string(king,king_string,3); 234 | square_to_string(rook,rook_string,3); 235 | 236 | sprintf(string,"K%s?%s?",king_string,rook_string); 237 | 238 | } else if (right == 5 && strncmp(san,"O-O-O",5) == 0) { 239 | 240 | if (board->castle[board->turn][SideA] == SquareNone) return false; 241 | 242 | king = king_pos(board,board->turn); 243 | rook = board->castle[board->turn][SideA]; 244 | 245 | square_to_string(king,king_string,3); 246 | square_to_string(rook,rook_string,3); 247 | 248 | sprintf(string,"K%s?%s?",king_string,rook_string); 249 | 250 | } else { 251 | 252 | // moved piece 253 | 254 | if (left < right) { 255 | 256 | c = san[left]; 257 | 258 | if (char_is_piece(c)) { 259 | string[0] = c; 260 | left++; 261 | } 262 | } 263 | 264 | // promotion 265 | 266 | if (left < right) { 267 | 268 | c = toupper(san[right-1]); 269 | 270 | if (char_is_piece(c)) { 271 | 272 | string[6] = c; 273 | right--; 274 | 275 | // skip '=' 276 | 277 | if (left < right && san[right-1] == '=') right--; 278 | } 279 | } 280 | 281 | // to-square rank 282 | 283 | if (left < right) { 284 | 285 | c = san[right-1]; 286 | 287 | if (char_is_rank(c)) { 288 | string[5] = c; 289 | right--; 290 | } 291 | } 292 | 293 | // to-square file 294 | 295 | if (left < right) { 296 | 297 | c = san[right-1]; 298 | 299 | if (char_is_file(c)) { 300 | string[4] = c; 301 | right--; 302 | } 303 | } 304 | 305 | // captured piece 306 | 307 | if (left < right) { 308 | 309 | c = san[right-1]; 310 | 311 | if (char_is_piece(c)) { 312 | string[3] = c; 313 | right--; 314 | } 315 | } 316 | 317 | // skip middle '-' or 'x' 318 | 319 | if (left < right) { 320 | c = san[right-1]; 321 | if (c == '-' || c == 'x') right--; 322 | } 323 | 324 | // from-square file 325 | 326 | if (left < right) { 327 | 328 | c = san[left]; 329 | 330 | if (char_is_file(c)) { 331 | string[1] = c; 332 | left++; 333 | } 334 | } 335 | 336 | // from-square rank 337 | 338 | if (left < right) { 339 | 340 | c = san[left]; 341 | 342 | if (char_is_rank(c)) { 343 | string[2] = c; 344 | left++; 345 | } 346 | } 347 | 348 | if (left != right) return false; 349 | } 350 | 351 | // end 352 | 353 | return true; 354 | } 355 | 356 | // move_from_lan() 357 | 358 | static int move_from_lan(const char string[], const board_t * board) { 359 | 360 | int len; 361 | int move; 362 | int promote; 363 | char s[256]; 364 | int from, to; 365 | int colour; 366 | int inc; 367 | int piece_char; 368 | int n; 369 | const uint8 * ptr; 370 | int piece; 371 | int side; 372 | 373 | ASSERT(string!=NULL); 374 | ASSERT(board_is_ok(board)); 375 | 376 | // init 377 | 378 | len = strlen(string); 379 | if (len != 7) return MoveNone; 380 | 381 | move = MoveNone; 382 | colour = board->turn; 383 | 384 | // promote 385 | 386 | promote = 0; 387 | 388 | switch (string[6]) { 389 | case '?': // not a promotion 390 | break; 391 | case 'N': 392 | promote = MovePromoteKnight; 393 | break; 394 | case 'B': 395 | promote = MovePromoteBishop; 396 | break; 397 | case 'R': 398 | promote = MovePromoteRook; 399 | break; 400 | case 'Q': 401 | promote = MovePromoteQueen; 402 | break; 403 | default: 404 | return MoveNone; 405 | break; 406 | } 407 | 408 | // to square 409 | 410 | s[0] = string[4]; 411 | s[1] = string[5]; 412 | s[2] = '\0'; 413 | 414 | to = square_from_string(s); 415 | if (to == SquareNone) return MoveNone; 416 | 417 | // known from square? 418 | 419 | if (string[1] != '?' && string[2] != '?') { 420 | 421 | // from square 422 | 423 | s[0] = string[1]; 424 | s[1] = string[2]; 425 | s[2] = '\0'; 426 | 427 | from = square_from_string(s); 428 | if (from == SquareNone) return MoveNone; 429 | 430 | // convert "king slide" castling to KxR 431 | 432 | if (piece_is_king(board->square[from]) 433 | && square_rank(to) == square_rank(from) 434 | && abs(to-from) > 1) { 435 | side = (to > from) ? SideH : SideA; 436 | to = board->castle[colour][side]; 437 | if (to == SquareNone) return MoveNone; 438 | } 439 | 440 | // move 441 | 442 | move = move_make(from,to) | promote; 443 | 444 | return move; 445 | } 446 | 447 | // pawn non-capture? 448 | 449 | if (string[0] == '?' && string[1] == '?') { 450 | 451 | if (board->square[to] != Empty) return MoveNone; // useful? 452 | 453 | inc = (colour_is_white(colour)) ? +16 : -16; 454 | 455 | from = to - inc; 456 | if (board->square[from] == Empty && square_side_rank(to,colour) == Rank4) { 457 | from -= inc; 458 | } 459 | 460 | if (board->square[from] != piece_make_pawn(colour)) { // useful? 461 | return MoveNone; 462 | } 463 | 464 | // move 465 | 466 | move = move_make(from,to) | promote; 467 | 468 | return move; 469 | } 470 | 471 | // pawn capture? 472 | 473 | piece_char = string[0]; 474 | 475 | if (piece_char == '?' && string[1] != '?') { 476 | piece_char = 'P'; 477 | } 478 | 479 | // attack loop 480 | 481 | n = 0; 482 | 483 | for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) { 484 | 485 | piece = board->square[from]; 486 | 487 | if (toupper(piece_to_char(piece)) == piece_char) { 488 | if (piece_attack(board,piece,from,to)) { 489 | if (true 490 | && (string[1] == '?' || file_to_char(square_file(from)) == string[1]) 491 | && (string[2] == '?' || rank_to_char(square_rank(from)) == string[2])) { 492 | if (!is_pinned(board,from,to,colour)) { 493 | move = move_make(from,to) | promote; 494 | n++; 495 | } 496 | } 497 | } 498 | } 499 | } 500 | 501 | if (n != 1) move = MoveNone; 502 | 503 | return move; 504 | } 505 | 506 | // ambiguity() 507 | 508 | static int ambiguity(int move, const board_t * board) { 509 | 510 | int from, to, piece; 511 | list_t list[1]; 512 | int i, n, m; 513 | 514 | // init 515 | 516 | from = move_from(move); 517 | to = move_to(move); 518 | piece = move_piece(move,board); 519 | 520 | gen_legal_moves(list,board); 521 | 522 | // no ambiguity? 523 | 524 | n = 0; 525 | 526 | for (i = 0; i < list_size(list); i++) { 527 | m = list_move(list,i); 528 | if (move_piece(m,board) == piece && move_to(m) == to) { 529 | n++; 530 | } 531 | } 532 | 533 | if (n == 1) return AMBIGUITY_NONE; 534 | 535 | // file ambiguity? 536 | 537 | n = 0; 538 | 539 | for (i = 0; i < list_size(list); i++) { 540 | m = list_move(list,i); 541 | if (move_piece(m,board) == piece && move_to(m) == to) { 542 | if (square_file(move_from(m)) == square_file(from)) n++; 543 | } 544 | } 545 | 546 | if (n == 1) return AMBIGUITY_FILE; 547 | 548 | // rank ambiguity? 549 | 550 | n = 0; 551 | 552 | for (i = 0; i < list_size(list); i++) { 553 | m = list_move(list,i); 554 | if (move_piece(m,board) == piece && move_to(m) == to) { 555 | if (square_rank(move_from(m)) == square_rank(from)) n++; 556 | } 557 | } 558 | 559 | if (n == 1) return AMBIGUITY_RANK; 560 | 561 | // square ambiguity 562 | 563 | return AMBIGUITY_SQUARE; 564 | } 565 | 566 | // end of san.cpp 567 | 568 | -------------------------------------------------------------------------------- /src/san.h: -------------------------------------------------------------------------------- 1 | 2 | // san.h 3 | 4 | #ifndef SAN_H 5 | #define SAN_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // functions 13 | 14 | extern bool move_to_san (int move, const board_t * board, char string[], int size); 15 | extern int move_from_san (const char string[], const board_t * board); 16 | 17 | extern int move_from_san_debug (const char string[], const board_t * board); 18 | 19 | #endif // !defined SAN_H 20 | 21 | // end of san.h 22 | 23 | -------------------------------------------------------------------------------- /src/search.cpp: -------------------------------------------------------------------------------- 1 | 2 | // search.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "attack.h" 11 | #include "board.h" 12 | #include "colour.h" 13 | #include "engine.h" 14 | #include "fen.h" 15 | #include "line.h" 16 | #include "list.h" 17 | #include "move.h" 18 | #include "move_do.h" 19 | #include "move_gen.h" 20 | #include "move_legal.h" 21 | #include "option.h" 22 | #include "parse.h" 23 | #include "san.h" 24 | #include "search.h" 25 | #include "uci.h" 26 | #include "util.h" 27 | 28 | // variables 29 | 30 | static int Depth; 31 | 32 | static int BestMove; 33 | static int BestValue; 34 | static move_t BestPV[LineSize]; 35 | 36 | static sint64 NodeNb; 37 | static sint64 LeafNb; 38 | static double Time; 39 | 40 | static int Move; 41 | static int MovePos; 42 | static int MoveNb; 43 | 44 | // prototypes 45 | 46 | static bool depth_is_ok (int depth); 47 | 48 | static void perft (const board_t * board, int depth); 49 | 50 | // functions 51 | 52 | // depth_is_ok() 53 | 54 | static bool depth_is_ok(int depth) { 55 | 56 | return depth >= 0 && depth < DepthMax; 57 | } 58 | 59 | // search() 60 | 61 | void search(const board_t * board, int depth_max, double time_max) { 62 | 63 | char string[256]; 64 | 65 | ASSERT(board_is_ok(board)); 66 | ASSERT(depth_max>=1&&depth_max=0.0); 68 | 69 | // engine 70 | 71 | Depth = 0; 72 | 73 | BestMove = MoveNone; 74 | BestValue = 0; 75 | line_clear(BestPV); 76 | 77 | NodeNb = 0; 78 | LeafNb = 0; 79 | Time = 0.0; 80 | 81 | Move = MoveNone; 82 | MovePos = 0; 83 | MoveNb = 0; 84 | 85 | // init 86 | 87 | uci_send_ucinewgame(Uci); 88 | uci_send_isready_sync(Uci); 89 | 90 | // position 91 | 92 | if (!board_to_fen(board,string,256)) ASSERT(false); 93 | engine_send(Engine,"position fen %s",string); 94 | 95 | // search 96 | 97 | engine_send_queue(Engine,"go"); 98 | 99 | engine_send_queue(Engine," movetime %.0f",time_max*1000.0); 100 | engine_send_queue(Engine," depth %d",depth_max); 101 | 102 | engine_send(Engine,""); // newline 103 | 104 | // wait for feed-back 105 | 106 | while (true) { 107 | 108 | engine_get(Engine,string,256); 109 | 110 | if (false) { 111 | 112 | } else if (match(string,"bestmove * ponder *")) { 113 | 114 | BestMove = move_from_can(Star[0],board); 115 | ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); 116 | 117 | break; 118 | 119 | } else if (match(string,"bestmove *")) { 120 | 121 | BestMove = move_from_can(Star[0],board); 122 | ASSERT(BestMove!=MoveNone&&move_is_legal(BestMove,board)); 123 | 124 | break; 125 | } 126 | } 127 | 128 | printf("\n"); 129 | } 130 | 131 | // search_perft() 132 | 133 | void search_perft(const board_t * board, int depth_max) { 134 | 135 | int depth; 136 | my_timer_t timer[1]; 137 | double time, speed; 138 | 139 | ASSERT(board_is_ok(board)); 140 | ASSERT(depth_max>=1&&depth_maxturn))); 183 | 184 | // init 185 | 186 | NodeNb++; 187 | 188 | // leaf 189 | 190 | if (depth == 0) { 191 | LeafNb++; 192 | return; 193 | } 194 | 195 | // more init 196 | 197 | me = board->turn; 198 | 199 | // move loop 200 | 201 | gen_moves(list,board); 202 | 203 | for (i = 0; i < list_size(list); i++) { 204 | 205 | move = list_move(list,i); 206 | 207 | board_copy(new_board,board); 208 | move_do(new_board,move); 209 | 210 | if (!is_in_check(new_board,me)) perft(new_board,depth-1); 211 | } 212 | } 213 | 214 | // end of search.cpp 215 | 216 | -------------------------------------------------------------------------------- /src/search.h: -------------------------------------------------------------------------------- 1 | 2 | // search.h 3 | 4 | #ifndef SEARCH_H 5 | #define SEARCH_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "util.h" 11 | 12 | // constants 13 | 14 | const int DepthMax = 63; 15 | 16 | // functions 17 | 18 | extern void search (const board_t * board, int depth_max, double time_max); 19 | extern void search_perft (const board_t * board, int depth_max); 20 | 21 | #endif // !defined SEARCH_H 22 | 23 | // end of search.h 24 | 25 | -------------------------------------------------------------------------------- /src/square.cpp: -------------------------------------------------------------------------------- 1 | 2 | // square.cpp 3 | 4 | // includes 5 | 6 | #include "colour.h" 7 | #include "square.h" 8 | #include "util.h" 9 | 10 | // "constants" 11 | 12 | static const uint8 SquareFrom64[64] = { 13 | A1, B1, C1, D1, E1, F1, G1, H1, 14 | A2, B2, C2, D2, E2, F2, G2, H2, 15 | A3, B3, C3, D3, E3, F3, G3, H3, 16 | A4, B4, C4, D4, E4, F4, G4, H4, 17 | A5, B5, C5, D5, E5, F5, G5, H5, 18 | A6, B6, C6, D6, E6, F6, G6, H6, 19 | A7, B7, C7, D7, E7, F7, G7, H7, 20 | A8, B8, C8, D8, E8, F8, G8, H8, 21 | }; 22 | 23 | // variables 24 | 25 | static sint8 SquareTo64[SquareNb]; 26 | 27 | // functions 28 | 29 | // square_init() 30 | 31 | void square_init() { 32 | 33 | int sq; 34 | 35 | for (sq = 0; sq < SquareNb; sq++) SquareTo64[sq] = -1; 36 | 37 | for (sq = 0; sq < 64; sq++) { 38 | SquareTo64[SquareFrom64[sq]] = sq; 39 | } 40 | } 41 | 42 | // square_is_ok() 43 | 44 | bool square_is_ok(int square) { 45 | 46 | if (square < 0 || square >= SquareNb) return false; 47 | 48 | if (SquareTo64[square] < 0) return false; 49 | 50 | return true; 51 | } 52 | 53 | // square_make() 54 | 55 | int square_make(int file, int rank) { 56 | 57 | int sq_64; 58 | 59 | ASSERT(file>=0&&file<8); 60 | ASSERT(rank>=0&&rank<8); 61 | 62 | sq_64 = (rank << 3) | file; 63 | 64 | return square_from_64(sq_64); 65 | } 66 | 67 | // square_file() 68 | 69 | int square_file(int square) { 70 | 71 | int file; 72 | 73 | ASSERT(square_is_ok(square)); 74 | 75 | file = (square - 4) & 7; 76 | ASSERT(file==(square_to_64(square)&7)); 77 | 78 | return file; 79 | } 80 | 81 | // square_rank() 82 | 83 | int square_rank(int square) { 84 | 85 | int rank; 86 | 87 | ASSERT(square_is_ok(square)); 88 | 89 | rank = (square >> 4) - 2; 90 | ASSERT(rank==square_to_64(square)>>3); 91 | 92 | return rank; 93 | } 94 | 95 | // square_side_rank() 96 | 97 | int square_side_rank(int square, int colour) { 98 | 99 | int rank; 100 | 101 | ASSERT(square_is_ok(square)); 102 | ASSERT(colour_is_ok(colour)); 103 | 104 | rank = square_rank(square); 105 | if (colour_is_black(colour)) rank = 7-rank; 106 | 107 | return rank; 108 | } 109 | 110 | // square_from_64() 111 | 112 | int square_from_64(int square) { 113 | 114 | ASSERT(square>=0&&square<64); 115 | 116 | return SquareFrom64[square]; 117 | } 118 | 119 | // square_to_64() 120 | 121 | int square_to_64(int square) { 122 | 123 | ASSERT(square_is_ok(square)); 124 | 125 | return SquareTo64[square]; 126 | } 127 | 128 | // square_is_promote() 129 | 130 | bool square_is_promote(int square) { 131 | 132 | int rank; 133 | 134 | ASSERT(square_is_ok(square)); 135 | 136 | rank = square_rank(square); 137 | 138 | return rank == Rank1 || rank == Rank8; 139 | } 140 | 141 | // square_ep_dual() 142 | 143 | int square_ep_dual(int square) { 144 | 145 | ASSERT(square_is_ok(square)); 146 | ASSERT(square_rank(square)>=2&&square_rank(square)<=5); 147 | 148 | return square ^ 16; 149 | } 150 | 151 | // square_colour() 152 | 153 | int square_colour(int square) { 154 | 155 | ASSERT(square_is_ok(square)); 156 | 157 | return (square ^ (square >> 4)) & 1; 158 | } 159 | 160 | // file_from_char() 161 | 162 | int file_from_char(int c) { 163 | 164 | ASSERT(c>='a'&&c<='h'); 165 | 166 | return c - 'a'; 167 | } 168 | 169 | // rank_from_char() 170 | 171 | int rank_from_char(int c) { 172 | 173 | ASSERT(c>='1'&&c<='8'); 174 | 175 | return c - '1'; 176 | } 177 | 178 | // file_to_char() 179 | 180 | int file_to_char(int file) { 181 | 182 | ASSERT(file>=0&&file<8); 183 | 184 | return 'a' + file; 185 | } 186 | 187 | // rank_to_char() 188 | 189 | int rank_to_char(int rank) { 190 | 191 | ASSERT(rank>=0&&rank<8); 192 | 193 | return '1' + rank; 194 | } 195 | 196 | // char_is_file() 197 | 198 | bool char_is_file(int c) { 199 | 200 | return c >= 'a' && c <= 'h'; 201 | } 202 | 203 | // char_is_rank() 204 | 205 | bool char_is_rank(int c) { 206 | 207 | return c >= '1' && c <= '8'; 208 | } 209 | 210 | // square_to_string() 211 | 212 | bool square_to_string(int square, char string[], int size) { 213 | 214 | ASSERT(square_is_ok(square)); 215 | ASSERT(string!=NULL); 216 | ASSERT(size>=3); 217 | 218 | if (size < 3) return false; 219 | 220 | string[0] = 'a' + square_file(square); 221 | string[1] = '1' + square_rank(square); 222 | string[2] = '\0'; 223 | 224 | return true; 225 | } 226 | 227 | // square_from_string() 228 | 229 | int square_from_string(const char string[]) { 230 | 231 | int file, rank; 232 | 233 | ASSERT(string!=NULL); 234 | 235 | if (string[0] < 'a' || string[0] > 'h') return SquareNone; 236 | if (string[1] < '1' || string[1] > '8') return SquareNone; 237 | if (string[2] != '\0') return SquareNone; 238 | 239 | file = file_from_char(string[0]); 240 | rank = rank_from_char(string[1]); 241 | 242 | return square_make(file,rank); 243 | } 244 | 245 | // end of square.cpp 246 | 247 | -------------------------------------------------------------------------------- /src/square.h: -------------------------------------------------------------------------------- 1 | 2 | // square.h 3 | 4 | #ifndef SQUARE_H 5 | #define SQUARE_H 6 | 7 | // includes 8 | 9 | #include "util.h" 10 | 11 | // constants 12 | 13 | const int SquareNb = 16 * 12; 14 | 15 | const int FileA = 0; 16 | const int FileB = 1; 17 | const int FileC = 2; 18 | const int FileD = 3; 19 | const int FileE = 4; 20 | const int FileF = 5; 21 | const int FileG = 6; 22 | const int FileH = 7; 23 | 24 | const int Rank1 = 0; 25 | const int Rank2 = 1; 26 | const int Rank3 = 2; 27 | const int Rank4 = 3; 28 | const int Rank5 = 4; 29 | const int Rank6 = 5; 30 | const int Rank7 = 6; 31 | const int Rank8 = 7; 32 | 33 | const int SquareNone = 0; 34 | 35 | const int A1=0x24, B1=0x25, C1=0x26, D1=0x27, E1=0x28, F1=0x29, G1=0x2A, H1=0x2B; 36 | const int A2=0x34, B2=0x35, C2=0x36, D2=0x37, E2=0x38, F2=0x39, G2=0x3A, H2=0x3B; 37 | const int A3=0x44, B3=0x45, C3=0x46, D3=0x47, E3=0x48, F3=0x49, G3=0x4A, H3=0x4B; 38 | const int A4=0x54, B4=0x55, C4=0x56, D4=0x57, E4=0x58, F4=0x59, G4=0x5A, H4=0x5B; 39 | const int A5=0x64, B5=0x65, C5=0x66, D5=0x67, E5=0x68, F5=0x69, G5=0x6A, H5=0x6B; 40 | const int A6=0x74, B6=0x75, C6=0x76, D6=0x77, E6=0x78, F6=0x79, G6=0x7A, H6=0x7B; 41 | const int A7=0x84, B7=0x85, C7=0x86, D7=0x87, E7=0x88, F7=0x89, G7=0x8A, H7=0x8B; 42 | const int A8=0x94, B8=0x95, C8=0x96, D8=0x97, E8=0x98, F8=0x99, G8=0x9A, H8=0x9B; 43 | 44 | const int Dark = 0; 45 | const int Light = 1; 46 | 47 | // functions 48 | 49 | extern void square_init (); 50 | 51 | extern bool square_is_ok (int square); 52 | 53 | extern int square_make (int file, int rank); 54 | 55 | extern int square_file (int square); 56 | extern int square_rank (int square); 57 | extern int square_side_rank (int square, int colour); 58 | 59 | extern int square_from_64 (int square); 60 | extern int square_to_64 (int square); 61 | 62 | extern bool square_is_promote (int square); 63 | extern int square_ep_dual (int square); 64 | 65 | extern int square_colour (int square); 66 | 67 | extern bool char_is_file (int c); 68 | extern bool char_is_rank (int c); 69 | 70 | extern int file_from_char (int c); 71 | extern int rank_from_char (int c); 72 | 73 | extern int file_to_char (int file); 74 | extern int rank_to_char (int rank); 75 | 76 | extern bool square_to_string (int square, char string[], int size); 77 | extern int square_from_string (const char string[]); 78 | 79 | #endif // !defined SQUARE_H 80 | 81 | // end of square.h 82 | 83 | -------------------------------------------------------------------------------- /src/uci.h: -------------------------------------------------------------------------------- 1 | 2 | // uci.h 3 | 4 | #ifndef UCI_H 5 | #define UCI_H 6 | 7 | // includes 8 | 9 | #include "board.h" 10 | #include "engine.h" 11 | #include "line.h" 12 | #include "move.h" 13 | #include "util.h" 14 | 15 | // constants 16 | 17 | const int OptionNb = 256; 18 | 19 | // types 20 | 21 | struct option_t { 22 | const char * name; 23 | const char * value; 24 | }; 25 | 26 | struct uci_t { 27 | 28 | engine_t * engine; 29 | 30 | const char * name; 31 | const char * author; 32 | 33 | int option_nb; 34 | option_t option[OptionNb]; 35 | 36 | bool ready; 37 | int ready_nb; 38 | 39 | bool searching; 40 | int pending_nb; 41 | 42 | board_t board[1]; 43 | 44 | int best_move; 45 | int ponder_move; 46 | 47 | int score; 48 | int depth; 49 | int sel_depth; 50 | move_t pv[LineSize]; 51 | 52 | int best_score; 53 | int best_depth; 54 | int best_sel_depth; 55 | move_t best_pv[LineSize]; 56 | 57 | sint64 node_nb; 58 | double time; 59 | double speed; 60 | double cpu; 61 | double hash; 62 | move_t current_line[LineSize]; 63 | 64 | int root_move; 65 | int root_move_pos; 66 | int root_move_nb; 67 | }; 68 | 69 | enum dummy_event_t { 70 | EVENT_NONE = 0, 71 | EVENT_UCI = 1 << 0, 72 | EVENT_READY = 1 << 1, 73 | EVENT_STOP = 1 << 2, 74 | EVENT_MOVE = 1 << 3, 75 | EVENT_PV = 1 << 4, 76 | EVENT_DEPTH = 1 << 5 77 | }; 78 | 79 | // variables 80 | 81 | extern uci_t Uci[1]; 82 | 83 | // functions 84 | 85 | extern void uci_open (uci_t * uci, engine_t * engine); 86 | extern void uci_close (uci_t * uci); 87 | 88 | extern void uci_clear (uci_t * uci); 89 | 90 | extern void uci_send_isready (uci_t * uci); 91 | extern void uci_send_isready_sync (uci_t * uci); 92 | extern void uci_send_stop (uci_t * uci); 93 | extern void uci_send_stop_sync (uci_t * uci); 94 | extern void uci_send_ucinewgame (uci_t * uci); 95 | 96 | extern bool uci_option_exist (uci_t * uci, const char option[]); 97 | extern void uci_send_option (uci_t * uci, const char option[], const char format[], ...); 98 | 99 | extern int uci_parse (uci_t * uci, const char string[]); 100 | 101 | #endif // !defined UCI_H 102 | 103 | // end of uci.h 104 | 105 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | 2 | // util.cpp 3 | 4 | // includes 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "main.h" 16 | #include "posix.h" 17 | #include "util.h" 18 | 19 | // variables 20 | 21 | static bool Error; 22 | 23 | static FILE * LogFile; 24 | 25 | // functions 26 | 27 | // util_init() 28 | 29 | void util_init() { 30 | 31 | Error = false; 32 | 33 | // init log file 34 | 35 | LogFile = NULL; 36 | 37 | // switch file buffering off 38 | 39 | setbuf(stdin,NULL); 40 | setbuf(stdout,NULL); 41 | } 42 | 43 | // my_random_init() 44 | 45 | void my_random_init() { 46 | 47 | srand(time(NULL)); 48 | } 49 | 50 | // my_random_int() 51 | 52 | int my_random_int(int n) { 53 | 54 | int r; 55 | 56 | ASSERT(n>0); 57 | 58 | r = int(floor(my_random_double()*double(n))); 59 | ASSERT(r>=0&&r=0.0&&r<1.0); 72 | 73 | return r; 74 | } 75 | 76 | // my_atoll() 77 | 78 | sint64 my_atoll(const char string[]) { 79 | 80 | sint64 n; 81 | 82 | sscanf(string,S64_FORMAT,&n); 83 | 84 | return n; 85 | } 86 | 87 | // my_round() 88 | 89 | int my_round(double x) { 90 | 91 | return int(floor(x+0.5)); 92 | } 93 | 94 | // my_malloc() 95 | 96 | void * my_malloc(int size) { 97 | 98 | void * address; 99 | 100 | ASSERT(size>0); 101 | 102 | address = malloc(size); 103 | if (address == NULL) my_fatal("my_malloc(): malloc(): %s\n",strerror(errno)); 104 | 105 | return address; 106 | } 107 | 108 | // my_realloc() 109 | 110 | void * my_realloc(void * address, int size) { 111 | 112 | ASSERT(address!=NULL); 113 | ASSERT(size>0); 114 | 115 | address = realloc(address,size); 116 | if (address == NULL) my_fatal("my_realloc(): realloc(): %s\n",strerror(errno)); 117 | 118 | return address; 119 | } 120 | 121 | // my_free() 122 | 123 | void my_free(void * address) { 124 | 125 | ASSERT(address!=NULL); 126 | 127 | free(address); 128 | } 129 | 130 | // my_log_open() 131 | 132 | void my_log_open(const char file_name[]) { 133 | 134 | ASSERT(file_name!=NULL); 135 | 136 | LogFile = fopen(file_name,"a"); 137 | 138 | if (LogFile != NULL) setvbuf(LogFile,NULL,_IOLBF,0); // line buffering 139 | } 140 | 141 | // my_log_close() 142 | 143 | void my_log_close() { 144 | 145 | if (LogFile != NULL) fclose(LogFile); 146 | } 147 | 148 | // my_log() 149 | 150 | void my_log(const char format[], ...) { 151 | 152 | va_list ap; 153 | 154 | ASSERT(format!=NULL); 155 | 156 | if (LogFile != NULL) { 157 | va_start(ap,format); 158 | vfprintf(LogFile,format,ap); 159 | va_end(ap); 160 | } 161 | } 162 | 163 | // my_fatal() 164 | 165 | void my_fatal(const char format[], ...) { 166 | 167 | va_list ap; 168 | 169 | ASSERT(format!=NULL); 170 | 171 | va_start(ap,format); 172 | 173 | vfprintf(stderr,format,ap); 174 | if (LogFile != NULL) vfprintf(LogFile,format,ap); 175 | 176 | va_end(ap); 177 | 178 | if (Error) { // recursive error 179 | my_log("POLYGLOT *** RECURSIVE ERROR ***\n"); 180 | exit(EXIT_FAILURE); 181 | // abort(); 182 | } else { 183 | Error = true; 184 | quit(); 185 | } 186 | } 187 | 188 | // my_file_read_line() 189 | 190 | bool my_file_read_line(FILE * file, char string[], int size) { 191 | 192 | int src, dst; 193 | int c; 194 | 195 | ASSERT(file!=NULL); 196 | ASSERT(string!=NULL); 197 | ASSERT(size>0); 198 | 199 | if (fgets(string,size,file) == NULL) { 200 | if (feof(file)) { 201 | return false; 202 | } else { // error 203 | my_fatal("my_file_read_line(): fgets(): %s\n",strerror(errno)); 204 | } 205 | } 206 | 207 | // remove CRs and LFs 208 | 209 | src = 0; 210 | dst = 0; 211 | 212 | while ((c=string[src++]) != '\0') { 213 | if (c != '\r' && c != '\n') string[dst++] = c; 214 | } 215 | 216 | string[dst] = '\0'; 217 | 218 | return true; 219 | } 220 | 221 | // my_string_empty() 222 | 223 | bool my_string_empty(const char string[]) { 224 | 225 | return string == NULL || string[0] == '\0'; 226 | } 227 | 228 | // my_string_equal() 229 | 230 | bool my_string_equal(const char string_1[], const char string_2[]) { 231 | 232 | ASSERT(string_1!=NULL); 233 | ASSERT(string_2!=NULL); 234 | 235 | return strcmp(string_1,string_2) == 0; 236 | } 237 | 238 | // my_string_case_equal() 239 | 240 | bool my_string_case_equal(const char string_1[], const char string_2[]) { 241 | 242 | int c1, c2; 243 | 244 | ASSERT(string_1!=NULL); 245 | ASSERT(string_2!=NULL); 246 | 247 | while (true) { 248 | 249 | c1 = *string_1++; 250 | c2 = *string_2++; 251 | 252 | if (tolower(c1) != tolower(c2)) return false; 253 | if (c1 == '\0') return true; 254 | } 255 | 256 | return false; 257 | } 258 | 259 | // my_strdup() 260 | 261 | char * my_strdup(const char string[]) { 262 | 263 | char * address; 264 | 265 | ASSERT(string!=NULL); 266 | 267 | // strdup() is not ANSI C 268 | 269 | address = (char *) my_malloc(strlen(string)+1); 270 | strcpy(address,string); 271 | 272 | return address; 273 | } 274 | 275 | // my_string_clear() 276 | 277 | void my_string_clear(const char * * variable) { 278 | 279 | ASSERT(variable!=NULL); 280 | 281 | if (*variable != NULL) { 282 | my_free((void*)(*variable)); 283 | *variable = NULL; 284 | } 285 | } 286 | 287 | // my_string_set() 288 | 289 | void my_string_set(const char * * variable, const char string[]) { 290 | 291 | ASSERT(variable!=NULL); 292 | ASSERT(string!=NULL); 293 | 294 | if (*variable != NULL) my_free((void*)(*variable)); 295 | *variable = my_strdup(string); 296 | } 297 | 298 | // my_timer_reset() 299 | 300 | void my_timer_reset(my_timer_t * timer) { 301 | 302 | ASSERT(timer!=NULL); 303 | 304 | timer->start_real = 0.0; 305 | timer->start_cpu = 0.0; 306 | timer->elapsed_real = 0.0; 307 | timer->elapsed_cpu = 0.0; 308 | timer->running = false; 309 | } 310 | 311 | // my_timer_start() 312 | 313 | void my_timer_start(my_timer_t * timer) { 314 | 315 | ASSERT(timer!=NULL); 316 | 317 | ASSERT(timer->start_real==0.0); 318 | ASSERT(timer->start_cpu==0.0); 319 | ASSERT(!timer->running); 320 | 321 | timer->running = true; 322 | timer->start_real = now_real(); 323 | timer->start_cpu = now_cpu(); 324 | } 325 | 326 | // my_timer_stop() 327 | 328 | void my_timer_stop(my_timer_t * timer) { 329 | 330 | ASSERT(timer!=NULL); 331 | 332 | ASSERT(timer->running); 333 | 334 | timer->elapsed_real += now_real() - timer->start_real; 335 | timer->elapsed_cpu += now_cpu() - timer->start_cpu; 336 | timer->start_real = 0.0; 337 | timer->start_cpu = 0.0; 338 | timer->running = false; 339 | } 340 | 341 | // my_timer_elapsed_real() 342 | 343 | double my_timer_elapsed_real(const my_timer_t * timer) { 344 | 345 | double elapsed; 346 | 347 | ASSERT(timer!=NULL); 348 | 349 | elapsed = timer->elapsed_real; 350 | if (timer->running) elapsed += now_real() - timer->start_real; 351 | 352 | if (elapsed < 0.0) elapsed = 0.0; 353 | 354 | return elapsed; 355 | } 356 | 357 | // my_timer_elapsed_cpu() 358 | 359 | double my_timer_elapsed_cpu(const my_timer_t * timer) { 360 | 361 | double elapsed; 362 | 363 | ASSERT(timer!=NULL); 364 | 365 | elapsed = timer->elapsed_cpu; 366 | if (timer->running) elapsed += now_cpu() - timer->start_cpu; 367 | 368 | if (elapsed < 0.0) elapsed = 0.0; 369 | 370 | return elapsed; 371 | } 372 | 373 | // my_timer_cpu_usage() 374 | 375 | double my_timer_cpu_usage(const my_timer_t * timer) { 376 | 377 | double real, cpu; 378 | double usage; 379 | 380 | ASSERT(timer!=NULL); 381 | 382 | real = my_timer_elapsed_real(timer); 383 | cpu = my_timer_elapsed_cpu(timer); 384 | 385 | if (real <= 0.0 || cpu <= 0.0) return 0.0; 386 | 387 | usage = cpu / real; 388 | if (usage >= 1.0) usage = 1.0; 389 | 390 | return usage; 391 | } 392 | 393 | // end of util.cpp 394 | 395 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | 2 | // util.h 3 | 4 | #ifndef UTIL_H 5 | #define UTIL_H 6 | 7 | // includes 8 | 9 | #include 10 | 11 | // constants 12 | 13 | #undef FALSE 14 | #define FALSE 0 15 | 16 | #undef TRUE 17 | #define TRUE 1 18 | 19 | #ifdef DEBUG 20 | # undef DEBUG 21 | # define DEBUG TRUE 22 | #else 23 | # define DEBUG FALSE 24 | #endif 25 | 26 | #ifdef _MSC_VER 27 | # define S64_FORMAT "%I64d" 28 | # define U64_FORMAT "%016I64X" 29 | #else 30 | # define S64_FORMAT "%lld" 31 | # define U64_FORMAT "%016llX" 32 | #endif 33 | 34 | // macros 35 | 36 | #ifdef _MSC_VER 37 | # define S64(u) (u##i64) 38 | # define U64(u) (u##ui64) 39 | #else 40 | # define S64(u) (u##LL) 41 | # define U64(u) (u##ULL) 42 | #endif 43 | 44 | #undef ASSERT 45 | #if DEBUG 46 | # define ASSERT(a) { if (!(a)) my_fatal("file \"%s\", line %d, assertion \"" #a "\" failed\n",__FILE__,__LINE__); } 47 | #else 48 | # define ASSERT(a) 49 | #endif 50 | 51 | // types 52 | 53 | typedef signed char sint8; 54 | typedef unsigned char uint8; 55 | 56 | typedef signed short sint16; 57 | typedef unsigned short uint16; 58 | 59 | typedef signed int sint32; 60 | typedef unsigned int uint32; 61 | 62 | #ifdef _MSC_VER 63 | typedef signed __int64 sint64; 64 | typedef unsigned __int64 uint64; 65 | #else 66 | typedef signed long long int sint64; 67 | typedef unsigned long long int uint64; 68 | #endif 69 | 70 | struct my_timer_t { 71 | double start_real; 72 | double start_cpu; 73 | double elapsed_real; 74 | double elapsed_cpu; 75 | bool running; 76 | }; 77 | 78 | // functions 79 | 80 | extern void util_init (); 81 | 82 | extern void my_random_init (); 83 | extern int my_random_int (int n); 84 | extern double my_random_double (); 85 | 86 | extern sint64 my_atoll (const char string[]); 87 | 88 | extern int my_round (double x); 89 | 90 | extern void * my_malloc (int size); 91 | extern void * my_realloc (void * address, int size); 92 | extern void my_free (void * address); 93 | 94 | extern void my_log_open (const char file_name[]); 95 | extern void my_log_close (); 96 | 97 | extern void my_log (const char format[], ...); 98 | extern void my_fatal (const char format[], ...); 99 | 100 | extern bool my_file_read_line (FILE * file, char string[], int size); 101 | 102 | extern bool my_string_empty (const char string[]); 103 | extern bool my_string_equal (const char string_1[], const char string_2[]); 104 | extern bool my_string_case_equal (const char string_1[], const char string_2[]); 105 | extern char * my_strdup (const char string[]); 106 | 107 | extern void my_string_clear (const char * * variable); 108 | extern void my_string_set (const char * * variable, const char string[]); 109 | 110 | extern void my_timer_reset (my_timer_t * timer); 111 | extern void my_timer_start (my_timer_t * timer); 112 | extern void my_timer_stop (my_timer_t * timer); 113 | 114 | extern double my_timer_elapsed_real (const my_timer_t * timer); 115 | extern double my_timer_elapsed_cpu (const my_timer_t * timer); 116 | extern double my_timer_cpu_usage (const my_timer_t * timer); 117 | 118 | #endif // !defined UTIL_H 119 | 120 | // end of util.h 121 | 122 | --------------------------------------------------------------------------------