├── .gitignore ├── Copying.txt ├── Readme.md ├── example ├── book.bin ├── css │ └── chessboard-0.3.0.min.css ├── enginegame.js ├── fwcm2013.html ├── img │ └── chesspieces │ │ └── wikipedia │ │ ├── bB.png │ │ ├── bK.png │ │ ├── bN.png │ │ ├── bP.png │ │ ├── bQ.png │ │ ├── bR.png │ │ ├── wB.png │ │ ├── wK.png │ │ ├── wN.png │ │ ├── wP.png │ │ ├── wQ.png │ │ └── wR.png ├── index.html ├── js │ ├── chess.min.js │ └── chessboard-0.3.0.min.js ├── server.js ├── stockfish.js └── test.html ├── polyglot.ini ├── src ├── Makefile ├── benchmark.cpp ├── bitbase.cpp ├── bitboard.cpp ├── bitboard.h ├── bitcount.h ├── book.cpp ├── book.h ├── endgame.cpp ├── endgame.h ├── evaluate.cpp ├── evaluate.h ├── main.cpp ├── main.js ├── material.cpp ├── material.h ├── misc.cpp ├── misc.h ├── movegen.cpp ├── movegen.h ├── movepick.cpp ├── movepick.h ├── notation.cpp ├── notation.h ├── pawns.cpp ├── pawns.h ├── platform.h ├── position.cpp ├── position.h ├── psqtab.h ├── rkiss.h ├── search.cpp ├── search.h ├── thread.cpp ├── thread.h ├── timeman.cpp ├── timeman.h ├── tt.cpp ├── tt.h ├── types.h ├── uci.cpp ├── ucioption.cpp └── ucioption.h └── stockfishjs /.gitignore: -------------------------------------------------------------------------------- 1 | .cproject 2 | .depend 3 | .project 4 | .settings/ 5 | *.o 6 | stockfish 7 | /src/stockfish.js* 8 | node_modules/ 9 | *~ -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ### Stockfish-js 2 | 3 | Stockfish-js is an emscripten port of the stockfish chess engine. 4 | (Emscripten being a c[++] to javascript compiler.) 5 | This enables one to run one of the strongest chess engines available 6 | without downloads or plugins in a web browser. 7 | In Firefox, thanks to its asm.js support, it runs at a respactable 8 | 1/3 of the (single-threaded) speed of a native compile on my machine. 9 | In Chrome it reaches about half the speed of FF - after a short 10 | warm-up time. 11 | 12 | ### Download 13 | 14 | Download Stockfish 5 compiled to javascript: 15 | [stockfish.js](https://github.com/exoticorn/stockfish-js/releases/download/sf_5_js/stockfish.js) 16 | 17 | ### See also 18 | 19 | [stockfish.js](https://github.com/nmrugg/stockfish.js) is a fork of this fork which adds some 20 | interesting features. Most notably is the ability for the engine to receive commands between 21 | iterations, which allows aborting an infitite search (pondering/analysing). 22 | 23 | ### API 24 | 25 | Stockfish-js is designed to run in a web-worker, which can be created 26 | like this: 27 | 28 | var stockfish = new Worker('stockfish.js'); 29 | 30 | Input (standard UCI commands) to the engine is posted as a message to the worker: 31 | 32 | engine.postMessage('go depth 15'); 33 | 34 | The output of the engine is again posted as a message, to receive it 35 | you need to install an event handler: 36 | 37 | engine.onmessage = function(event) { 38 | console.log(event.data); 39 | }; 40 | 41 | Since the engine cannot load an opening book from the filesystem, there 42 | is a special message "{book: }" to send a book 43 | that you have downloaded yourself to the engine: 44 | 45 | var bookRequest = new XMLHttpRequest(); 46 | bookRequest.open('GET', 'book.bin', true); 47 | bookRequest.responseType = "arraybuffer"; 48 | bookRequest.onload = function(event) { 49 | if(bookRequest.status == 200) 50 | engine.postMessage({book: bookRequest.response}); 51 | }; 52 | bookRequest.send(null); 53 | 54 | ### Restrictions 55 | 56 | Since there is no support for multi-threading with shared state in browsers, 57 | the engine can only run in a single thread. The 'Threads' option is therefore 58 | ignored. 59 | 60 | The engine cannot receive a command during a search. This means that the 61 | 'stop' and 'ponderhit' commands will not work as intended. 62 | So pondering make no sense at all, and infinite analysis ('go infinite') 63 | only limited sense, as the only way to stop the search is to kill the 64 | web-worker and start a new one for the next position to analyze which 65 | incurrs quite some overhead and obviously loses the state of the hash. 66 | 67 | ### Compiling 68 | 69 | You need to have the emscripten compiler installed and in your path. 70 | Then you can compile Stockfish-js like this: 71 | 72 | make build ARCH=js 73 | 74 | ### Example 75 | 76 | There is an example implementation of a game against the computer in 77 | the example folder. To run this, it needs to be served by a webserver. 78 | If you have node.js, you can start a simple webserver in that directory 79 | like this: 80 | 81 | npm install connect # once to install the connect library 82 | node server.js 83 | 84 | Alternatively, there is a online version of this example here: 85 | [exoticorn.github.io/stockfish-js](http://exoticorn.github.io/stockfish-js) 86 | 87 | The example uses the excellent [chess.js](http://github.com/jhlywa/chess.js) 88 | and [chessboard.js](http://chessboardjs.com/) libraries. 89 | 90 | ## Original Stockfish Readme: 91 | 92 | ### Overview 93 | 94 | Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is 95 | not a complete chess program and requires some UCI-compatible GUI 96 | (e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess 97 | Partner or Fritz) in order to be used comfortably. Read the 98 | documentation for your GUI of choice for information about how to use 99 | Stockfish with it. 100 | 101 | This version of Stockfish supports up to 128 CPUs. The engine defaults 102 | to one search thread, so it is therefore recommended to inspect the value of 103 | the *Threads* UCI parameter, and to make sure it equals the number of CPU 104 | cores on your computer. 105 | 106 | 107 | ### Files 108 | 109 | This distribution of Stockfish consists of the following files: 110 | 111 | * Readme.md, the file you are currently reading. 112 | 113 | * Copying.txt, a text file containing the GNU General Public License. 114 | 115 | * src, a subdirectory containing the full source code, including a Makefile 116 | that can be used to compile Stockfish on Unix-like systems. For further 117 | information about how to compile Stockfish yourself read section below. 118 | 119 | * polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot 120 | adapter. 121 | 122 | 123 | ### Opening books 124 | 125 | This version of Stockfish has support for PolyGlot opening books. For 126 | information about how to create such books, consult the PolyGlot 127 | documentation. The book file can be selected by setting the *Book File* 128 | UCI parameter. 129 | 130 | 131 | ### Compiling it yourself 132 | 133 | On Unix-like systems, it should be possible to compile Stockfish 134 | directly from the source code with the included Makefile. 135 | 136 | Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT 137 | instruction, big-endian machines such as Power PC, and other platforms. 138 | 139 | In general it is recommended to run `make help` to see a list of make 140 | targets with corresponding descriptions. When not using the Makefile to 141 | compile (for instance with Microsoft MSVC) you need to manually 142 | set/unset some switches in the compiler command line; see file *types.h* 143 | for a quick reference. 144 | 145 | 146 | ### Terms of use 147 | 148 | Stockfish is free, and distributed under the **GNU General Public License** 149 | (GPL). Essentially, this means that you are free to do almost exactly 150 | what you want with the program, including distributing it among your 151 | friends, making it available for download from your web site, selling 152 | it (either by itself or as part of some bigger software package), or 153 | using it as the starting point for a software project of your own. 154 | 155 | The only real limitation is that whenever you distribute Stockfish in 156 | some way, you must always include the full source code, or a pointer 157 | to where the source code can be found. If you make any changes to the 158 | source code, these changes must also be made available under the GPL. 159 | 160 | For full details, read the copy of the GPL found in the file named 161 | *Copying.txt* 162 | -------------------------------------------------------------------------------- /example/book.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/book.bin -------------------------------------------------------------------------------- /example/css/chessboard-0.3.0.min.css: -------------------------------------------------------------------------------- 1 | /*! chessboard.js v0.3.0 | (c) 2013 Chris Oakman | MIT License chessboardjs.com/license */ 2 | .clearfix-7da63{clear:both}.board-b72b1{border:2px solid #404040;-moz-box-sizing:content-box;box-sizing:content-box}.square-55d63{float:left;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.white-1e1d7{background-color:#f0d9b5;color:#b58863}.black-3c85d{background-color:#b58863;color:#f0d9b5}.highlight1-32417,.highlight2-9c5d2{-webkit-box-shadow:inset 0 0 3px 3px yellow;-moz-box-shadow:inset 0 0 3px 3px yellow;box-shadow:inset 0 0 3px 3px yellow}.notation-322f9{cursor:default;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;position:absolute}.alpha-d2270{bottom:1px;right:3px}.numeric-fc462{top:2px;left:2px} -------------------------------------------------------------------------------- /example/enginegame.js: -------------------------------------------------------------------------------- 1 | function engineGame(options) { 2 | options = options || {} 3 | var game = new Chess(); 4 | var board; 5 | var engine = new Worker(options.stockfishjs || 'stockfish.js'); 6 | var engineStatus = {}; 7 | var displayScore = false; 8 | var time = { wtime: 300000, btime: 300000, winc: 2000, binc: 2000 }; 9 | var playerColor = 'white'; 10 | var clockTimeoutID = null; 11 | var isEngineRunning = false; 12 | 13 | // do not pick up pieces if the game is over 14 | // only pick up pieces for White 15 | var onDragStart = function(source, piece, position, orientation) { 16 | var re = playerColor == 'white' ? /^b/ : /^w/ 17 | if (game.game_over() || 18 | piece.search(re) !== -1) { 19 | return false; 20 | } 21 | }; 22 | 23 | function uciCmd(cmd) { 24 | engine.postMessage(cmd); 25 | } 26 | uciCmd('uci'); 27 | 28 | function displayStatus() { 29 | var status = 'Engine: '; 30 | if(!engineStatus.engineLoaded) { 31 | status += 'loading...'; 32 | } else if(!engineStatus.engineReady) { 33 | status += 'loaded...'; 34 | } else { 35 | status += 'ready.'; 36 | } 37 | status += ' Book: ' + engineStatus.book; 38 | if(engineStatus.search) { 39 | status += '
' + engineStatus.search; 40 | if(engineStatus.score && displayScore) { 41 | status += ' Score: ' + engineStatus.score; 42 | } 43 | } 44 | $('#engineStatus').html(status); 45 | } 46 | 47 | function displayClock(color, t) { 48 | var isRunning = false; 49 | if(time.startTime > 0 && color == time.clockColor) { 50 | t = Math.max(0, t + time.startTime - Date.now()); 51 | isRunning = true; 52 | } 53 | var id = color == playerColor ? '#time2' : '#time1'; 54 | var sec = Math.ceil(t / 1000); 55 | var min = Math.floor(sec / 60); 56 | sec -= min * 60; 57 | var hours = Math.floor(min / 60); 58 | min -= hours * 60; 59 | var display = hours + ':' + ('0' + min).slice(-2) + ':' + ('0' + sec).slice(-2); 60 | if(isRunning) { 61 | display += sec & 1 ? ' <--' : ' <-'; 62 | } 63 | $(id).text(display); 64 | } 65 | 66 | function updateClock() { 67 | displayClock('white', time.wtime); 68 | displayClock('black', time.btime); 69 | } 70 | 71 | function clockTick() { 72 | updateClock(); 73 | var t = (time.clockColor == 'white' ? time.wtime : time.btime) + time.startTime - Date.now(); 74 | var timeToNextSecond = (t % 1000) + 1; 75 | clockTimeoutID = setTimeout(clockTick, timeToNextSecond); 76 | } 77 | 78 | function stopClock() { 79 | if(clockTimeoutID !== null) { 80 | clearTimeout(clockTimeoutID); 81 | clockTimeoutID = null; 82 | } 83 | if(time.startTime > 0) { 84 | var elapsed = Date.now() - time.startTime; 85 | time.startTime = null; 86 | if(time.clockColor == 'white') { 87 | time.wtime = Math.max(0, time.wtime - elapsed); 88 | } else { 89 | time.btime = Math.max(0, time.btime - elapsed); 90 | } 91 | } 92 | } 93 | 94 | function startClock() { 95 | if(game.turn() == 'w') { 96 | time.wtime += time.winc; 97 | time.clockColor = 'white'; 98 | } else { 99 | time.btime += time.binc; 100 | time.clockColor = 'black'; 101 | } 102 | time.startTime = Date.now(); 103 | clockTick(); 104 | } 105 | 106 | function prepareMove() { 107 | stopClock(); 108 | $('#pgn').text(game.pgn()); 109 | board.position(game.fen()); 110 | updateClock(); 111 | var turn = game.turn() == 'w' ? 'white' : 'black'; 112 | if(!game.game_over()) { 113 | if(turn != playerColor) { 114 | var moves = ''; 115 | var history = game.history({verbose: true}); 116 | for(var i = 0; i < history.length; ++i) { 117 | var move = history[i]; 118 | moves += ' ' + move.from + move.to + (move.promotion ? move.promotion : ''); 119 | } 120 | uciCmd('position startpos moves' + moves); 121 | if(time.depth) { 122 | uciCmd('go depth ' + time.depth); 123 | } else if(time.nodes) { 124 | uciCmd('go nodes ' + time.nodes); 125 | } else { 126 | uciCmd('go wtime ' + time.wtime + ' winc ' + time.winc + ' btime ' + time.btime + ' binc ' + time.binc); 127 | } 128 | isEngineRunning = true; 129 | } 130 | if(game.history().length >= 2 && !time.depth && !time.nodes) { 131 | startClock(); 132 | } 133 | } 134 | } 135 | 136 | engine.onmessage = function(event) { 137 | var line = event.data; 138 | if(line == 'uciok') { 139 | engineStatus.engineLoaded = true; 140 | } else if(line == 'readyok') { 141 | engineStatus.engineReady = true; 142 | } else { 143 | var match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([qrbk])?/); 144 | if(match) { 145 | isEngineRunning = false; 146 | game.move({from: match[1], to: match[2], promotion: match[3]}); 147 | prepareMove(); 148 | } else if(match = line.match(/^info .*\bdepth (\d+) .*\bnps (\d+)/)) { 149 | engineStatus.search = 'Depth: ' + match[1] + ' Nps: ' + match[2]; 150 | } 151 | if(match = line.match(/^info .*\bscore (\w+) (-?\d+)/)) { 152 | var score = parseInt(match[2]) * (game.turn() == 'w' ? 1 : -1); 153 | if(match[1] == 'cp') { 154 | engineStatus.score = (score / 100.0).toFixed(2); 155 | } else if(match[1] == 'mate') { 156 | engineStatus.score = '#' + score; 157 | } 158 | if(match = line.match(/\b(upper|lower)bound\b/)) { 159 | engineStatus.score = ((match[1] == 'upper') == (game.turn() == 'w') ? '<= ' : '>= ') + engineStatus.score 160 | } 161 | } 162 | } 163 | displayStatus(); 164 | }; 165 | 166 | var onDrop = function(source, target) { 167 | // see if the move is legal 168 | var move = game.move({ 169 | from: source, 170 | to: target, 171 | promotion: 'q' // NOTE: always promote to a pawn for example simplicity 172 | }); 173 | 174 | // illegal move 175 | if (move === null) return 'snapback'; 176 | 177 | prepareMove(); 178 | }; 179 | 180 | // update the board position after the piece snap 181 | // for castling, en passant, pawn promotion 182 | var onSnapEnd = function() { 183 | board.position(game.fen()); 184 | }; 185 | 186 | var cfg = { 187 | draggable: true, 188 | position: 'start', 189 | onDragStart: onDragStart, 190 | onDrop: onDrop, 191 | onSnapEnd: onSnapEnd 192 | }; 193 | 194 | if(options.book) { 195 | var bookRequest = new XMLHttpRequest(); 196 | bookRequest.open('GET', options.book, true); 197 | bookRequest.responseType = "arraybuffer"; 198 | bookRequest.onload = function(event) { 199 | if(bookRequest.status == 200) { 200 | engine.postMessage({book: bookRequest.response}); 201 | engineStatus.book = 'ready.'; 202 | displayStatus(); 203 | } else { 204 | engineStatus.book = 'failed!'; 205 | displayStatus(); 206 | } 207 | }; 208 | bookRequest.send(null); 209 | } else { 210 | engineStatus.book = 'none'; 211 | } 212 | 213 | board = new ChessBoard('board', cfg); 214 | 215 | return { 216 | reset: function() { 217 | game.reset(); 218 | uciCmd('setoption name Contempt Factor value 0'); 219 | uciCmd('setoption name Skill Level value 20'); 220 | uciCmd('setoption name Aggressiveness value 100'); 221 | }, 222 | loadPgn: function(pgn) { game.load_pgn(pgn); }, 223 | setPlayerColor: function(color) { 224 | playerColor = color; 225 | board.orientation(playerColor); 226 | }, 227 | setSkillLevel: function(skill) { 228 | uciCmd('setoption name Skill Level value ' + skill); 229 | }, 230 | setTime: function(baseTime, inc) { 231 | time = { wtime: baseTime * 1000, btime: baseTime * 1000, winc: inc * 1000, binc: inc * 1000 }; 232 | }, 233 | setDepth: function(depth) { 234 | time = { depth: depth }; 235 | }, 236 | setNodes: function(nodes) { 237 | time = { nodes: nodes }; 238 | }, 239 | setContempt: function(contempt) { 240 | uciCmd('setoption name Contempt Factor value ' + contempt); 241 | }, 242 | setAggressiveness: function(value) { 243 | uciCmd('setoption name Aggressiveness value ' + value); 244 | }, 245 | setDisplayScore: function(flag) { 246 | displayScore = flag; 247 | displayStatus(); 248 | }, 249 | start: function() { 250 | uciCmd('ucinewgame'); 251 | uciCmd('isready'); 252 | engineStatus.engineReady = false; 253 | engineStatus.search = null; 254 | displayStatus(); 255 | prepareMove(); 256 | }, 257 | undo: function() { 258 | if(isEngineRunning) 259 | return false; 260 | game.undo(); 261 | game.undo(); 262 | engineStatus.search = null; 263 | displayStatus(); 264 | prepareMove(); 265 | return true; 266 | } 267 | }; 268 | } 269 | -------------------------------------------------------------------------------- /example/fwcm2013.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Positions from the World Championship 2013

15 |
16 |
17 | 18 | 19 | Show evaluation 20 |
21 |
...
22 |
23 |
24 | 25 |

Moves:

26 |
27 |
28 |
29 |
30 |
Compatibility
31 | This chess engine has been tested and found working in both Firefox 25 and Chrome 31. It runs about twice as fast in Firefox as in Chrome, so for best performance use Firefox. The engine has also been tested in Safari 6 where it does not run. It might run in a later version of this browser, though. It has not been tested in the Internet Explorer, but it should in theory run in IE versions >= 10. 32 |
33 |
34 | 35 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bB.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bK.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bN.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bP.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bQ.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/bR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/bR.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wB.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wK.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wN.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wP.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wQ.png -------------------------------------------------------------------------------- /example/img/chesspieces/wikipedia/wR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exoticorn/stockfish-js/79659c5acbf09ec528838278f8feb2883661db56/example/img/chesspieces/wikipedia/wR.png -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 0:05:00 15 |
16 | 0:05:00 17 |
18 |
...
19 |
20 |
21 |

Moves:

22 |
23 |
24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 | 48 | 49 |
50 |
51 |
52 |
53 | 54 |
55 | 56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 |
65 |
Compatibility
66 | This chess engine has been tested and found working in both Firefox 25 and Chrome 31. It runs about twice as fast in Firefox as in Chrome, so for best performance use Firefox. The engine has also been tested in Safari 6 where it does not run. It might run in a later version of this browser, though. It has not been tested in the Internet Explorer, but it should in theory run in IE versions >= 10. 67 |
68 |
69 | 70 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | var connect = require('connect'); 2 | connect.createServer(connect.static(__dirname)).listen(8080); 3 | -------------------------------------------------------------------------------- /example/stockfish.js: -------------------------------------------------------------------------------- 1 | ../src/stockfish.js -------------------------------------------------------------------------------- /example/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /polyglot.ini: -------------------------------------------------------------------------------- 1 | [PolyGlot] 2 | 3 | EngineDir = . 4 | EngineCommand = ./stockfish 5 | 6 | Book = false 7 | BookFile = book.bin 8 | 9 | Log = false 10 | LogFile = stockfish.log 11 | 12 | Resign = true 13 | ResignScore = 600 14 | 15 | [Engine] 16 | 17 | Write Debug Log = false 18 | Write Search Log = false 19 | Search Log Filename = SearchLog.txt 20 | Book File = book.bin 21 | Best Book Move = false 22 | Contempt Factor = 0 23 | Mobility (Midgame) = 100 24 | Mobility (Endgame) = 100 25 | Pawn Structure (Midgame) = 100 26 | Pawn Structure (Endgame) = 100 27 | Passed Pawns (Midgame) = 100 28 | Passed Pawns (Endgame) = 100 29 | Space = 100 30 | King Safety = 100 31 | Min Split Depth = 0 32 | Threads = 1 33 | Hash = 128 34 | Ponder = true 35 | OwnBook = false 36 | MultiPV = 1 37 | Skill Level = 20 38 | Emergency Move Horizon = 40 39 | Emergency Base Time = 200 40 | Emergency Move Time = 70 41 | Minimum Thinking Time = 20 42 | Slow Mover = 100 43 | UCI_Chess960 = false 44 | -------------------------------------------------------------------------------- /src/benchmark.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "misc.h" 26 | #include "notation.h" 27 | #include "position.h" 28 | #include "search.h" 29 | #include "thread.h" 30 | #include "tt.h" 31 | #include "ucioption.h" 32 | 33 | using namespace std; 34 | 35 | static const char* Defaults[] = { 36 | "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 37 | "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", 38 | "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11", 39 | "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", 40 | "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", 41 | "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", 42 | "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", 43 | "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", 44 | "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", 45 | "4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17", 46 | "2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11", 47 | "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16", 48 | "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", 49 | "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", 50 | "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", 51 | "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26", 52 | "6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1", 53 | "3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1", 54 | "2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1", 55 | "8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1", 56 | "7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1", 57 | "8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1", 58 | "8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1", 59 | "8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1", 60 | "8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1", 61 | "5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1", 62 | "6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1", 63 | "1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1", 64 | "6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1", 65 | "8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1" 66 | }; 67 | 68 | 69 | /// benchmark() runs a simple benchmark by letting Stockfish analyze a set 70 | /// of positions for a given limit each. There are five parameters: the 71 | /// transposition table size, the number of search threads that should 72 | /// be used, the limit value spent for each position (optional, default is 73 | /// depth 13), an optional file name where to look for positions in FEN 74 | /// format (defaults are the positions defined above) and the type of the 75 | /// limit value: depth (default), time in secs or number of nodes. 76 | 77 | void benchmark(const Position& current, istream& is) { 78 | 79 | string token; 80 | Search::LimitsType limits; 81 | vector fens; 82 | 83 | // Assign default values to missing arguments 84 | string ttSize = (is >> token) ? token : "32"; 85 | string threads = (is >> token) ? token : "1"; 86 | string limit = (is >> token) ? token : "13"; 87 | string fenFile = (is >> token) ? token : "default"; 88 | string limitType = (is >> token) ? token : "depth"; 89 | 90 | Options["Hash"] = ttSize; 91 | Options["Threads"] = threads; 92 | TT.clear(); 93 | 94 | if (limitType == "time") 95 | limits.movetime = 1000 * atoi(limit.c_str()); // movetime is in ms 96 | 97 | else if (limitType == "nodes") 98 | limits.nodes = atoi(limit.c_str()); 99 | 100 | else if (limitType == "mate") 101 | limits.mate = atoi(limit.c_str()); 102 | 103 | else 104 | limits.depth = atoi(limit.c_str()); 105 | 106 | if (fenFile == "default") 107 | fens.assign(Defaults, Defaults + 30); 108 | 109 | else if (fenFile == "current") 110 | fens.push_back(current.fen()); 111 | 112 | else 113 | { 114 | string fen; 115 | ifstream file(fenFile.c_str()); 116 | 117 | if (!file.is_open()) 118 | { 119 | cerr << "Unable to open file " << fenFile << endl; 120 | return; 121 | } 122 | 123 | while (getline(file, fen)) 124 | if (!fen.empty()) 125 | fens.push_back(fen); 126 | 127 | file.close(); 128 | } 129 | 130 | uint64_t nodes = 0; 131 | Search::StateStackPtr st; 132 | Time::point elapsed = Time::now(); 133 | 134 | for (size_t i = 0; i < fens.size(); ++i) 135 | { 136 | Position pos(fens[i], Options["UCI_Chess960"], Threads.main()); 137 | 138 | cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl; 139 | 140 | if (limitType == "divide") 141 | for (MoveList it(pos); *it; ++it) 142 | { 143 | StateInfo si; 144 | pos.do_move(*it, si); 145 | uint64_t cnt = limits.depth > 1 ? Search::perft(pos, (limits.depth - 1) * ONE_PLY) : 1; 146 | pos.undo_move(*it); 147 | cerr << move_to_uci(*it, pos.is_chess960()) << ": " << cnt << endl; 148 | nodes += cnt; 149 | } 150 | else if (limitType == "perft") 151 | { 152 | uint64_t cnt = Search::perft(pos, limits.depth * ONE_PLY); 153 | cerr << "\nPerft " << limits.depth << " leaf nodes: " << cnt << endl; 154 | nodes += cnt; 155 | } 156 | else 157 | { 158 | Threads.start_thinking(pos, limits, st); 159 | Threads.wait_for_think_finished(); 160 | nodes += Search::RootPos.nodes_searched(); 161 | } 162 | } 163 | 164 | elapsed = Time::now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero' 165 | 166 | dbg_print(); // Just before to exit 167 | 168 | cerr << "\n===========================" 169 | << "\nTotal time (ms) : " << elapsed 170 | << "\nNodes searched : " << nodes 171 | << "\nNodes/second : " << 1000 * nodes / elapsed << endl; 172 | } 173 | -------------------------------------------------------------------------------- /src/bitbase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "bitboard.h" 24 | #include "types.h" 25 | 26 | namespace { 27 | 28 | // There are 24 possible pawn squares: the first 4 files and ranks from 2 to 7 29 | const unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608 30 | 31 | // Each uint32_t stores results of 32 positions, one per bit 32 | uint32_t KPKBitbase[MAX_INDEX / 32]; 33 | 34 | // A KPK bitbase index is an integer in [0, IndexMax] range 35 | // 36 | // Information is mapped in a way that minimizes the number of iterations: 37 | // 38 | // bit 0- 5: white king square (from SQ_A1 to SQ_H8) 39 | // bit 6-11: black king square (from SQ_A1 to SQ_H8) 40 | // bit 12: side to move (WHITE or BLACK) 41 | // bit 13-14: white pawn file (from FILE_A to FILE_D) 42 | // bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2) 43 | unsigned index(Color us, Square bksq, Square wksq, Square psq) { 44 | return wksq + (bksq << 6) + (us << 12) + (file_of(psq) << 13) + ((RANK_7 - rank_of(psq)) << 15); 45 | } 46 | 47 | enum Result { 48 | INVALID = 0, 49 | UNKNOWN = 1, 50 | DRAW = 2, 51 | WIN = 4 52 | }; 53 | 54 | inline Result& operator|=(Result& r, Result v) { return r = Result(r | v); } 55 | 56 | struct KPKPosition { 57 | 58 | KPKPosition(unsigned idx); 59 | operator Result() const { return result; } 60 | Result classify(const std::vector& db) 61 | { return us == WHITE ? classify(db) : classify(db); } 62 | 63 | private: 64 | template Result classify(const std::vector& db); 65 | 66 | Color us; 67 | Square bksq, wksq, psq; 68 | Result result; 69 | }; 70 | 71 | } // namespace 72 | 73 | 74 | bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color us) { 75 | 76 | assert(file_of(wpsq) <= FILE_D); 77 | 78 | unsigned idx = index(us, bksq, wksq, wpsq); 79 | return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); 80 | } 81 | 82 | 83 | void Bitbases::init_kpk() { 84 | 85 | unsigned idx, repeat = 1; 86 | std::vector db; 87 | db.reserve(MAX_INDEX); 88 | 89 | // Initialize db with known win / draw positions 90 | for (idx = 0; idx < MAX_INDEX; ++idx) 91 | db.push_back(KPKPosition(idx)); 92 | 93 | // Iterate through the positions until none of the unknown positions can be 94 | // changed to either wins or draws (15 cycles needed). 95 | while (repeat) 96 | for (repeat = idx = 0; idx < MAX_INDEX; ++idx) 97 | repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN); 98 | 99 | // Map 32 results into one KPKBitbase[] entry 100 | for (idx = 0; idx < MAX_INDEX; ++idx) 101 | if (db[idx] == WIN) 102 | KPKBitbase[idx / 32] |= 1 << (idx & 0x1F); 103 | } 104 | 105 | 106 | namespace { 107 | 108 | KPKPosition::KPKPosition(unsigned idx) { 109 | 110 | wksq = Square((idx >> 0) & 0x3F); 111 | bksq = Square((idx >> 6) & 0x3F); 112 | us = Color ((idx >> 12) & 0x01); 113 | psq = make_square(File((idx >> 13) & 0x03), Rank(RANK_7 - (idx >> 15))); 114 | result = UNKNOWN; 115 | 116 | // Check if two pieces are on the same square or if a king can be captured 117 | if ( square_distance(wksq, bksq) <= 1 118 | || wksq == psq 119 | || bksq == psq 120 | || (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq))) 121 | result = INVALID; 122 | 123 | else if (us == WHITE) 124 | { 125 | // Immediate win if a pawn can be promoted without getting captured 126 | if ( rank_of(psq) == RANK_7 127 | && wksq != psq + DELTA_N 128 | && ( square_distance(bksq, psq + DELTA_N) > 1 129 | ||(StepAttacksBB[KING][wksq] & (psq + DELTA_N)))) 130 | result = WIN; 131 | } 132 | // Immediate draw if it is a stalemate or a king captures undefended pawn 133 | else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq])) 134 | || (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq])) 135 | result = DRAW; 136 | } 137 | 138 | template 139 | Result KPKPosition::classify(const std::vector& db) { 140 | 141 | // White to Move: If one move leads to a position classified as WIN, the result 142 | // of the current position is WIN. If all moves lead to positions classified 143 | // as DRAW, the current position is classified as DRAW, otherwise the current 144 | // position is classified as UNKNOWN. 145 | // 146 | // Black to Move: If one move leads to a position classified as DRAW, the result 147 | // of the current position is DRAW. If all moves lead to positions classified 148 | // as WIN, the position is classified as WIN, otherwise the current position is 149 | // classified as UNKNOWN. 150 | 151 | const Color Them = (Us == WHITE ? BLACK : WHITE); 152 | 153 | Result r = INVALID; 154 | Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq]; 155 | 156 | while (b) 157 | r |= Us == WHITE ? db[index(Them, bksq, pop_lsb(&b), psq)] 158 | : db[index(Them, pop_lsb(&b), wksq, psq)]; 159 | 160 | if (Us == WHITE && rank_of(psq) < RANK_7) 161 | { 162 | Square s = psq + DELTA_N; 163 | r |= db[index(BLACK, bksq, wksq, s)]; // Single push 164 | 165 | if (rank_of(psq) == RANK_2 && s != wksq && s != bksq) 166 | r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push 167 | } 168 | 169 | if (Us == WHITE) 170 | return result = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW; 171 | else 172 | return result = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN; 173 | } 174 | 175 | } // namespace 176 | -------------------------------------------------------------------------------- /src/bitboard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include // For memset 22 | 23 | #include "bitboard.h" 24 | #include "bitcount.h" 25 | #include "rkiss.h" 26 | 27 | CACHE_LINE_ALIGNMENT 28 | 29 | Bitboard RMasks[SQUARE_NB]; 30 | Bitboard RMagics[SQUARE_NB]; 31 | Bitboard* RAttacks[SQUARE_NB]; 32 | unsigned RShifts[SQUARE_NB]; 33 | 34 | Bitboard BMasks[SQUARE_NB]; 35 | Bitboard BMagics[SQUARE_NB]; 36 | Bitboard* BAttacks[SQUARE_NB]; 37 | unsigned BShifts[SQUARE_NB]; 38 | 39 | Bitboard SquareBB[SQUARE_NB]; 40 | Bitboard FileBB[FILE_NB]; 41 | Bitboard RankBB[RANK_NB]; 42 | Bitboard AdjacentFilesBB[FILE_NB]; 43 | Bitboard InFrontBB[COLOR_NB][RANK_NB]; 44 | Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB]; 45 | Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; 46 | Bitboard LineBB[SQUARE_NB][SQUARE_NB]; 47 | Bitboard DistanceRingsBB[SQUARE_NB][8]; 48 | Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; 49 | Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; 50 | Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; 51 | Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; 52 | 53 | int SquareDistance[SQUARE_NB][SQUARE_NB]; 54 | 55 | namespace { 56 | 57 | // De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan 58 | const uint64_t DeBruijn_64 = 0x3F79D71B4CB0A89ULL; 59 | const uint32_t DeBruijn_32 = 0x783A9B23; 60 | 61 | CACHE_LINE_ALIGNMENT 62 | 63 | int MS1BTable[256]; 64 | Square BSFTable[SQUARE_NB]; 65 | Bitboard RTable[0x19000]; // Storage space for rook attacks 66 | Bitboard BTable[0x1480]; // Storage space for bishop attacks 67 | 68 | typedef unsigned (Fn)(Square, Bitboard); 69 | 70 | void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], 71 | Bitboard masks[], unsigned shifts[], Square deltas[], Fn index); 72 | 73 | FORCE_INLINE unsigned bsf_index(Bitboard b) { 74 | 75 | // Matt Taylor's folding for 32 bit systems, extended to 64 bits by Kim Walisch 76 | b ^= (b - 1); 77 | return Is64Bit ? (b * DeBruijn_64) >> 58 78 | : ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn_32) >> 26; 79 | } 80 | } 81 | 82 | /// lsb()/msb() finds the least/most significant bit in a non-zero bitboard. 83 | /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard. 84 | 85 | #ifndef USE_BSFQ 86 | 87 | Square lsb(Bitboard b) { return BSFTable[bsf_index(b)]; } 88 | 89 | Square pop_lsb(Bitboard* b) { 90 | 91 | Bitboard bb = *b; 92 | *b = bb & (bb - 1); 93 | return BSFTable[bsf_index(bb)]; 94 | } 95 | 96 | Square msb(Bitboard b) { 97 | 98 | unsigned b32; 99 | int result = 0; 100 | 101 | if (b > 0xFFFFFFFF) 102 | { 103 | b >>= 32; 104 | result = 32; 105 | } 106 | 107 | b32 = unsigned(b); 108 | 109 | if (b32 > 0xFFFF) 110 | { 111 | b32 >>= 16; 112 | result += 16; 113 | } 114 | 115 | if (b32 > 0xFF) 116 | { 117 | b32 >>= 8; 118 | result += 8; 119 | } 120 | 121 | return Square(result + MS1BTable[b32]); 122 | } 123 | 124 | #endif // ifndef USE_BSFQ 125 | 126 | 127 | /// Bitboards::pretty() returns an ASCII representation of a bitboard to be 128 | /// printed to standard output. This is sometimes useful for debugging. 129 | 130 | const std::string Bitboards::pretty(Bitboard b) { 131 | 132 | std::string s = "+---+---+---+---+---+---+---+---+\n"; 133 | 134 | for (Rank r = RANK_8; r >= RANK_1; --r) 135 | { 136 | for (File f = FILE_A; f <= FILE_H; ++f) 137 | s.append(b & make_square(f, r) ? "| X " : "| "); 138 | 139 | s.append("|\n+---+---+---+---+---+---+---+---+\n"); 140 | } 141 | 142 | return s; 143 | } 144 | 145 | 146 | /// Bitboards::init() initializes various bitboard tables. It is called at 147 | /// startup and relies on global objects to be already zero-initialized. 148 | 149 | void Bitboards::init() { 150 | 151 | for (Square s = SQ_A1; s <= SQ_H8; ++s) 152 | BSFTable[bsf_index(SquareBB[s] = 1ULL << s)] = s; 153 | 154 | for (Bitboard b = 1; b < 256; ++b) 155 | MS1BTable[b] = more_than_one(b) ? MS1BTable[b - 1] : lsb(b); 156 | 157 | for (File f = FILE_A; f <= FILE_H; ++f) 158 | FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB; 159 | 160 | for (Rank r = RANK_1; r <= RANK_8; ++r) 161 | RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB; 162 | 163 | for (File f = FILE_A; f <= FILE_H; ++f) 164 | AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0); 165 | 166 | for (Rank r = RANK_1; r < RANK_8; ++r) 167 | InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]); 168 | 169 | for (Color c = WHITE; c <= BLACK; ++c) 170 | for (Square s = SQ_A1; s <= SQ_H8; ++s) 171 | { 172 | ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)]; 173 | PawnAttackSpan[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; 174 | PassedPawnMask[c][s] = ForwardBB[c][s] | PawnAttackSpan[c][s]; 175 | } 176 | 177 | for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) 178 | for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) 179 | if (s1 != s2) 180 | { 181 | SquareDistance[s1][s2] = std::max(file_distance(s1, s2), rank_distance(s1, s2)); 182 | DistanceRingsBB[s1][SquareDistance[s1][s2] - 1] |= s2; 183 | } 184 | 185 | int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 }, 186 | {}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } }; 187 | 188 | for (Color c = WHITE; c <= BLACK; ++c) 189 | for (PieceType pt = PAWN; pt <= KING; ++pt) 190 | for (Square s = SQ_A1; s <= SQ_H8; ++s) 191 | for (int i = 0; steps[pt][i]; ++i) 192 | { 193 | Square to = s + Square(c == WHITE ? steps[pt][i] : -steps[pt][i]); 194 | 195 | if (is_ok(to) && square_distance(s, to) < 3) 196 | StepAttacksBB[make_piece(c, pt)][s] |= to; 197 | } 198 | 199 | Square RDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W }; 200 | Square BDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW }; 201 | 202 | init_magics(RTable, RAttacks, RMagics, RMasks, RShifts, RDeltas, magic_index); 203 | init_magics(BTable, BAttacks, BMagics, BMasks, BShifts, BDeltas, magic_index); 204 | 205 | for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) 206 | { 207 | PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); 208 | PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); 209 | 210 | for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) 211 | { 212 | Piece pc = (PseudoAttacks[BISHOP][s1] & s2) ? W_BISHOP : 213 | (PseudoAttacks[ROOK][s1] & s2) ? W_ROOK : NO_PIECE; 214 | 215 | if (pc == NO_PIECE) 216 | continue; 217 | 218 | LineBB[s1][s2] = (attacks_bb(pc, s1, 0) & attacks_bb(pc, s2, 0)) | s1 | s2; 219 | BetweenBB[s1][s2] = attacks_bb(pc, s1, SquareBB[s2]) & attacks_bb(pc, s2, SquareBB[s1]); 220 | } 221 | } 222 | } 223 | 224 | 225 | namespace { 226 | 227 | Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) { 228 | 229 | Bitboard attack = 0; 230 | 231 | for (int i = 0; i < 4; ++i) 232 | for (Square s = sq + deltas[i]; 233 | is_ok(s) && square_distance(s, s - deltas[i]) == 1; 234 | s += deltas[i]) 235 | { 236 | attack |= s; 237 | 238 | if (occupied & s) 239 | break; 240 | } 241 | 242 | return attack; 243 | } 244 | 245 | 246 | // init_magics() computes all rook and bishop attacks at startup. Magic 247 | // bitboards are used to look up attacks of sliding pieces. As a reference see 248 | // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we 249 | // use the so called "fancy" approach. 250 | 251 | void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], 252 | Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) { 253 | 254 | int MagicBoosters[][8] = { { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 }, 255 | { 3101, 552, 3555, 926, 834, 26, 2131, 1117 } }; 256 | 257 | RKISS rk; 258 | Bitboard occupancy[4096], reference[4096], edges, b; 259 | int i, size, booster; 260 | 261 | // attacks[s] is a pointer to the beginning of the attacks table for square 's' 262 | attacks[SQ_A1] = table; 263 | 264 | for (Square s = SQ_A1; s <= SQ_H8; ++s) 265 | { 266 | // Board edges are not considered in the relevant occupancies 267 | edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s)); 268 | 269 | // Given a square 's', the mask is the bitboard of sliding attacks from 270 | // 's' computed on an empty board. The index must be big enough to contain 271 | // all the attacks for each possible subset of the mask and so is 2 power 272 | // the number of 1s of the mask. Hence we deduce the size of the shift to 273 | // apply to the 64 or 32 bits word to get the index. 274 | masks[s] = sliding_attack(deltas, s, 0) & ~edges; 275 | shifts[s] = (Is64Bit ? 64 : 32) - popcount(masks[s]); 276 | 277 | // Use Carry-Rippler trick to enumerate all subsets of masks[s] and 278 | // store the corresponding sliding attack bitboard in reference[]. 279 | b = size = 0; 280 | do { 281 | occupancy[size] = b; 282 | reference[size] = sliding_attack(deltas, s, b); 283 | 284 | if (HasPext) 285 | attacks[s][_pext_u64(b, masks[s])] = reference[size]; 286 | 287 | size++; 288 | b = (b - masks[s]) & masks[s]; 289 | } while (b); 290 | 291 | // Set the offset for the table of the next square. We have individual 292 | // table sizes for each square with "Fancy Magic Bitboards". 293 | if (s < SQ_H8) 294 | attacks[s + 1] = attacks[s] + size; 295 | 296 | if (HasPext) 297 | continue; 298 | 299 | booster = MagicBoosters[Is64Bit][rank_of(s)]; 300 | 301 | // Find a magic for square 's' picking up an (almost) random number 302 | // until we find the one that passes the verification test. 303 | do { 304 | do magics[s] = rk.magic_rand(booster); 305 | while (popcount((magics[s] * masks[s]) >> 56) < 6); 306 | 307 | std::memset(attacks[s], 0, size * sizeof(Bitboard)); 308 | 309 | // A good magic must map every possible occupancy to an index that 310 | // looks up the correct sliding attack in the attacks[s] database. 311 | // Note that we build up the database for square 's' as a side 312 | // effect of verifying the magic. 313 | for (i = 0; i < size; ++i) 314 | { 315 | Bitboard& attack = attacks[s][index(s, occupancy[i])]; 316 | 317 | if (attack && attack != reference[i]) 318 | break; 319 | 320 | assert(reference[i]); 321 | 322 | attack = reference[i]; 323 | } 324 | } while (i < size); 325 | } 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /src/bitboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | 12 | Stockfish is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #ifndef BITBOARD_H_INCLUDED 22 | #define BITBOARD_H_INCLUDED 23 | 24 | #include "types.h" 25 | 26 | namespace Bitboards { 27 | 28 | void init(); 29 | const std::string pretty(Bitboard b); 30 | 31 | } 32 | 33 | namespace Bitbases { 34 | 35 | void init_kpk(); 36 | bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color us); 37 | 38 | } 39 | 40 | const Bitboard FileABB = 0x0101010101010101ULL; 41 | const Bitboard FileBBB = FileABB << 1; 42 | const Bitboard FileCBB = FileABB << 2; 43 | const Bitboard FileDBB = FileABB << 3; 44 | const Bitboard FileEBB = FileABB << 4; 45 | const Bitboard FileFBB = FileABB << 5; 46 | const Bitboard FileGBB = FileABB << 6; 47 | const Bitboard FileHBB = FileABB << 7; 48 | 49 | const Bitboard Rank1BB = 0xFF; 50 | const Bitboard Rank2BB = Rank1BB << (8 * 1); 51 | const Bitboard Rank3BB = Rank1BB << (8 * 2); 52 | const Bitboard Rank4BB = Rank1BB << (8 * 3); 53 | const Bitboard Rank5BB = Rank1BB << (8 * 4); 54 | const Bitboard Rank6BB = Rank1BB << (8 * 5); 55 | const Bitboard Rank7BB = Rank1BB << (8 * 6); 56 | const Bitboard Rank8BB = Rank1BB << (8 * 7); 57 | 58 | CACHE_LINE_ALIGNMENT 59 | 60 | extern Bitboard RMasks[SQUARE_NB]; 61 | extern Bitboard RMagics[SQUARE_NB]; 62 | extern Bitboard* RAttacks[SQUARE_NB]; 63 | extern unsigned RShifts[SQUARE_NB]; 64 | 65 | extern Bitboard BMasks[SQUARE_NB]; 66 | extern Bitboard BMagics[SQUARE_NB]; 67 | extern Bitboard* BAttacks[SQUARE_NB]; 68 | extern unsigned BShifts[SQUARE_NB]; 69 | 70 | extern Bitboard SquareBB[SQUARE_NB]; 71 | extern Bitboard FileBB[FILE_NB]; 72 | extern Bitboard RankBB[RANK_NB]; 73 | extern Bitboard AdjacentFilesBB[FILE_NB]; 74 | extern Bitboard InFrontBB[COLOR_NB][RANK_NB]; 75 | extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB]; 76 | extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; 77 | extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; 78 | extern Bitboard DistanceRingsBB[SQUARE_NB][8]; 79 | extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; 80 | extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; 81 | extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; 82 | extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; 83 | 84 | extern int SquareDistance[SQUARE_NB][SQUARE_NB]; 85 | 86 | const Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL; 87 | 88 | /// Overloads of bitwise operators between a Bitboard and a Square for testing 89 | /// whether a given bit is set in a bitboard, and for setting and clearing bits. 90 | 91 | inline Bitboard operator&(Bitboard b, Square s) { 92 | return b & SquareBB[s]; 93 | } 94 | 95 | inline Bitboard& operator|=(Bitboard& b, Square s) { 96 | return b |= SquareBB[s]; 97 | } 98 | 99 | inline Bitboard& operator^=(Bitboard& b, Square s) { 100 | return b ^= SquareBB[s]; 101 | } 102 | 103 | inline Bitboard operator|(Bitboard b, Square s) { 104 | return b | SquareBB[s]; 105 | } 106 | 107 | inline Bitboard operator^(Bitboard b, Square s) { 108 | return b ^ SquareBB[s]; 109 | } 110 | 111 | inline bool more_than_one(Bitboard b) { 112 | return b & (b - 1); 113 | } 114 | 115 | inline int square_distance(Square s1, Square s2) { 116 | return SquareDistance[s1][s2]; 117 | } 118 | 119 | inline int file_distance(Square s1, Square s2) { 120 | return abs(file_of(s1) - file_of(s2)); 121 | } 122 | 123 | inline int rank_distance(Square s1, Square s2) { 124 | return abs(rank_of(s1) - rank_of(s2)); 125 | } 126 | 127 | 128 | /// shift_bb() moves bitboard one step along direction Delta. Mainly for pawns. 129 | 130 | template 131 | inline Bitboard shift_bb(Bitboard b) { 132 | 133 | return Delta == DELTA_N ? b << 8 : Delta == DELTA_S ? b >> 8 134 | : Delta == DELTA_NE ? (b & ~FileHBB) << 9 : Delta == DELTA_SE ? (b & ~FileHBB) >> 7 135 | : Delta == DELTA_NW ? (b & ~FileABB) << 7 : Delta == DELTA_SW ? (b & ~FileABB) >> 9 136 | : 0; 137 | } 138 | 139 | 140 | /// rank_bb() and file_bb() take a file or a square as input and return 141 | /// a bitboard representing all squares on the given file or rank. 142 | 143 | inline Bitboard rank_bb(Rank r) { 144 | return RankBB[r]; 145 | } 146 | 147 | inline Bitboard rank_bb(Square s) { 148 | return RankBB[rank_of(s)]; 149 | } 150 | 151 | inline Bitboard file_bb(File f) { 152 | return FileBB[f]; 153 | } 154 | 155 | inline Bitboard file_bb(Square s) { 156 | return FileBB[file_of(s)]; 157 | } 158 | 159 | 160 | /// adjacent_files_bb() takes a file as input and returns a bitboard representing 161 | /// all squares on the adjacent files. 162 | 163 | inline Bitboard adjacent_files_bb(File f) { 164 | return AdjacentFilesBB[f]; 165 | } 166 | 167 | 168 | /// in_front_bb() takes a color and a rank as input, and returns a bitboard 169 | /// representing all the squares on all ranks in front of the rank, from the 170 | /// given color's point of view. For instance, in_front_bb(BLACK, RANK_3) will 171 | /// give all squares on ranks 1 and 2. 172 | 173 | inline Bitboard in_front_bb(Color c, Rank r) { 174 | return InFrontBB[c][r]; 175 | } 176 | 177 | 178 | /// between_bb() returns a bitboard representing all squares between two squares. 179 | /// For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with the bits for 180 | /// square d5 and e6 set. If s1 and s2 are not on the same rank, file or diagonal, 181 | /// 0 is returned. 182 | 183 | inline Bitboard between_bb(Square s1, Square s2) { 184 | return BetweenBB[s1][s2]; 185 | } 186 | 187 | 188 | /// forward_bb() takes a color and a square as input, and returns a bitboard 189 | /// representing all squares along the line in front of the square, from the 190 | /// point of view of the given color. Definition of the table is: 191 | /// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s) 192 | 193 | inline Bitboard forward_bb(Color c, Square s) { 194 | return ForwardBB[c][s]; 195 | } 196 | 197 | 198 | /// pawn_attack_span() takes a color and a square as input, and returns a bitboard 199 | /// representing all squares that can be attacked by a pawn of the given color 200 | /// when it moves along its file starting from the given square. Definition is: 201 | /// PawnAttackSpan[c][s] = in_front_bb(c, s) & adjacent_files_bb(s); 202 | 203 | inline Bitboard pawn_attack_span(Color c, Square s) { 204 | return PawnAttackSpan[c][s]; 205 | } 206 | 207 | 208 | /// passed_pawn_mask() takes a color and a square as input, and returns a 209 | /// bitboard mask which can be used to test if a pawn of the given color on 210 | /// the given square is a passed pawn. Definition of the table is: 211 | /// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_bb(c, s) 212 | 213 | inline Bitboard passed_pawn_mask(Color c, Square s) { 214 | return PassedPawnMask[c][s]; 215 | } 216 | 217 | 218 | /// squares_of_color() returns a bitboard representing all squares with the same 219 | /// color of the given square. 220 | 221 | inline Bitboard squares_of_color(Square s) { 222 | return DarkSquares & s ? DarkSquares : ~DarkSquares; 223 | } 224 | 225 | 226 | /// aligned() returns true if the squares s1, s2 and s3 are aligned 227 | /// either on a straight or on a diagonal line. 228 | 229 | inline bool aligned(Square s1, Square s2, Square s3) { 230 | return LineBB[s1][s2] & s3; 231 | } 232 | 233 | 234 | /// Functions for computing sliding attack bitboards. Function attacks_bb() takes 235 | /// a square and a bitboard of occupied squares as input, and returns a bitboard 236 | /// representing all squares attacked by Pt (bishop or rook) on the given square. 237 | template 238 | FORCE_INLINE unsigned magic_index(Square s, Bitboard occ) { 239 | 240 | Bitboard* const Masks = Pt == ROOK ? RMasks : BMasks; 241 | Bitboard* const Magics = Pt == ROOK ? RMagics : BMagics; 242 | unsigned* const Shifts = Pt == ROOK ? RShifts : BShifts; 243 | 244 | if (HasPext) 245 | return unsigned(_pext_u64(occ, Masks[s])); 246 | 247 | if (Is64Bit) 248 | return unsigned(((occ & Masks[s]) * Magics[s]) >> Shifts[s]); 249 | 250 | unsigned lo = unsigned(occ) & unsigned(Masks[s]); 251 | unsigned hi = unsigned(occ >> 32) & unsigned(Masks[s] >> 32); 252 | return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s]; 253 | } 254 | 255 | template 256 | inline Bitboard attacks_bb(Square s, Bitboard occ) { 257 | return (Pt == ROOK ? RAttacks : BAttacks)[s][magic_index(s, occ)]; 258 | } 259 | 260 | inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occ) { 261 | 262 | switch (type_of(pc)) 263 | { 264 | case BISHOP: return attacks_bb(s, occ); 265 | case ROOK : return attacks_bb(s, occ); 266 | case QUEEN : return attacks_bb(s, occ) | attacks_bb(s, occ); 267 | default : return StepAttacksBB[pc][s]; 268 | } 269 | } 270 | 271 | /// lsb()/msb() finds the least/most significant bit in a non-zero bitboard. 272 | /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard. 273 | 274 | #ifdef USE_BSFQ 275 | 276 | # if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 277 | 278 | FORCE_INLINE Square lsb(Bitboard b) { 279 | unsigned long idx; 280 | _BitScanForward64(&idx, b); 281 | return (Square) idx; 282 | } 283 | 284 | FORCE_INLINE Square msb(Bitboard b) { 285 | unsigned long idx; 286 | _BitScanReverse64(&idx, b); 287 | return (Square) idx; 288 | } 289 | 290 | # elif defined(__arm__) 291 | 292 | FORCE_INLINE int lsb32(uint32_t v) { 293 | __asm__("rbit %0, %1" : "=r"(v) : "r"(v)); 294 | return __builtin_clz(v); 295 | } 296 | 297 | FORCE_INLINE Square msb(Bitboard b) { 298 | return (Square) (63 - __builtin_clzll(b)); 299 | } 300 | 301 | FORCE_INLINE Square lsb(Bitboard b) { 302 | return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32))); 303 | } 304 | 305 | # else 306 | 307 | FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen 308 | Bitboard idx; 309 | __asm__("bsfq %1, %0": "=r"(idx): "rm"(b) ); 310 | return (Square) idx; 311 | } 312 | 313 | FORCE_INLINE Square msb(Bitboard b) { 314 | Bitboard idx; 315 | __asm__("bsrq %1, %0": "=r"(idx): "rm"(b) ); 316 | return (Square) idx; 317 | } 318 | 319 | # endif 320 | 321 | FORCE_INLINE Square pop_lsb(Bitboard* b) { 322 | const Square s = lsb(*b); 323 | *b &= *b - 1; 324 | return s; 325 | } 326 | 327 | #else // if defined(USE_BSFQ) 328 | 329 | extern Square msb(Bitboard b); 330 | extern Square lsb(Bitboard b); 331 | extern Square pop_lsb(Bitboard* b); 332 | 333 | #endif 334 | 335 | /// frontmost_sq() and backmost_sq() find the square corresponding to the 336 | /// most/least advanced bit relative to the given color. 337 | 338 | inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); } 339 | inline Square backmost_sq(Color c, Bitboard b) { return c == WHITE ? lsb(b) : msb(b); } 340 | 341 | #endif // #ifndef BITBOARD_H_INCLUDED 342 | -------------------------------------------------------------------------------- /src/bitcount.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | 12 | Stockfish is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #ifndef BITCOUNT_H_INCLUDED 22 | #define BITCOUNT_H_INCLUDED 23 | 24 | #include 25 | #include "types.h" 26 | 27 | enum BitCountType { 28 | CNT_64, 29 | CNT_64_MAX15, 30 | CNT_32, 31 | CNT_32_MAX15, 32 | CNT_HW_POPCNT 33 | }; 34 | 35 | /// Determine at compile time the best popcount<> specialization according to 36 | /// whether the platform is 32 or 64 bit, the maximum number of non-zero 37 | /// bits to count and if the hardware popcnt instruction is available. 38 | const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32; 39 | const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15; 40 | 41 | 42 | /// popcount() counts the number of non-zero bits in a bitboard 43 | template inline int popcount(Bitboard); 44 | 45 | template<> 46 | inline int popcount(Bitboard b) { 47 | b -= (b >> 1) & 0x5555555555555555ULL; 48 | b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); 49 | b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL; 50 | return (b * 0x0101010101010101ULL) >> 56; 51 | } 52 | 53 | template<> 54 | inline int popcount(Bitboard b) { 55 | b -= (b >> 1) & 0x5555555555555555ULL; 56 | b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); 57 | return (b * 0x1111111111111111ULL) >> 60; 58 | } 59 | 60 | template<> 61 | inline int popcount(Bitboard b) { 62 | unsigned w = unsigned(b >> 32), v = unsigned(b); 63 | v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits 64 | w -= (w >> 1) & 0x55555555; 65 | v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits 66 | w = ((w >> 2) & 0x33333333) + (w & 0x33333333); 67 | v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F; 68 | return (v * 0x01010101) >> 24; 69 | } 70 | 71 | template<> 72 | inline int popcount(Bitboard b) { 73 | unsigned w = unsigned(b >> 32), v = unsigned(b); 74 | v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits 75 | w -= (w >> 1) & 0x55555555; 76 | v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits 77 | w = ((w >> 2) & 0x33333333) + (w & 0x33333333); 78 | return ((v + w) * 0x11111111) >> 28; 79 | } 80 | 81 | template<> 82 | inline int popcount(Bitboard b) { 83 | 84 | #ifndef USE_POPCNT 85 | 86 | assert(false); 87 | return b != 0; // Avoid 'b not used' warning 88 | 89 | #elif defined(_MSC_VER) && defined(__INTEL_COMPILER) 90 | 91 | return _mm_popcnt_u64(b); 92 | 93 | #elif defined(_MSC_VER) 94 | 95 | return (int)__popcnt64(b); 96 | 97 | #else 98 | 99 | __asm__("popcnt %1, %0" : "=r" (b) : "r" (b)); 100 | return b; 101 | 102 | #endif 103 | } 104 | 105 | #endif // #ifndef BITCOUNT_H_INCLUDED 106 | -------------------------------------------------------------------------------- /src/book.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef BOOK_H_INCLUDED 21 | #define BOOK_H_INCLUDED 22 | 23 | #include "position.h" 24 | #include "rkiss.h" 25 | 26 | class PolyglotBook { 27 | public: 28 | PolyglotBook(); 29 | ~PolyglotBook(); 30 | Move probe(const Position& pos, const std::string& fName, bool pickBest); 31 | 32 | static void setBookData(unsigned char* pData, size_t size); 33 | 34 | private: 35 | template PolyglotBook& operator>>(T& n); 36 | 37 | bool open(const char* fName); 38 | size_t find_first(Key key); 39 | 40 | size_t position; 41 | static unsigned char* pBookData; 42 | static size_t bookSize; 43 | 44 | RKISS rkiss; 45 | }; 46 | 47 | #endif // #ifndef BOOK_H_INCLUDED 48 | -------------------------------------------------------------------------------- /src/endgame.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef ENDGAME_H_INCLUDED 21 | #define ENDGAME_H_INCLUDED 22 | 23 | #include 24 | #include 25 | 26 | #include "position.h" 27 | #include "types.h" 28 | 29 | 30 | /// EndgameType lists all supported endgames 31 | 32 | enum EndgameType { 33 | 34 | // Evaluation functions 35 | 36 | KNNK, // KNN vs K 37 | KXK, // Generic "mate lone king" eval 38 | KBNK, // KBN vs K 39 | KPK, // KP vs K 40 | KRKP, // KR vs KP 41 | KRKB, // KR vs KB 42 | KRKN, // KR vs KN 43 | KQKP, // KQ vs KP 44 | KQKR, // KQ vs KR 45 | 46 | 47 | // Scaling functions 48 | SCALE_FUNS, 49 | 50 | KBPsK, // KB and pawns vs K 51 | KQKRPs, // KQ vs KR and pawns 52 | KRPKR, // KRP vs KR 53 | KRPKB, // KRP vs KB 54 | KRPPKRP, // KRPP vs KRP 55 | KPsK, // K and pawns vs K 56 | KBPKB, // KBP vs KB 57 | KBPPKB, // KBPP vs KB 58 | KBPKN, // KBP vs KN 59 | KNPK, // KNP vs K 60 | KNPKB, // KNP vs KB 61 | KPKP // KP vs KP 62 | }; 63 | 64 | 65 | /// Endgame functions can be of two types depending on whether they return a 66 | /// Value or a ScaleFactor. Type eg_fun::type returns either ScaleFactor 67 | /// or Value depending on whether the template parameter is 0 or 1. 68 | 69 | template struct eg_fun { typedef Value type; }; 70 | template<> struct eg_fun<1> { typedef ScaleFactor type; }; 71 | 72 | 73 | /// Base and derived templates for endgame evaluation and scaling functions 74 | 75 | template 76 | struct EndgameBase { 77 | 78 | virtual ~EndgameBase() {} 79 | virtual Color color() const = 0; 80 | virtual T operator()(const Position&) const = 0; 81 | }; 82 | 83 | 84 | template SCALE_FUNS)>::type> 85 | struct Endgame : public EndgameBase { 86 | 87 | explicit Endgame(Color c) : strongSide(c), weakSide(~c) {} 88 | Color color() const { return strongSide; } 89 | T operator()(const Position&) const; 90 | 91 | private: 92 | const Color strongSide, weakSide; 93 | }; 94 | 95 | 96 | /// The Endgames class stores the pointers to endgame evaluation and scaling 97 | /// base objects in two std::map typedefs. We then use polymorphism to invoke 98 | /// the actual endgame function by calling its virtual operator(). 99 | 100 | class Endgames { 101 | 102 | typedef std::map::type>*> M1; 103 | typedef std::map::type>*> M2; 104 | 105 | M1 m1; 106 | M2 m2; 107 | 108 | M1& map(M1::mapped_type) { return m1; } 109 | M2& map(M2::mapped_type) { return m2; } 110 | 111 | template void add(const std::string& code); 112 | 113 | public: 114 | Endgames(); 115 | ~Endgames(); 116 | 117 | template T probe(Key key, T& eg) 118 | { return eg = map(eg).count(key) ? map(eg)[key] : NULL; } 119 | }; 120 | 121 | #endif // #ifndef ENDGAME_H_INCLUDED 122 | -------------------------------------------------------------------------------- /src/evaluate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef EVALUATE_H_INCLUDED 21 | #define EVALUATE_H_INCLUDED 22 | 23 | #include "types.h" 24 | 25 | class Position; 26 | 27 | namespace Eval { 28 | 29 | extern void init(); 30 | extern Value evaluate(const Position& pos); 31 | extern std::string trace(const Position& pos); 32 | 33 | } 34 | 35 | #endif // #ifndef EVALUATE_H_INCLUDED 36 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "book.h" 23 | #include "bitboard.h" 24 | #include "evaluate.h" 25 | #include "position.h" 26 | #include "search.h" 27 | #include "thread.h" 28 | #include "tt.h" 29 | #include "ucioption.h" 30 | 31 | extern "C" void init() { 32 | 33 | std::cout << engine_info() << std::endl; 34 | 35 | UCI::init(Options); 36 | Bitboards::init(); 37 | Position::init(); 38 | Bitbases::init_kpk(); 39 | Search::init(); 40 | Pawns::init(); 41 | Eval::init(); 42 | Threads.init(); 43 | TT.resize(Options["Hash"]); 44 | 45 | UCI::commandInit(); 46 | } 47 | 48 | int main(int argc, char* argv[]) { 49 | init(); 50 | 51 | std::string args; 52 | 53 | for (int i = 1; i < argc; ++i) 54 | args += std::string(argv[i]) + " "; 55 | 56 | if(!args.empty()) 57 | UCI::command(args); 58 | 59 | #ifndef EMSCRIPTEN 60 | std::string cmd; 61 | while(std::getline(std::cin, cmd)) 62 | UCI::command(cmd); 63 | #endif 64 | } 65 | 66 | extern "C" void uci_command(const char* cmd) { 67 | UCI::command(cmd); 68 | } 69 | 70 | extern "C" void set_book(unsigned char* pBookData, unsigned int size) { 71 | PolyglotBook::setBookData(pBookData, size); 72 | UCI::command("setoption name OwnBook value true"); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish is free, and distributed under the **GNU General Public License** 3 | (GPL). Essentially, this means that you are free to do almost exactly 4 | what you want with the program, including distributing it among your 5 | friends, making it available for download from your web site, selling 6 | it (either by itself or as part of some bigger software package), or 7 | using it as the starting point for a software project of your own. 8 | 9 | The only real limitation is that whenever you distribute Stockfish in 10 | some way, you must always include the full source code, or a pointer 11 | to where the source code can be found. If you make any changes to the 12 | source code, these changes must also be made available under the GPL. 13 | 14 | The source code for this emscripten port of stockfish can be found 15 | at http://github.com/exoticorn/stockfish-js 16 | */ 17 | (function() { 18 | if(typeof process == 'undefined') { 19 | var initialized = false; 20 | 21 | onmessage = function(event) { 22 | if(!initialized) { 23 | Module.ccall('init', 'number', [], []); 24 | initialized = true; 25 | } 26 | if(typeof event.data == 'object') { 27 | if(event.data.book) { 28 | var book = event.data.book; 29 | var byteArray = new Uint8Array(book); 30 | var buf = Module._malloc(book.byteLength); 31 | Module.HEAPU8.set(byteArray, buf); 32 | Module.ccall('set_book', 'number', ['number', 'number'], [buf, book.byteLength]); 33 | } 34 | } else { 35 | Module.ccall('uci_command', 'number', ['string'], [event.data]) 36 | } 37 | } 38 | 39 | console = { 40 | log: function(line) { 41 | postMessage(line); 42 | } 43 | } 44 | } else { 45 | process.stdin.resume(); 46 | var lines = null; 47 | var init = function() { 48 | if(lines === null) { 49 | Module.ccall('init', 'number', [], []); 50 | lines = ''; 51 | } 52 | }; 53 | process.nextTick(init); 54 | process.stdin.on('data', function(chunk) { 55 | init(); 56 | lines += chunk; 57 | var match; 58 | while(match = lines.match(/\r\n|\n\r|\n|\r/)) { 59 | var line = lines.slice(0, match.index); 60 | lines = lines.slice(match.index + match[0].length); 61 | Module.ccall('uci_command', 'number', ['string'], [line]); 62 | if(line == 'quit') { 63 | process.exit(); 64 | } 65 | } 66 | }); 67 | process.stdin.on('end', function() { 68 | process.exit(); 69 | }); 70 | 71 | } 72 | })(); 73 | -------------------------------------------------------------------------------- /src/material.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include // For std::min 21 | #include 22 | #include 23 | 24 | #include "material.h" 25 | 26 | using namespace std; 27 | 28 | namespace { 29 | 30 | // Polynomial material balance parameters 31 | 32 | // pair pawn knight bishop rook queen 33 | const int LinearCoefficients[6] = { 1852, -162, -1122, -183, 249, -154 }; 34 | 35 | const int QuadraticCoefficientsSameSide[][PIECE_TYPE_NB] = { 36 | // OUR PIECES 37 | // pair pawn knight bishop rook queen 38 | { 0 }, // Bishop pair 39 | { 39, 2 }, // Pawn 40 | { 35, 271, -4 }, // knight OUR PIECES 41 | { 0, 105, 4, 0 }, // Bishop 42 | { -27, -2, 46, 100, -141 }, // Rook 43 | {-177, 25, 129, 142, -137, 0 } // Queen 44 | }; 45 | 46 | const int QuadraticCoefficientsOppositeSide[][PIECE_TYPE_NB] = { 47 | // THEIR PIECES 48 | // pair pawn knight bishop rook queen 49 | { 0 }, // Bishop pair 50 | { 37, 0 }, // Pawn 51 | { 10, 62, 0 }, // Knight OUR PIECES 52 | { 57, 64, 39, 0 }, // Bishop 53 | { 50, 40, 23, -22, 0 }, // Rook 54 | { 98, 105, -39, 141, 274, 0 } // Queen 55 | }; 56 | 57 | // Endgame evaluation and scaling functions are accessed directly and not through 58 | // the function maps because they correspond to more than one material hash key. 59 | Endgame EvaluateKXK[] = { Endgame(WHITE), Endgame(BLACK) }; 60 | 61 | Endgame ScaleKBPsK[] = { Endgame(WHITE), Endgame(BLACK) }; 62 | Endgame ScaleKQKRPs[] = { Endgame(WHITE), Endgame(BLACK) }; 63 | Endgame ScaleKPsK[] = { Endgame(WHITE), Endgame(BLACK) }; 64 | Endgame ScaleKPKP[] = { Endgame(WHITE), Endgame(BLACK) }; 65 | 66 | // Helper templates used to detect a given material distribution 67 | template bool is_KXK(const Position& pos) { 68 | const Color Them = (Us == WHITE ? BLACK : WHITE); 69 | return !pos.count(Them) 70 | && pos.non_pawn_material(Them) == VALUE_ZERO 71 | && pos.non_pawn_material(Us) >= RookValueMg; 72 | } 73 | 74 | template bool is_KBPsKs(const Position& pos) { 75 | return pos.non_pawn_material(Us) == BishopValueMg 76 | && pos.count(Us) == 1 77 | && pos.count(Us) >= 1; 78 | } 79 | 80 | template bool is_KQKRPs(const Position& pos) { 81 | const Color Them = (Us == WHITE ? BLACK : WHITE); 82 | return !pos.count(Us) 83 | && pos.non_pawn_material(Us) == QueenValueMg 84 | && pos.count(Us) == 1 85 | && pos.count(Them) == 1 86 | && pos.count(Them) >= 1; 87 | } 88 | 89 | /// imbalance() calculates the imbalance by comparing the piece count of each 90 | /// piece type for both colors. 91 | 92 | template 93 | int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { 94 | 95 | const Color Them = (Us == WHITE ? BLACK : WHITE); 96 | 97 | int pt1, pt2, pc, v; 98 | int value = 0; 99 | 100 | // Second-degree polynomial material imbalance by Tord Romstad 101 | for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; ++pt1) 102 | { 103 | pc = pieceCount[Us][pt1]; 104 | if (!pc) 105 | continue; 106 | 107 | v = LinearCoefficients[pt1]; 108 | 109 | for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2) 110 | v += QuadraticCoefficientsSameSide[pt1][pt2] * pieceCount[Us][pt2] 111 | + QuadraticCoefficientsOppositeSide[pt1][pt2] * pieceCount[Them][pt2]; 112 | 113 | value += pc * v; 114 | } 115 | 116 | return value; 117 | } 118 | 119 | } // namespace 120 | 121 | namespace Material { 122 | 123 | /// Material::probe() takes a position object as input, looks up a MaterialEntry 124 | /// object, and returns a pointer to it. If the material configuration is not 125 | /// already present in the table, it is computed and stored there, so we don't 126 | /// have to recompute everything when the same material configuration occurs again. 127 | 128 | Entry* probe(const Position& pos, Table& entries, Endgames& endgames) { 129 | 130 | Key key = pos.material_key(); 131 | Entry* e = entries[key]; 132 | 133 | // If e->key matches the position's material hash key, it means that we 134 | // have analysed this material configuration before, and we can simply 135 | // return the information we found the last time instead of recomputing it. 136 | if (e->key == key) 137 | return e; 138 | 139 | std::memset(e, 0, sizeof(Entry)); 140 | e->key = key; 141 | e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL; 142 | e->gamePhase = game_phase(pos); 143 | 144 | // Let's look if we have a specialized evaluation function for this particular 145 | // material configuration. Firstly we look for a fixed configuration one, then 146 | // for a generic one if the previous search failed. 147 | if (endgames.probe(key, e->evaluationFunction)) 148 | return e; 149 | 150 | if (is_KXK(pos)) 151 | { 152 | e->evaluationFunction = &EvaluateKXK[WHITE]; 153 | return e; 154 | } 155 | 156 | if (is_KXK(pos)) 157 | { 158 | e->evaluationFunction = &EvaluateKXK[BLACK]; 159 | return e; 160 | } 161 | 162 | // OK, we didn't find any special evaluation function for the current 163 | // material configuration. Is there a suitable scaling function? 164 | // 165 | // We face problems when there are several conflicting applicable 166 | // scaling functions and we need to decide which one to use. 167 | EndgameBase* sf; 168 | 169 | if (endgames.probe(key, sf)) 170 | { 171 | e->scalingFunction[sf->color()] = sf; 172 | return e; 173 | } 174 | 175 | // Generic scaling functions that refer to more than one material 176 | // distribution. They should be probed after the specialized ones. 177 | // Note that these ones don't return after setting the function. 178 | if (is_KBPsKs(pos)) 179 | e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE]; 180 | 181 | if (is_KBPsKs(pos)) 182 | e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK]; 183 | 184 | if (is_KQKRPs(pos)) 185 | e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE]; 186 | 187 | else if (is_KQKRPs(pos)) 188 | e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK]; 189 | 190 | Value npm_w = pos.non_pawn_material(WHITE); 191 | Value npm_b = pos.non_pawn_material(BLACK); 192 | 193 | if (npm_w + npm_b == VALUE_ZERO && pos.pieces(PAWN)) 194 | { 195 | if (!pos.count(BLACK)) 196 | { 197 | assert(pos.count(WHITE) >= 2); 198 | e->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; 199 | } 200 | else if (!pos.count(WHITE)) 201 | { 202 | assert(pos.count(BLACK) >= 2); 203 | e->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; 204 | } 205 | else if (pos.count(WHITE) == 1 && pos.count(BLACK) == 1) 206 | { 207 | // This is a special case because we set scaling functions 208 | // for both colors instead of only one. 209 | e->scalingFunction[WHITE] = &ScaleKPKP[WHITE]; 210 | e->scalingFunction[BLACK] = &ScaleKPKP[BLACK]; 211 | } 212 | } 213 | 214 | // No pawns makes it difficult to win, even with a material advantage. This 215 | // catches some trivial draws like KK, KBK and KNK and gives a very drawish 216 | // scale factor for cases such as KRKBP and KmmKm (except for KBBKN). 217 | if (!pos.count(WHITE) && npm_w - npm_b <= BishopValueMg) 218 | e->factor[WHITE] = uint8_t(npm_w < RookValueMg ? SCALE_FACTOR_DRAW : npm_b <= BishopValueMg ? 4 : 12); 219 | 220 | if (!pos.count(BLACK) && npm_b - npm_w <= BishopValueMg) 221 | e->factor[BLACK] = uint8_t(npm_b < RookValueMg ? SCALE_FACTOR_DRAW : npm_w <= BishopValueMg ? 4 : 12); 222 | 223 | if (pos.count(WHITE) == 1 && npm_w - npm_b <= BishopValueMg) 224 | e->factor[WHITE] = (uint8_t) SCALE_FACTOR_ONEPAWN; 225 | 226 | if (pos.count(BLACK) == 1 && npm_b - npm_w <= BishopValueMg) 227 | e->factor[BLACK] = (uint8_t) SCALE_FACTOR_ONEPAWN; 228 | 229 | // Compute the space weight 230 | if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg) 231 | { 232 | int minorPieceCount = pos.count(WHITE) + pos.count(WHITE) 233 | + pos.count(BLACK) + pos.count(BLACK); 234 | 235 | e->spaceWeight = make_score(minorPieceCount * minorPieceCount, 0); 236 | } 237 | 238 | // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder 239 | // for the bishop pair "extended piece", which allows us to be more flexible 240 | // in defining bishop pair bonuses. 241 | const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = { 242 | { pos.count(WHITE) > 1, pos.count(WHITE), pos.count(WHITE), 243 | pos.count(WHITE) , pos.count(WHITE), pos.count(WHITE) }, 244 | { pos.count(BLACK) > 1, pos.count(BLACK), pos.count(BLACK), 245 | pos.count(BLACK) , pos.count(BLACK), pos.count(BLACK) } }; 246 | 247 | e->value = (int16_t)((imbalance(pieceCount) - imbalance(pieceCount)) / 16); 248 | return e; 249 | } 250 | 251 | 252 | /// Material::game_phase() calculates the phase given the current 253 | /// position. Because the phase is strictly a function of the material, it 254 | /// is stored in MaterialEntry. 255 | 256 | Phase game_phase(const Position& pos) { 257 | 258 | Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK); 259 | 260 | return npm >= MidgameLimit ? PHASE_MIDGAME 261 | : npm <= EndgameLimit ? PHASE_ENDGAME 262 | : Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit)); 263 | } 264 | 265 | } // namespace Material 266 | -------------------------------------------------------------------------------- /src/material.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef MATERIAL_H_INCLUDED 21 | #define MATERIAL_H_INCLUDED 22 | 23 | #include "endgame.h" 24 | #include "misc.h" 25 | #include "position.h" 26 | #include "types.h" 27 | 28 | namespace Material { 29 | 30 | /// Material::Entry contains various information about a material configuration. 31 | /// It contains a material balance evaluation, a function pointer to a special 32 | /// endgame evaluation function (which in most cases is NULL, meaning that the 33 | /// standard evaluation function will be used), and "scale factors". 34 | /// 35 | /// The scale factors are used to scale the evaluation score up or down. 36 | /// For instance, in KRB vs KR endgames, the score is scaled down by a factor 37 | /// of 4, which will result in scores of absolute value less than one pawn. 38 | 39 | struct Entry { 40 | 41 | Score material_value() const { return make_score(value, value); } 42 | Score space_weight() const { return spaceWeight; } 43 | Phase game_phase() const { return gamePhase; } 44 | bool specialized_eval_exists() const { return evaluationFunction != NULL; } 45 | Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); } 46 | 47 | // scale_factor takes a position and a color as input, and returns a scale factor 48 | // for the given color. We have to provide the position in addition to the color, 49 | // because the scale factor need not be a constant: It can also be a function 50 | // which should be applied to the position. For instance, in KBP vs K endgames, 51 | // a scaling function for draws with rook pawns and wrong-colored bishops. 52 | 53 | ScaleFactor scale_factor(const Position& pos, Color c) const { 54 | 55 | return !scalingFunction[c] || (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE 56 | ? ScaleFactor(factor[c]) : (*scalingFunction[c])(pos); 57 | } 58 | 59 | Key key; 60 | int16_t value; 61 | uint8_t factor[COLOR_NB]; 62 | EndgameBase* evaluationFunction; 63 | EndgameBase* scalingFunction[COLOR_NB]; 64 | Score spaceWeight; 65 | Phase gamePhase; 66 | }; 67 | 68 | typedef HashTable Table; 69 | 70 | Entry* probe(const Position& pos, Table& entries, Endgames& endgames); 71 | Phase game_phase(const Position& pos); 72 | 73 | } // namespace Material 74 | 75 | #endif // #ifndef MATERIAL_H_INCLUDED 76 | -------------------------------------------------------------------------------- /src/misc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "misc.h" 25 | #include "thread.h" 26 | 27 | using namespace std; 28 | 29 | /// Version number. If Version is left empty, then compile date in the format 30 | /// DD-MM-YY and show in engine_info. 31 | static const string Version = "5"; 32 | 33 | 34 | /// engine_info() returns the full name of the current Stockfish version. This 35 | /// will be either "Stockfish DD-MM-YY" (where DD-MM-YY is the date when 36 | /// the program was compiled) or "Stockfish ", depending on whether 37 | /// Version is empty. 38 | 39 | const string engine_info(bool to_uci) { 40 | 41 | const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); 42 | string month, day, year; 43 | stringstream ss, date(__DATE__); // From compiler, format is "Sep 21 2008" 44 | 45 | ss << "Stockfish " << Version << setfill('0'); 46 | 47 | if (Version.empty()) 48 | { 49 | date >> month >> day >> year; 50 | ss << setw(2) << day << setw(2) << (1 + months.find(month) / 4) << year.substr(2); 51 | } 52 | 53 | ss << (Is64Bit ? " 64" : "") 54 | << (HasPext ? " BMI2" : (HasPopCnt ? " SSE4.2" : "")) 55 | << (to_uci ? "\nid author ": " by ") 56 | << "Tord Romstad, Marco Costalba and Joona Kiiski"; 57 | 58 | return ss.str(); 59 | } 60 | 61 | 62 | /// Debug functions used mainly to collect run-time statistics 63 | 64 | static int64_t hits[2], means[2]; 65 | 66 | void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; } 67 | void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); } 68 | void dbg_mean_of(int v) { ++means[0]; means[1] += v; } 69 | 70 | void dbg_print() { 71 | 72 | if (hits[0]) 73 | cerr << "Total " << hits[0] << " Hits " << hits[1] 74 | << " hit rate (%) " << 100 * hits[1] / hits[0] << endl; 75 | 76 | if (means[0]) 77 | cerr << "Total " << means[0] << " Mean " 78 | << (double)means[1] / means[0] << endl; 79 | } 80 | 81 | 82 | /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and 83 | /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We 84 | /// can toggle the logging of std::cout and std:cin at runtime whilst preserving 85 | /// usual i/o functionality, all without changing a single line of code! 86 | /// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81 87 | 88 | struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout 89 | 90 | Tie(streambuf* b, ofstream* f) : buf(b), file(f) {} 91 | 92 | int sync() { return file->rdbuf()->pubsync(), buf->pubsync(); } 93 | int overflow(int c) { return log(buf->sputc((char)c), "<< "); } 94 | int underflow() { return buf->sgetc(); } 95 | int uflow() { return log(buf->sbumpc(), ">> "); } 96 | 97 | streambuf* buf; 98 | ofstream* file; 99 | 100 | int log(int c, const char* prefix) { 101 | 102 | static int last = '\n'; 103 | 104 | if (last == '\n') 105 | file->rdbuf()->sputn(prefix, 3); 106 | 107 | return last = file->rdbuf()->sputc((char)c); 108 | } 109 | }; 110 | 111 | class Logger { 112 | 113 | Logger() : in(cin.rdbuf(), &file), out(cout.rdbuf(), &file) {} 114 | ~Logger() { start(false); } 115 | 116 | ofstream file; 117 | Tie in, out; 118 | 119 | public: 120 | static void start(bool b) { 121 | 122 | static Logger l; 123 | 124 | if (b && !l.file.is_open()) 125 | { 126 | l.file.open("io_log.txt", ifstream::out | ifstream::app); 127 | cin.rdbuf(&l.in); 128 | cout.rdbuf(&l.out); 129 | } 130 | else if (!b && l.file.is_open()) 131 | { 132 | cout.rdbuf(l.out.buf); 133 | cin.rdbuf(l.in.buf); 134 | l.file.close(); 135 | } 136 | } 137 | }; 138 | 139 | 140 | /// Used to serialize access to std::cout to avoid multiple threads writing at 141 | /// the same time. 142 | 143 | std::ostream& operator<<(std::ostream& os, SyncCout sc) { 144 | 145 | static Mutex m; 146 | 147 | if (sc == IO_LOCK) 148 | m.lock(); 149 | 150 | if (sc == IO_UNLOCK) 151 | m.unlock(); 152 | 153 | return os; 154 | } 155 | 156 | 157 | /// Trampoline helper to avoid moving Logger to misc.h 158 | void start_logger(bool b) { Logger::start(b); } 159 | 160 | 161 | /// timed_wait() waits for msec milliseconds. It is mainly a helper to wrap 162 | /// the conversion from milliseconds to struct timespec, as used by pthreads. 163 | 164 | void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) { 165 | 166 | #ifdef _WIN32 167 | int tm = msec; 168 | #else 169 | timespec ts, *tm = &ts; 170 | uint64_t ms = Time::now() + msec; 171 | 172 | ts.tv_sec = ms / 1000; 173 | ts.tv_nsec = (ms % 1000) * 1000000LL; 174 | #endif 175 | 176 | cond_timedwait(sleepCond, sleepLock, tm); 177 | } 178 | 179 | 180 | /// prefetch() preloads the given address in L1/L2 cache. This is a non-blocking 181 | /// function that doesn't stall the CPU waiting for data to be loaded from memory, 182 | /// which can be quite slow. 183 | #ifdef NO_PREFETCH 184 | 185 | void prefetch(char*) {} 186 | 187 | #else 188 | 189 | void prefetch(char* addr) { 190 | 191 | # if defined(__INTEL_COMPILER) 192 | // This hack prevents prefetches from being optimized away by 193 | // Intel compiler. Both MSVC and gcc seem not be affected by this. 194 | __asm__ (""); 195 | # endif 196 | 197 | # if defined(__INTEL_COMPILER) || defined(_MSC_VER) 198 | _mm_prefetch(addr, _MM_HINT_T0); 199 | # else 200 | __builtin_prefetch(addr); 201 | # endif 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /src/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef MISC_H_INCLUDED 21 | #define MISC_H_INCLUDED 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "types.h" 28 | 29 | extern const std::string engine_info(bool to_uci = false); 30 | extern void timed_wait(WaitCondition&, Lock&, int); 31 | extern void prefetch(char* addr); 32 | extern void start_logger(bool b); 33 | 34 | extern void dbg_hit_on(bool b); 35 | extern void dbg_hit_on_c(bool c, bool b); 36 | extern void dbg_mean_of(int v); 37 | extern void dbg_print(); 38 | 39 | 40 | struct Log : public std::ofstream { 41 | Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {} 42 | ~Log() { if (is_open()) close(); } 43 | }; 44 | 45 | 46 | namespace Time { 47 | typedef int64_t point; 48 | inline point now() { return system_time_to_msec(); } 49 | } 50 | 51 | 52 | template 53 | struct HashTable { 54 | HashTable() : table(Size, Entry()) {} 55 | Entry* operator[](Key k) { return &table[(uint32_t)k & (Size - 1)]; } 56 | 57 | private: 58 | std::vector table; 59 | }; 60 | 61 | 62 | enum SyncCout { IO_LOCK, IO_UNLOCK }; 63 | std::ostream& operator<<(std::ostream&, SyncCout); 64 | 65 | #define sync_cout std::cout << IO_LOCK 66 | #define sync_endl std::endl << IO_UNLOCK 67 | 68 | #endif // #ifndef MISC_H_INCLUDED 69 | -------------------------------------------------------------------------------- /src/movegen.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef MOVEGEN_H_INCLUDED 21 | #define MOVEGEN_H_INCLUDED 22 | 23 | #include "types.h" 24 | 25 | enum GenType { 26 | CAPTURES, 27 | QUIETS, 28 | QUIET_CHECKS, 29 | EVASIONS, 30 | NON_EVASIONS, 31 | LEGAL 32 | }; 33 | 34 | class Position; 35 | 36 | template 37 | ExtMove* generate(const Position& pos, ExtMove* mlist); 38 | 39 | /// The MoveList struct is a simple wrapper around generate(). It sometimes comes 40 | /// in handy to use this class instead of the low level generate() function. 41 | template 42 | struct MoveList { 43 | 44 | explicit MoveList(const Position& pos) : cur(mlist), last(generate(pos, mlist)) { last->move = MOVE_NONE; } 45 | void operator++() { ++cur; } 46 | Move operator*() const { return cur->move; } 47 | size_t size() const { return last - mlist; } 48 | bool contains(Move m) const { 49 | for (const ExtMove* it(mlist); it != last; ++it) if (it->move == m) return true; 50 | return false; 51 | } 52 | 53 | private: 54 | ExtMove mlist[MAX_MOVES]; 55 | ExtMove *cur, *last; 56 | }; 57 | 58 | #endif // #ifndef MOVEGEN_H_INCLUDED 59 | -------------------------------------------------------------------------------- /src/movepick.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | 12 | Stockfish is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include "movepick.h" 24 | #include "thread.h" 25 | 26 | namespace { 27 | 28 | enum Stages { 29 | MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1, 30 | EVASION, EVASIONS_S2, 31 | QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3, 32 | QSEARCH_1, CAPTURES_S4, 33 | PROBCUT, CAPTURES_S5, 34 | RECAPTURE, CAPTURES_S6, 35 | STOP 36 | }; 37 | 38 | // Our insertion sort, which is guaranteed (and also needed) to be stable 39 | void insertion_sort(ExtMove* begin, ExtMove* end) 40 | { 41 | ExtMove tmp, *p, *q; 42 | 43 | for (p = begin + 1; p < end; ++p) 44 | { 45 | tmp = *p; 46 | for (q = p; q != begin && *(q-1) < tmp; --q) 47 | *q = *(q-1); 48 | *q = tmp; 49 | } 50 | } 51 | 52 | // Unary predicate used by std::partition to split positive values from remaining 53 | // ones so as to sort the two sets separately, with the second sort delayed. 54 | inline bool has_positive_value(const ExtMove& ms) { return ms.value > 0; } 55 | 56 | // Picks the best move in the range (begin, end) and moves it to the front. 57 | // It's faster than sorting all the moves in advance when there are few 58 | // moves e.g. possible captures. 59 | inline ExtMove* pick_best(ExtMove* begin, ExtMove* end) 60 | { 61 | std::swap(*begin, *std::max_element(begin, end)); 62 | return begin; 63 | } 64 | } 65 | 66 | 67 | /// Constructors of the MovePicker class. As arguments we pass information 68 | /// to help it to return the (presumably) good moves first, to decide which 69 | /// moves to return (in the quiescence search, for instance, we only want to 70 | /// search captures, promotions and some checks) and how important good move 71 | /// ordering is at the current node. 72 | 73 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h, 74 | Move* cm, Move* fm, Search::Stack* s) : pos(p), history(h), depth(d) { 75 | 76 | assert(d > DEPTH_ZERO); 77 | 78 | cur = end = moves; 79 | endBadCaptures = moves + MAX_MOVES - 1; 80 | countermoves = cm; 81 | followupmoves = fm; 82 | ss = s; 83 | 84 | if (pos.checkers()) 85 | stage = EVASION; 86 | 87 | else 88 | stage = MAIN_SEARCH; 89 | 90 | ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE); 91 | end += (ttMove != MOVE_NONE); 92 | } 93 | 94 | MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const HistoryStats& h, 95 | Square s) : pos(p), history(h), cur(moves), end(moves) { 96 | 97 | assert(d <= DEPTH_ZERO); 98 | 99 | if (pos.checkers()) 100 | stage = EVASION; 101 | 102 | else if (d > DEPTH_QS_NO_CHECKS) 103 | stage = QSEARCH_0; 104 | 105 | else if (d > DEPTH_QS_RECAPTURES) 106 | { 107 | stage = QSEARCH_1; 108 | 109 | // Skip TT move if is not a capture or a promotion. This avoids qsearch 110 | // tree explosion due to a possible perpetual check or similar rare cases 111 | // when TT table is full. 112 | if (ttm && !pos.capture_or_promotion(ttm)) 113 | ttm = MOVE_NONE; 114 | } 115 | else 116 | { 117 | stage = RECAPTURE; 118 | recaptureSquare = s; 119 | ttm = MOVE_NONE; 120 | } 121 | 122 | ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE); 123 | end += (ttMove != MOVE_NONE); 124 | } 125 | 126 | MovePicker::MovePicker(const Position& p, Move ttm, const HistoryStats& h, PieceType pt) 127 | : pos(p), history(h), cur(moves), end(moves) { 128 | 129 | assert(!pos.checkers()); 130 | 131 | stage = PROBCUT; 132 | 133 | // In ProbCut we generate only captures that are better than the parent's 134 | // captured piece. 135 | captureThreshold = PieceValue[MG][pt]; 136 | ttMove = (ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE); 137 | 138 | if (ttMove && (!pos.capture(ttMove) || pos.see(ttMove) <= captureThreshold)) 139 | ttMove = MOVE_NONE; 140 | 141 | end += (ttMove != MOVE_NONE); 142 | } 143 | 144 | 145 | /// score() assign a numerical value to each move in a move list. The moves with 146 | /// highest values will be picked first. 147 | template<> 148 | void MovePicker::score() { 149 | // Winning and equal captures in the main search are ordered by MVV/LVA. 150 | // Suprisingly, this appears to perform slightly better than SEE based 151 | // move ordering. The reason is probably that in a position with a winning 152 | // capture, capturing a more valuable (but sufficiently defended) piece 153 | // first usually doesn't hurt. The opponent will have to recapture, and 154 | // the hanging piece will still be hanging (except in the unusual cases 155 | // where it is possible to recapture with the hanging piece). Exchanging 156 | // big pieces before capturing a hanging piece probably helps to reduce 157 | // the subtree size. 158 | // In main search we want to push captures with negative SEE values to the 159 | // badCaptures[] array, but instead of doing it now we delay until the move 160 | // has been picked up in pick_move_from_list(). This way we save some SEE 161 | // calls in case we get a cutoff. 162 | Move m; 163 | 164 | for (ExtMove* it = moves; it != end; ++it) 165 | { 166 | m = it->move; 167 | it->value = PieceValue[MG][pos.piece_on(to_sq(m))] 168 | - Value(type_of(pos.moved_piece(m))); 169 | 170 | if (type_of(m) == ENPASSANT) 171 | it->value += PieceValue[MG][PAWN]; 172 | 173 | else if (type_of(m) == PROMOTION) 174 | it->value += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN]; 175 | } 176 | } 177 | 178 | template<> 179 | void MovePicker::score() { 180 | 181 | Move m; 182 | 183 | for (ExtMove* it = moves; it != end; ++it) 184 | { 185 | m = it->move; 186 | it->value = history[pos.moved_piece(m)][to_sq(m)]; 187 | } 188 | } 189 | 190 | template<> 191 | void MovePicker::score() { 192 | // Try good captures ordered by MVV/LVA, then non-captures if destination square 193 | // is not under attack, ordered by history value, then bad-captures and quiet 194 | // moves with a negative SEE. This last group is ordered by the SEE value. 195 | Move m; 196 | Value see; 197 | 198 | for (ExtMove* it = moves; it != end; ++it) 199 | { 200 | m = it->move; 201 | if ((see = pos.see_sign(m)) < VALUE_ZERO) 202 | it->value = see - HistoryStats::Max; // At the bottom 203 | 204 | else if (pos.capture(m)) 205 | it->value = PieceValue[MG][pos.piece_on(to_sq(m))] 206 | - Value(type_of(pos.moved_piece(m))) + HistoryStats::Max; 207 | else 208 | it->value = history[pos.moved_piece(m)][to_sq(m)]; 209 | } 210 | } 211 | 212 | 213 | /// generate_next_stage() generates, scores and sorts the next bunch of moves, 214 | /// when there are no more moves to try for the current stage. 215 | 216 | void MovePicker::generate_next_stage() { 217 | 218 | cur = moves; 219 | 220 | switch (++stage) { 221 | 222 | case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6: 223 | end = generate(pos, moves); 224 | score(); 225 | return; 226 | 227 | case KILLERS_S1: 228 | cur = killers; 229 | end = cur + 2; 230 | 231 | killers[0].move = ss->killers[0]; 232 | killers[1].move = ss->killers[1]; 233 | killers[2].move = killers[3].move = MOVE_NONE; 234 | killers[4].move = killers[5].move = MOVE_NONE; 235 | 236 | // Please note that following code is racy and could yield to rare (less 237 | // than 1 out of a million) duplicated entries in SMP case. This is harmless. 238 | 239 | // Be sure countermoves are different from killers 240 | for (int i = 0; i < 2; ++i) 241 | if ( countermoves[i] != (cur+0)->move 242 | && countermoves[i] != (cur+1)->move) 243 | (end++)->move = countermoves[i]; 244 | 245 | // Be sure followupmoves are different from killers and countermoves 246 | for (int i = 0; i < 2; ++i) 247 | if ( followupmoves[i] != (cur+0)->move 248 | && followupmoves[i] != (cur+1)->move 249 | && followupmoves[i] != (cur+2)->move 250 | && followupmoves[i] != (cur+3)->move) 251 | (end++)->move = followupmoves[i]; 252 | return; 253 | 254 | case QUIETS_1_S1: 255 | endQuiets = end = generate(pos, moves); 256 | score(); 257 | end = std::partition(cur, end, has_positive_value); 258 | insertion_sort(cur, end); 259 | return; 260 | 261 | case QUIETS_2_S1: 262 | cur = end; 263 | end = endQuiets; 264 | if (depth >= 3 * ONE_PLY) 265 | insertion_sort(cur, end); 266 | return; 267 | 268 | case BAD_CAPTURES_S1: 269 | // Just pick them in reverse order to get MVV/LVA ordering 270 | cur = moves + MAX_MOVES - 1; 271 | end = endBadCaptures; 272 | return; 273 | 274 | case EVASIONS_S2: 275 | end = generate(pos, moves); 276 | if (end > moves + 1) 277 | score(); 278 | return; 279 | 280 | case QUIET_CHECKS_S3: 281 | end = generate(pos, moves); 282 | return; 283 | 284 | case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE: 285 | stage = STOP; 286 | /* Fall through */ 287 | 288 | case STOP: 289 | end = cur + 1; // Avoid another next_phase() call 290 | return; 291 | 292 | default: 293 | assert(false); 294 | } 295 | } 296 | 297 | 298 | /// next_move() is the most important method of the MovePicker class. It returns 299 | /// a new pseudo legal move every time it is called, until there are no more moves 300 | /// left. It picks the move with the biggest value from a list of generated moves 301 | /// taking care not to return the ttMove if it has already been searched. 302 | template<> 303 | Move MovePicker::next_move() { 304 | 305 | Move move; 306 | 307 | while (true) 308 | { 309 | while (cur == end) 310 | generate_next_stage(); 311 | 312 | switch (stage) { 313 | 314 | case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: 315 | ++cur; 316 | return ttMove; 317 | 318 | case CAPTURES_S1: 319 | move = pick_best(cur++, end)->move; 320 | if (move != ttMove) 321 | { 322 | if (pos.see_sign(move) >= VALUE_ZERO) 323 | return move; 324 | 325 | // Losing capture, move it to the tail of the array 326 | (endBadCaptures--)->move = move; 327 | } 328 | break; 329 | 330 | case KILLERS_S1: 331 | move = (cur++)->move; 332 | if ( move != MOVE_NONE 333 | && move != ttMove 334 | && pos.pseudo_legal(move) 335 | && !pos.capture(move)) 336 | return move; 337 | break; 338 | 339 | case QUIETS_1_S1: case QUIETS_2_S1: 340 | move = (cur++)->move; 341 | if ( move != ttMove 342 | && move != killers[0].move 343 | && move != killers[1].move 344 | && move != killers[2].move 345 | && move != killers[3].move 346 | && move != killers[4].move 347 | && move != killers[5].move) 348 | return move; 349 | break; 350 | 351 | case BAD_CAPTURES_S1: 352 | return (cur--)->move; 353 | 354 | case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4: 355 | move = pick_best(cur++, end)->move; 356 | if (move != ttMove) 357 | return move; 358 | break; 359 | 360 | case CAPTURES_S5: 361 | move = pick_best(cur++, end)->move; 362 | if (move != ttMove && pos.see(move) > captureThreshold) 363 | return move; 364 | break; 365 | 366 | case CAPTURES_S6: 367 | move = pick_best(cur++, end)->move; 368 | if (to_sq(move) == recaptureSquare) 369 | return move; 370 | break; 371 | 372 | case QUIET_CHECKS_S3: 373 | move = (cur++)->move; 374 | if (move != ttMove) 375 | return move; 376 | break; 377 | 378 | case STOP: 379 | return MOVE_NONE; 380 | 381 | default: 382 | assert(false); 383 | } 384 | } 385 | } 386 | 387 | 388 | /// Version of next_move() to use at split point nodes where the move is grabbed 389 | /// from the split point's shared MovePicker object. This function is not thread 390 | /// safe so must be lock protected by the caller. 391 | template<> 392 | Move MovePicker::next_move() { return ss->splitPoint->movePicker->next_move(); } 393 | -------------------------------------------------------------------------------- /src/movepick.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef MOVEPICK_H_INCLUDED 21 | #define MOVEPICK_H_INCLUDED 22 | 23 | #include // For std::max 24 | #include // For std::memset 25 | 26 | #include "movegen.h" 27 | #include "position.h" 28 | #include "search.h" 29 | #include "types.h" 30 | 31 | 32 | /// The Stats struct stores moves statistics. According to the template parameter 33 | /// the class can store History, Gains and Countermoves. History records how often 34 | /// different moves have been successful or unsuccessful during the current search 35 | /// and is used for reduction and move ordering decisions. Gains records the move's 36 | /// best evaluation gain from one ply to the next and is used for pruning decisions. 37 | /// Countermoves store the move that refute a previous one. Entries are stored 38 | /// using only the moving piece and destination square, hence two moves with 39 | /// different origin but same destination and piece will be considered identical. 40 | template 41 | struct Stats { 42 | 43 | static const Value Max = Value(2000); 44 | 45 | const T* operator[](Piece pc) const { return table[pc]; } 46 | void clear() { std::memset(table, 0, sizeof(table)); } 47 | 48 | void update(Piece pc, Square to, Move m) { 49 | 50 | if (m == table[pc][to].first) 51 | return; 52 | 53 | table[pc][to].second = table[pc][to].first; 54 | table[pc][to].first = m; 55 | } 56 | 57 | void update(Piece pc, Square to, Value v) { 58 | 59 | if (Gain) 60 | table[pc][to] = std::max(v, table[pc][to] - 1); 61 | 62 | else if (abs(table[pc][to] + v) < Max) 63 | table[pc][to] += v; 64 | } 65 | 66 | private: 67 | T table[PIECE_NB][SQUARE_NB]; 68 | }; 69 | 70 | typedef Stats< true, Value> GainsStats; 71 | typedef Stats HistoryStats; 72 | typedef Stats > MovesStats; 73 | 74 | 75 | /// MovePicker class is used to pick one pseudo legal move at a time from the 76 | /// current position. The most important method is next_move(), which returns a 77 | /// new pseudo legal move each time it is called, until there are no moves left, 78 | /// when MOVE_NONE is returned. In order to improve the efficiency of the alpha 79 | /// beta algorithm, MovePicker attempts to return the moves which are most likely 80 | /// to get a cut-off first. 81 | 82 | class MovePicker { 83 | 84 | MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC 85 | 86 | public: 87 | MovePicker(const Position&, Move, Depth, const HistoryStats&, Square); 88 | MovePicker(const Position&, Move, const HistoryStats&, PieceType); 89 | MovePicker(const Position&, Move, Depth, const HistoryStats&, Move*, Move*, Search::Stack*); 90 | 91 | template Move next_move(); 92 | 93 | private: 94 | template void score(); 95 | void generate_next_stage(); 96 | 97 | const Position& pos; 98 | const HistoryStats& history; 99 | Search::Stack* ss; 100 | Move* countermoves; 101 | Move* followupmoves; 102 | Depth depth; 103 | Move ttMove; 104 | ExtMove killers[6]; 105 | Square recaptureSquare; 106 | Value captureThreshold; 107 | int stage; 108 | ExtMove *cur, *end, *endQuiets, *endBadCaptures; 109 | ExtMove moves[MAX_MOVES]; 110 | }; 111 | 112 | #endif // #ifndef MOVEPICK_H_INCLUDED 113 | -------------------------------------------------------------------------------- /src/notation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "movegen.h" 26 | #include "notation.h" 27 | #include "position.h" 28 | 29 | using namespace std; 30 | 31 | static const char* PieceToChar[COLOR_NB] = { " PNBRQK", " pnbrqk" }; 32 | 33 | 34 | /// score_to_uci() converts a value to a string suitable for use with the UCI 35 | /// protocol specifications: 36 | /// 37 | /// cp The score from the engine's point of view in centipawns. 38 | /// mate Mate in y moves, not plies. If the engine is getting mated 39 | /// use negative values for y. 40 | 41 | string score_to_uci(Value v, Value alpha, Value beta) { 42 | 43 | stringstream ss; 44 | 45 | if (abs(v) < VALUE_MATE_IN_MAX_PLY) 46 | ss << "cp " << v * 100 / PawnValueEg; 47 | else 48 | ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; 49 | 50 | ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); 51 | 52 | return ss.str(); 53 | } 54 | 55 | 56 | /// move_to_uci() converts a move to a string in coordinate notation 57 | /// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print 58 | /// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960 59 | /// mode. Internally castling moves are always encoded as "king captures rook". 60 | 61 | const string move_to_uci(Move m, bool chess960) { 62 | 63 | Square from = from_sq(m); 64 | Square to = to_sq(m); 65 | 66 | if (m == MOVE_NONE) 67 | return "(none)"; 68 | 69 | if (m == MOVE_NULL) 70 | return "0000"; 71 | 72 | if (type_of(m) == CASTLING && !chess960) 73 | to = make_square(to > from ? FILE_G : FILE_C, rank_of(from)); 74 | 75 | string move = to_string(from) + to_string(to); 76 | 77 | if (type_of(m) == PROMOTION) 78 | move += PieceToChar[BLACK][promotion_type(m)]; // Lower case 79 | 80 | return move; 81 | } 82 | 83 | 84 | /// move_from_uci() takes a position and a string representing a move in 85 | /// simple coordinate notation and returns an equivalent legal Move if any. 86 | 87 | Move move_from_uci(const Position& pos, string& str) { 88 | 89 | if (str.length() == 5) // Junior could send promotion piece in uppercase 90 | str[4] = char(tolower(str[4])); 91 | 92 | for (MoveList it(pos); *it; ++it) 93 | if (str == move_to_uci(*it, pos.is_chess960())) 94 | return *it; 95 | 96 | return MOVE_NONE; 97 | } 98 | 99 | 100 | /// move_to_san() takes a position and a legal Move as input and returns its 101 | /// short algebraic notation representation. 102 | 103 | const string move_to_san(Position& pos, Move m) { 104 | 105 | if (m == MOVE_NONE) 106 | return "(none)"; 107 | 108 | if (m == MOVE_NULL) 109 | return "(null)"; 110 | 111 | assert(MoveList(pos).contains(m)); 112 | 113 | Bitboard others, b; 114 | string san; 115 | Color us = pos.side_to_move(); 116 | Square from = from_sq(m); 117 | Square to = to_sq(m); 118 | Piece pc = pos.piece_on(from); 119 | PieceType pt = type_of(pc); 120 | 121 | if (type_of(m) == CASTLING) 122 | san = to > from ? "O-O" : "O-O-O"; 123 | else 124 | { 125 | if (pt != PAWN) 126 | { 127 | san = PieceToChar[WHITE][pt]; // Upper case 128 | 129 | // A disambiguation occurs if we have more then one piece of type 'pt' 130 | // that can reach 'to' with a legal move. 131 | others = b = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from; 132 | 133 | while (b) 134 | { 135 | Square s = pop_lsb(&b); 136 | if (!pos.legal(make_move(s, to), pos.pinned_pieces(us))) 137 | others ^= s; 138 | } 139 | 140 | if (!others) 141 | { /* Disambiguation is not needed */ } 142 | 143 | else if (!(others & file_bb(from))) 144 | san += to_char(file_of(from)); 145 | 146 | else if (!(others & rank_bb(from))) 147 | san += to_char(rank_of(from)); 148 | 149 | else 150 | san += to_string(from); 151 | } 152 | else if (pos.capture(m)) 153 | san = to_char(file_of(from)); 154 | 155 | if (pos.capture(m)) 156 | san += 'x'; 157 | 158 | san += to_string(to); 159 | 160 | if (type_of(m) == PROMOTION) 161 | san += string("=") + PieceToChar[WHITE][promotion_type(m)]; 162 | } 163 | 164 | if (pos.gives_check(m, CheckInfo(pos))) 165 | { 166 | StateInfo st; 167 | pos.do_move(m, st); 168 | san += MoveList(pos).size() ? "+" : "#"; 169 | pos.undo_move(m); 170 | } 171 | 172 | return san; 173 | } 174 | 175 | 176 | /// pretty_pv() formats human-readable search information, typically to be 177 | /// appended to the search log file. It uses the two helpers below to pretty 178 | /// format the time and score respectively. 179 | 180 | static string format(int64_t msecs) { 181 | 182 | const int MSecMinute = 1000 * 60; 183 | const int MSecHour = 1000 * 60 * 60; 184 | 185 | int64_t hours = msecs / MSecHour; 186 | int64_t minutes = (msecs % MSecHour) / MSecMinute; 187 | int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000; 188 | 189 | stringstream ss; 190 | 191 | if (hours) 192 | ss << hours << ':'; 193 | 194 | ss << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds; 195 | 196 | return ss.str(); 197 | } 198 | 199 | static string format(Value v) { 200 | 201 | stringstream ss; 202 | 203 | if (v >= VALUE_MATE_IN_MAX_PLY) 204 | ss << "#" << (VALUE_MATE - v + 1) / 2; 205 | 206 | else if (v <= VALUE_MATED_IN_MAX_PLY) 207 | ss << "-#" << (VALUE_MATE + v) / 2; 208 | 209 | else 210 | ss << setprecision(2) << fixed << showpos << double(v) / PawnValueEg; 211 | 212 | return ss.str(); 213 | } 214 | 215 | string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) { 216 | 217 | const uint64_t K = 1000; 218 | const uint64_t M = 1000000; 219 | 220 | std::stack st; 221 | Move* m = pv; 222 | string san, str, padding; 223 | stringstream ss; 224 | 225 | ss << setw(2) << depth << setw(8) << format(value) << setw(8) << format(msecs); 226 | 227 | if (pos.nodes_searched() < M) 228 | ss << setw(8) << pos.nodes_searched() / 1 << " "; 229 | 230 | else if (pos.nodes_searched() < K * M) 231 | ss << setw(7) << pos.nodes_searched() / K << "K "; 232 | 233 | else 234 | ss << setw(7) << pos.nodes_searched() / M << "M "; 235 | 236 | str = ss.str(); 237 | padding = string(str.length(), ' '); 238 | 239 | while (*m != MOVE_NONE) 240 | { 241 | san = move_to_san(pos, *m) + ' '; 242 | 243 | if ((str.length() + san.length()) % 80 <= san.length()) // Exceed 80 cols 244 | str += "\n" + padding; 245 | 246 | str += san; 247 | 248 | st.push(StateInfo()); 249 | pos.do_move(*m++, st.top()); 250 | } 251 | 252 | while (m != pv) 253 | pos.undo_move(*--m); 254 | 255 | return str; 256 | } 257 | -------------------------------------------------------------------------------- /src/notation.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef NOTATION_H_INCLUDED 21 | #define NOTATION_H_INCLUDED 22 | 23 | #include 24 | 25 | #include "types.h" 26 | 27 | class Position; 28 | 29 | std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE); 30 | Move move_from_uci(const Position& pos, std::string& str); 31 | const std::string move_to_uci(Move m, bool chess960); 32 | const std::string move_to_san(Position& pos, Move m); 33 | std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]); 34 | 35 | #endif // #ifndef NOTATION_H_INCLUDED 36 | -------------------------------------------------------------------------------- /src/pawns.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "bitboard.h" 24 | #include "bitcount.h" 25 | #include "pawns.h" 26 | #include "position.h" 27 | 28 | namespace { 29 | 30 | #define V Value 31 | #define S(mg, eg) make_score(mg, eg) 32 | 33 | // Doubled pawn penalty by file 34 | const Score Doubled[FILE_NB] = { 35 | S(13, 43), S(20, 48), S(23, 48), S(23, 48), 36 | S(23, 48), S(23, 48), S(20, 48), S(13, 43) }; 37 | 38 | // Isolated pawn penalty by opposed flag and file 39 | const Score Isolated[2][FILE_NB] = { 40 | { S(37, 45), S(54, 52), S(60, 52), S(60, 52), 41 | S(60, 52), S(60, 52), S(54, 52), S(37, 45) }, 42 | { S(25, 30), S(36, 35), S(40, 35), S(40, 35), 43 | S(40, 35), S(40, 35), S(36, 35), S(25, 30) } }; 44 | 45 | // Backward pawn penalty by opposed flag and file 46 | const Score Backward[2][FILE_NB] = { 47 | { S(30, 42), S(43, 46), S(49, 46), S(49, 46), 48 | S(49, 46), S(49, 46), S(43, 46), S(30, 42) }, 49 | { S(20, 28), S(29, 31), S(33, 31), S(33, 31), 50 | S(33, 31), S(33, 31), S(29, 31), S(20, 28) } }; 51 | 52 | // Connected pawn bonus by file and rank (initialized by formula) 53 | Score Connected[FILE_NB][RANK_NB]; 54 | 55 | // Candidate passed pawn bonus by rank 56 | const Score CandidatePassed[RANK_NB] = { 57 | S( 0, 0), S( 6, 13), S(6,13), S(14,29), 58 | S(34,68), S(83,166), S(0, 0), S( 0, 0) }; 59 | 60 | // Bonus for file distance of the two outermost pawns 61 | const Score PawnsFileSpan = S(0, 15); 62 | 63 | // Unsupported pawn penalty 64 | const Score UnsupportedPawnPenalty = S(20, 10); 65 | 66 | // Weakness of our pawn shelter in front of the king indexed by [rank] 67 | const Value ShelterWeakness[RANK_NB] = 68 | { V(100), V(0), V(27), V(73), V(92), V(101), V(101) }; 69 | 70 | // Danger of enemy pawns moving toward our king indexed by 71 | // [no friendly pawn | pawn unblocked | pawn blocked][rank of enemy pawn] 72 | const Value StormDanger[3][RANK_NB] = { 73 | { V( 0), V(64), V(128), V(51), V(26) }, 74 | { V(26), V(32), V( 96), V(38), V(20) }, 75 | { V( 0), V( 0), V(160), V(25), V(13) } }; 76 | 77 | // Max bonus for king safety. Corresponds to start position with all the pawns 78 | // in front of the king and no enemy pawn on the horizon. 79 | const Value MaxSafetyBonus = V(263); 80 | 81 | #undef S 82 | #undef V 83 | 84 | template 85 | Score evaluate(const Position& pos, Pawns::Entry* e) { 86 | 87 | const Color Them = (Us == WHITE ? BLACK : WHITE); 88 | const Square Up = (Us == WHITE ? DELTA_N : DELTA_S); 89 | const Square Right = (Us == WHITE ? DELTA_NE : DELTA_SW); 90 | const Square Left = (Us == WHITE ? DELTA_NW : DELTA_SE); 91 | 92 | Bitboard b, p, doubled; 93 | Square s; 94 | File f; 95 | bool passed, isolated, opposed, connected, backward, candidate, unsupported; 96 | Score value = SCORE_ZERO; 97 | const Square* pl = pos.list(Us); 98 | 99 | Bitboard ourPawns = pos.pieces(Us, PAWN); 100 | Bitboard theirPawns = pos.pieces(Them, PAWN); 101 | 102 | e->passedPawns[Us] = e->candidatePawns[Us] = 0; 103 | e->kingSquares[Us] = SQ_NONE; 104 | e->semiopenFiles[Us] = 0xFF; 105 | e->pawnAttacks[Us] = shift_bb(ourPawns) | shift_bb(ourPawns); 106 | e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); 107 | e->pawnsOnSquares[Us][WHITE] = pos.count(Us) - e->pawnsOnSquares[Us][BLACK]; 108 | 109 | // Loop through all pawns of the current color and score each pawn 110 | while ((s = *pl++) != SQ_NONE) 111 | { 112 | assert(pos.piece_on(s) == make_piece(Us, PAWN)); 113 | 114 | f = file_of(s); 115 | 116 | // This file cannot be semi-open 117 | e->semiopenFiles[Us] &= ~(1 << f); 118 | 119 | // Previous rank 120 | p = rank_bb(s - pawn_push(Us)); 121 | 122 | // Our rank plus previous one 123 | b = rank_bb(s) | p; 124 | 125 | // Flag the pawn as passed, isolated, doubled, 126 | // unsupported or connected (but not the backward one). 127 | connected = ourPawns & adjacent_files_bb(f) & b; 128 | unsupported = !(ourPawns & adjacent_files_bb(f) & p); 129 | isolated = !(ourPawns & adjacent_files_bb(f)); 130 | doubled = ourPawns & forward_bb(Us, s); 131 | opposed = theirPawns & forward_bb(Us, s); 132 | passed = !(theirPawns & passed_pawn_mask(Us, s)); 133 | 134 | // Test for backward pawn. 135 | // If the pawn is passed, isolated, or connected it cannot be 136 | // backward. If there are friendly pawns behind on adjacent files 137 | // or if it can capture an enemy pawn it cannot be backward either. 138 | if ( (passed | isolated | connected) 139 | || (ourPawns & pawn_attack_span(Them, s)) 140 | || (pos.attacks_from(s, Us) & theirPawns)) 141 | backward = false; 142 | else 143 | { 144 | // We now know that there are no friendly pawns beside or behind this 145 | // pawn on adjacent files. We now check whether the pawn is 146 | // backward by looking in the forward direction on the adjacent 147 | // files, and picking the closest pawn there. 148 | b = pawn_attack_span(Us, s) & (ourPawns | theirPawns); 149 | b = pawn_attack_span(Us, s) & rank_bb(backmost_sq(Us, b)); 150 | 151 | // If we have an enemy pawn in the same or next rank, the pawn is 152 | // backward because it cannot advance without being captured. 153 | backward = (b | shift_bb(b)) & theirPawns; 154 | } 155 | 156 | assert(opposed | passed | (pawn_attack_span(Us, s) & theirPawns)); 157 | 158 | // A not-passed pawn is a candidate to become passed, if it is free to 159 | // advance and if the number of friendly pawns beside or behind this 160 | // pawn on adjacent files is higher than or equal to the number of 161 | // enemy pawns in the forward direction on the adjacent files. 162 | candidate = !(opposed | passed | backward | isolated) 163 | && (b = pawn_attack_span(Them, s + pawn_push(Us)) & ourPawns) != 0 164 | && popcount(b) >= popcount(pawn_attack_span(Us, s) & theirPawns); 165 | 166 | // Passed pawns will be properly scored in evaluation because we need 167 | // full attack info to evaluate passed pawns. Only the frontmost passed 168 | // pawn on each file is considered a true passed pawn. 169 | if (passed && !doubled) 170 | e->passedPawns[Us] |= s; 171 | 172 | // Score this pawn 173 | if (isolated) 174 | value -= Isolated[opposed][f]; 175 | 176 | if (unsupported && !isolated) 177 | value -= UnsupportedPawnPenalty; 178 | 179 | if (doubled) 180 | value -= Doubled[f] / rank_distance(s, lsb(doubled)); 181 | 182 | if (backward) 183 | value -= Backward[opposed][f]; 184 | 185 | if (connected) 186 | value += Connected[f][relative_rank(Us, s)]; 187 | 188 | if (candidate) 189 | { 190 | value += CandidatePassed[relative_rank(Us, s)]; 191 | 192 | if (!doubled) 193 | e->candidatePawns[Us] |= s; 194 | } 195 | } 196 | 197 | // In endgame it's better to have pawns on both wings. So give a bonus according 198 | // to file distance between left and right outermost pawns. 199 | if (pos.count(Us) > 1) 200 | { 201 | b = e->semiopenFiles[Us] ^ 0xFF; 202 | value += PawnsFileSpan * int(msb(b) - lsb(b)); 203 | } 204 | 205 | return value; 206 | } 207 | 208 | } // namespace 209 | 210 | namespace Pawns { 211 | 212 | /// init() initializes some tables by formula instead of hard-coding their values 213 | 214 | void init() { 215 | 216 | const int bonusesByFile[8] = { 1, 3, 3, 4, 4, 3, 3, 1 }; 217 | int bonus; 218 | 219 | for (Rank r = RANK_1; r < RANK_8; ++r) 220 | for (File f = FILE_A; f <= FILE_H; ++f) 221 | { 222 | bonus = r * (r-1) * (r-2) + bonusesByFile[f] * (r/2 + 1); 223 | Connected[f][r] = make_score(bonus, bonus); 224 | } 225 | } 226 | 227 | 228 | /// probe() takes a position object as input, computes a Entry object, and returns 229 | /// a pointer to it. The result is also stored in a hash table, so we don't have 230 | /// to recompute everything when the same pawn structure occurs again. 231 | 232 | Entry* probe(const Position& pos, Table& entries) { 233 | 234 | Key key = pos.pawn_key(); 235 | Entry* e = entries[key]; 236 | 237 | if (e->key == key) 238 | return e; 239 | 240 | e->key = key; 241 | e->value = evaluate(pos, e) - evaluate(pos, e); 242 | return e; 243 | } 244 | 245 | 246 | /// Entry::shelter_storm() calculates shelter and storm penalties for the file 247 | /// the king is on, as well as the two adjacent files. 248 | 249 | template 250 | Value Entry::shelter_storm(const Position& pos, Square ksq) { 251 | 252 | const Color Them = (Us == WHITE ? BLACK : WHITE); 253 | static const Bitboard MiddleEdges = (FileABB | FileHBB) & (Rank2BB | Rank3BB); 254 | 255 | Value safety = MaxSafetyBonus; 256 | Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, rank_of(ksq)) | rank_bb(ksq)); 257 | Bitboard ourPawns = b & pos.pieces(Us); 258 | Bitboard theirPawns = b & pos.pieces(Them); 259 | Rank rkUs, rkThem; 260 | File kf = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); 261 | 262 | for (File f = kf - File(1); f <= kf + File(1); ++f) 263 | { 264 | b = ourPawns & file_bb(f); 265 | rkUs = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; 266 | 267 | b = theirPawns & file_bb(f); 268 | rkThem = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; 269 | 270 | if ( (MiddleEdges & make_square(f, rkThem)) 271 | && file_of(ksq) == f 272 | && relative_rank(Us, ksq) == rkThem - 1) 273 | safety += 200; 274 | else 275 | safety -= ShelterWeakness[rkUs] 276 | + StormDanger[rkUs == RANK_1 ? 0 : rkThem == rkUs + 1 ? 2 : 1][rkThem]; 277 | } 278 | 279 | return safety; 280 | } 281 | 282 | 283 | /// Entry::do_king_safety() calculates a bonus for king safety. It is called only 284 | /// when king square changes, which is about 20% of total king_safety() calls. 285 | 286 | template 287 | Score Entry::do_king_safety(const Position& pos, Square ksq) { 288 | 289 | kingSquares[Us] = ksq; 290 | castlingRights[Us] = pos.can_castle(Us); 291 | minKPdistance[Us] = 0; 292 | 293 | Bitboard pawns = pos.pieces(Us, PAWN); 294 | if (pawns) 295 | while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {} 296 | 297 | if (relative_rank(Us, ksq) > RANK_4) 298 | return make_score(0, -16 * minKPdistance[Us]); 299 | 300 | Value bonus = shelter_storm(pos, ksq); 301 | 302 | // If we can castle use the bonus after the castling if it is bigger 303 | if (pos.can_castle(MakeCastling::right)) 304 | bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_G1))); 305 | 306 | if (pos.can_castle(MakeCastling::right)) 307 | bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_C1))); 308 | 309 | return make_score(bonus, -16 * minKPdistance[Us]); 310 | } 311 | 312 | // Explicit template instantiation 313 | template Score Entry::do_king_safety(const Position& pos, Square ksq); 314 | template Score Entry::do_king_safety(const Position& pos, Square ksq); 315 | 316 | } // namespace Pawns 317 | -------------------------------------------------------------------------------- /src/pawns.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef PAWNS_H_INCLUDED 21 | #define PAWNS_H_INCLUDED 22 | 23 | #include "misc.h" 24 | #include "position.h" 25 | #include "types.h" 26 | 27 | namespace Pawns { 28 | 29 | /// Pawns::Entry contains various information about a pawn structure. A lookup 30 | /// to the pawn hash table (performed by calling the probe function) returns a 31 | /// pointer to an Entry object. 32 | 33 | struct Entry { 34 | 35 | Score pawns_value() const { return value; } 36 | Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } 37 | Bitboard passed_pawns(Color c) const { return passedPawns[c]; } 38 | Bitboard candidate_pawns(Color c) const { return candidatePawns[c]; } 39 | 40 | int semiopen_file(Color c, File f) const { 41 | return semiopenFiles[c] & (1 << f); 42 | } 43 | 44 | int semiopen_side(Color c, File f, bool leftSide) const { 45 | return semiopenFiles[c] & (leftSide ? (1 << f) - 1 : ~((1 << (f + 1)) - 1)); 46 | } 47 | 48 | int pawns_on_same_color_squares(Color c, Square s) const { 49 | return pawnsOnSquares[c][!!(DarkSquares & s)]; 50 | } 51 | 52 | template 53 | Score king_safety(const Position& pos, Square ksq) { 54 | return kingSquares[Us] == ksq && castlingRights[Us] == pos.can_castle(Us) 55 | ? kingSafety[Us] : (kingSafety[Us] = do_king_safety(pos, ksq)); 56 | } 57 | 58 | template 59 | Score do_king_safety(const Position& pos, Square ksq); 60 | 61 | template 62 | Value shelter_storm(const Position& pos, Square ksq); 63 | 64 | Key key; 65 | Score value; 66 | Bitboard passedPawns[COLOR_NB]; 67 | Bitboard candidatePawns[COLOR_NB]; 68 | Bitboard pawnAttacks[COLOR_NB]; 69 | Square kingSquares[COLOR_NB]; 70 | Score kingSafety[COLOR_NB]; 71 | int minKPdistance[COLOR_NB]; 72 | int castlingRights[COLOR_NB]; 73 | int semiopenFiles[COLOR_NB]; 74 | int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] 75 | }; 76 | 77 | typedef HashTable Table; 78 | 79 | void init(); 80 | Entry* probe(const Position& pos, Table& entries); 81 | 82 | } // namespace Pawns 83 | 84 | #endif // #ifndef PAWNS_H_INCLUDED 85 | -------------------------------------------------------------------------------- /src/platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef PLATFORM_H_INCLUDED 21 | #define PLATFORM_H_INCLUDED 22 | 23 | #ifdef _MSC_VER 24 | 25 | // Disable some silly and noisy warnings from MSVC compiler 26 | #pragma warning(disable: 4127) // Conditional expression is constant 27 | #pragma warning(disable: 4146) // Unary minus operator applied to unsigned type 28 | #pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false' 29 | #pragma warning(disable: 4996) // Function _ftime() may be unsafe 30 | 31 | // MSVC does not support 32 | typedef signed __int8 int8_t; 33 | typedef unsigned __int8 uint8_t; 34 | typedef signed __int16 int16_t; 35 | typedef unsigned __int16 uint16_t; 36 | typedef signed __int32 int32_t; 37 | typedef unsigned __int32 uint32_t; 38 | typedef signed __int64 int64_t; 39 | typedef unsigned __int64 uint64_t; 40 | 41 | #else 42 | # include 43 | #endif 44 | 45 | #ifndef _WIN32 // Linux - Unix 46 | 47 | # include 48 | 49 | inline int64_t system_time_to_msec() { 50 | timeval t; 51 | gettimeofday(&t, NULL); 52 | return t.tv_sec * 1000LL + t.tv_usec / 1000; 53 | } 54 | 55 | typedef void* Lock; 56 | typedef void* WaitCondition; 57 | typedef void* NativeHandle; 58 | typedef void*(*pt_start_fn)(void*); 59 | 60 | # define lock_init(x) (x = 0) 61 | # define lock_grab(x) ((void)x) 62 | # define lock_release(x) ((void)x) 63 | # define lock_destroy(x) ((void)x) 64 | # define cond_destroy(x) ((void)x) 65 | # define cond_init(x) (x = 0) 66 | # define cond_signal(x) ((void)x) 67 | # define cond_wait(x,y) ((void)x,(void)y) 68 | # define cond_timedwait(x,y,z) ((void)x,(void)y,(void)z) 69 | # define thread_create(x,f,t) (x = ((void)f,(void)t,(void*)0)) 70 | # define thread_join(x) ((void)x) 71 | 72 | #else // Windows and MinGW 73 | 74 | # include 75 | 76 | inline int64_t system_time_to_msec() { 77 | _timeb t; 78 | _ftime(&t); 79 | return t.time * 1000LL + t.millitm; 80 | } 81 | 82 | #ifndef NOMINMAX 83 | # define NOMINMAX // disable macros min() and max() 84 | #endif 85 | 86 | #define WIN32_LEAN_AND_MEAN 87 | #include 88 | #undef WIN32_LEAN_AND_MEAN 89 | #undef NOMINMAX 90 | 91 | // We use critical sections on Windows to support Windows XP and older versions. 92 | // Unfortunately, cond_wait() is racy between lock_release() and WaitForSingleObject() 93 | // but apart from this they have the same speed performance of SRW locks. 94 | typedef CRITICAL_SECTION Lock; 95 | typedef HANDLE WaitCondition; 96 | typedef HANDLE NativeHandle; 97 | 98 | // On Windows 95 and 98 parameter lpThreadId may not be null 99 | inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; } 100 | 101 | # define lock_init(x) InitializeCriticalSection(&(x)) 102 | # define lock_grab(x) EnterCriticalSection(&(x)) 103 | # define lock_release(x) LeaveCriticalSection(&(x)) 104 | # define lock_destroy(x) DeleteCriticalSection(&(x)) 105 | # define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); } 106 | # define cond_destroy(x) CloseHandle(x) 107 | # define cond_signal(x) SetEvent(x) 108 | # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } 109 | # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } 110 | # define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,dwWin9xKludge())) 111 | # define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); } 112 | 113 | #endif 114 | 115 | #endif // #ifndef PLATFORM_H_INCLUDED 116 | -------------------------------------------------------------------------------- /src/psqtab.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef PSQTAB_H_INCLUDED 21 | #define PSQTAB_H_INCLUDED 22 | 23 | #include "types.h" 24 | 25 | #define S(mg, eg) make_score(mg, eg) 26 | 27 | 28 | /// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on 29 | /// a given square a (middlegame, endgame) score pair is assigned. PSQT is defined 30 | /// for the white side and the tables are symmetric for the black side. 31 | 32 | static const Score PSQT[][SQUARE_NB] = { 33 | { }, 34 | { // Pawn 35 | S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0), 36 | S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0), 37 | S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0), 38 | S(-20, 0), S( 0, 0), S(20, 0), S(40, 0), S(40, 0), S(20, 0), S( 0, 0), S(-20, 0), 39 | S(-20, 0), S( 0, 0), S(10, 0), S(20, 0), S(20, 0), S(10, 0), S( 0, 0), S(-20, 0), 40 | S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0), 41 | S(-20, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S(-20, 0), 42 | S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0) 43 | }, 44 | { // Knight 45 | S(-144,-98), S(-109,-83), S(-85,-51), S(-73,-16), S(-73,-16), S(-85,-51), S(-109,-83), S(-144,-98), 46 | S( -88,-68), S( -43,-53), S(-19,-21), S( -7, 14), S( -7, 14), S(-19,-21), S( -43,-53), S( -88,-68), 47 | S( -69,-53), S( -24,-38), S( 0, -6), S( 12, 29), S( 12, 29), S( 0, -6), S( -24,-38), S( -69,-53), 48 | S( -28,-42), S( 17,-27), S( 41, 5), S( 53, 40), S( 53, 40), S( 41, 5), S( 17,-27), S( -28,-42), 49 | S( -30,-42), S( 15,-27), S( 39, 5), S( 51, 40), S( 51, 40), S( 39, 5), S( 15,-27), S( -30,-42), 50 | S( -10,-53), S( 35,-38), S( 59, -6), S( 71, 29), S( 71, 29), S( 59, -6), S( 35,-38), S( -10,-53), 51 | S( -64,-68), S( -19,-53), S( 5,-21), S( 17, 14), S( 17, 14), S( 5,-21), S( -19,-53), S( -64,-68), 52 | S(-200,-98), S( -65,-83), S(-41,-51), S(-29,-16), S(-29,-16), S(-41,-51), S( -65,-83), S(-200,-98) 53 | }, 54 | { // Bishop 55 | S(-54,-65), S(-27,-42), S(-34,-44), S(-43,-26), S(-43,-26), S(-34,-44), S(-27,-42), S(-54,-65), 56 | S(-29,-43), S( 8,-20), S( 1,-22), S( -8, -4), S( -8, -4), S( 1,-22), S( 8,-20), S(-29,-43), 57 | S(-20,-33), S( 17,-10), S( 10,-12), S( 1, 6), S( 1, 6), S( 10,-12), S( 17,-10), S(-20,-33), 58 | S(-19,-35), S( 18,-12), S( 11,-14), S( 2, 4), S( 2, 4), S( 11,-14), S( 18,-12), S(-19,-35), 59 | S(-22,-35), S( 15,-12), S( 8,-14), S( -1, 4), S( -1, 4), S( 8,-14), S( 15,-12), S(-22,-35), 60 | S(-28,-33), S( 9,-10), S( 2,-12), S( -7, 6), S( -7, 6), S( 2,-12), S( 9,-10), S(-28,-33), 61 | S(-32,-43), S( 5,-20), S( -2,-22), S(-11, -4), S(-11, -4), S( -2,-22), S( 5,-20), S(-32,-43), 62 | S(-49,-65), S(-22,-42), S(-29,-44), S(-38,-26), S(-38,-26), S(-29,-44), S(-22,-42), S(-49,-65) 63 | }, 64 | { // Rook 65 | S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3), 66 | S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3), 67 | S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3), 68 | S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3), 69 | S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3), 70 | S(-22, 3), S( -7, 3), S( -2, 3), S( 2, 3), S( 2, 3), S( -2, 3), S( -7, 3), S(-22, 3), 71 | S(-11, 3), S( 4, 3), S( 9, 3), S(13, 3), S(13, 3), S( 9, 3), S( 4, 3), S(-11, 3), 72 | S(-22, 3), S(-17, 3), S(-12, 3), S(-8, 3), S(-8, 3), S(-12, 3), S(-17, 3), S(-22, 3) 73 | }, 74 | { // Queen 75 | S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80), 76 | S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54), 77 | S(-2,-42), S( 8,-18), S( 8, -6), S( 8, 6), S( 8, 6), S( 8, -6), S( 8,-18), S(-2,-42), 78 | S(-2,-30), S( 8, -6), S( 8, 6), S( 8, 18), S( 8, 18), S( 8, 6), S( 8, -6), S(-2,-30), 79 | S(-2,-30), S( 8, -6), S( 8, 6), S( 8, 18), S( 8, 18), S( 8, 6), S( 8, -6), S(-2,-30), 80 | S(-2,-42), S( 8,-18), S( 8, -6), S( 8, 6), S( 8, 6), S( 8, -6), S( 8,-18), S(-2,-42), 81 | S(-2,-54), S( 8,-30), S( 8,-18), S( 8, -6), S( 8, -6), S( 8,-18), S( 8,-30), S(-2,-54), 82 | S(-2,-80), S(-2,-54), S(-2,-42), S(-2,-30), S(-2,-30), S(-2,-42), S(-2,-54), S(-2,-80) 83 | }, 84 | { // King 85 | S(298, 27), S(332, 81), S(273,108), S(225,116), S(225,116), S(273,108), S(332, 81), S(298, 27), 86 | S(287, 74), S(321,128), S(262,155), S(214,163), S(214,163), S(262,155), S(321,128), S(287, 74), 87 | S(224,111), S(258,165), S(199,192), S(151,200), S(151,200), S(199,192), S(258,165), S(224,111), 88 | S(196,135), S(230,189), S(171,216), S(123,224), S(123,224), S(171,216), S(230,189), S(196,135), 89 | S(173,135), S(207,189), S(148,216), S(100,224), S(100,224), S(148,216), S(207,189), S(173,135), 90 | S(146,111), S(180,165), S(121,192), S( 73,200), S( 73,200), S(121,192), S(180,165), S(146,111), 91 | S(119, 74), S(153,128), S( 94,155), S( 46,163), S( 46,163), S( 94,155), S(153,128), S(119, 74), 92 | S( 98, 27), S(132, 81), S( 73,108), S( 25,116), S( 25,116), S( 73,108), S(132, 81), S( 98, 27) 93 | } 94 | }; 95 | 96 | #undef S 97 | 98 | #endif // #ifndef PSQTAB_H_INCLUDED 99 | -------------------------------------------------------------------------------- /src/rkiss.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | 19 | This file is based on original code by Heinz van Saanen and is 20 | available under the GNU General Public License as published by 21 | the Free Software Foundation, either version 3 of the License, or 22 | (at your option) any later version. 23 | */ 24 | 25 | #ifndef RKISS_H_INCLUDED 26 | #define RKISS_H_INCLUDED 27 | 28 | #include "types.h" 29 | 30 | /// RKISS is our pseudo random number generator (PRNG) used to compute hash keys. 31 | /// George Marsaglia invented the RNG-Kiss-family in the early 90's. This is a 32 | /// specific version that Heinz van Saanen derived from some public domain code 33 | /// by Bob Jenkins. Following the feature list, as tested by Heinz. 34 | /// 35 | /// - Quite platform independent 36 | /// - Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-) 37 | /// - ~12 times faster than my *nix sys-rand() 38 | /// - ~4 times faster than SSE2-version of Mersenne twister 39 | /// - Average cycle length: ~2^126 40 | /// - 64 bit seed 41 | /// - Return doubles with a full 53 bit mantissa 42 | /// - Thread safe 43 | 44 | class RKISS { 45 | 46 | uint64_t a, b, c, d; 47 | 48 | uint64_t rotate_L(uint64_t x, unsigned k) const { 49 | return (x << k) | (x >> (64 - k)); 50 | } 51 | 52 | uint64_t rand64() { 53 | 54 | const uint64_t e = a - rotate_L(b, 7); 55 | a = b ^ rotate_L(c, 13); 56 | b = c + rotate_L(d, 37); 57 | c = d + e; 58 | return d = e + a; 59 | } 60 | 61 | public: 62 | RKISS(int seed = 73) { 63 | 64 | a = 0xF1EA5EED, b = c = d = 0xD4E12C77; 65 | 66 | for (int i = 0; i < seed; ++i) // Scramble a few rounds 67 | rand64(); 68 | } 69 | 70 | template T rand() { return T(rand64()); } 71 | 72 | /// Special generator used to fast init magic numbers. Here the 73 | /// trick is to rotate the randoms of a given quantity 's' known 74 | /// to be optimal to quickly find a good magic candidate. 75 | template T magic_rand(int s) { 76 | return rotate_L(rotate_L(rand(), (s >> 0) & 0x3F) & rand() 77 | , (s >> 6) & 0x3F) & rand(); 78 | } 79 | }; 80 | 81 | #endif // #ifndef RKISS_H_INCLUDED 82 | -------------------------------------------------------------------------------- /src/search.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef SEARCH_H_INCLUDED 21 | #define SEARCH_H_INCLUDED 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "misc.h" 28 | #include "position.h" 29 | #include "types.h" 30 | 31 | struct SplitPoint; 32 | 33 | namespace Search { 34 | 35 | /// The Stack struct keeps track of the information we need to remember from 36 | /// nodes shallower and deeper in the tree during the search. Each search thread 37 | /// has its own array of Stack objects, indexed by the current ply. 38 | 39 | struct Stack { 40 | SplitPoint* splitPoint; 41 | int ply; 42 | Move currentMove; 43 | Move ttMove; 44 | Move excludedMove; 45 | Move killers[2]; 46 | Depth reduction; 47 | Value staticEval; 48 | int skipNullMove; 49 | }; 50 | 51 | 52 | /// RootMove struct is used for moves at the root of the tree. For each root 53 | /// move we store a score, a node count, and a PV (really a refutation in the 54 | /// case of moves which fail low). Score is normally set at -VALUE_INFINITE for 55 | /// all non-pv moves. 56 | struct RootMove { 57 | 58 | RootMove(Move m) : score(-VALUE_INFINITE), prevScore(-VALUE_INFINITE) { 59 | pv.push_back(m); pv.push_back(MOVE_NONE); 60 | } 61 | 62 | bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort 63 | bool operator==(const Move& m) const { return pv[0] == m; } 64 | 65 | void extract_pv_from_tt(Position& pos); 66 | void insert_pv_in_tt(Position& pos); 67 | 68 | Value score; 69 | Value prevScore; 70 | std::vector pv; 71 | }; 72 | 73 | 74 | /// The LimitsType struct stores information sent by GUI about available time 75 | /// to search the current move, maximum depth/time, if we are in analysis mode 76 | /// or if we have to ponder while it's our opponent's turn to move. 77 | 78 | struct LimitsType { 79 | 80 | LimitsType() { // Using memset on a std::vector is undefined behavior 81 | time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = movestogo = 82 | depth = nodes = movetime = mate = infinite = ponder = 0; 83 | } 84 | bool use_time_management() const { return !(mate | movetime | depth | nodes | infinite); } 85 | 86 | std::vector searchmoves; 87 | int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, nodes, movetime, mate, infinite, ponder; 88 | }; 89 | 90 | 91 | /// The SignalsType struct stores volatile flags updated during the search 92 | /// typically in an async fashion e.g. to stop the search by the GUI. 93 | 94 | struct SignalsType { 95 | bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot; 96 | }; 97 | 98 | typedef std::auto_ptr > StateStackPtr; 99 | 100 | extern volatile SignalsType Signals; 101 | extern LimitsType Limits; 102 | extern std::vector RootMoves; 103 | extern Position RootPos; 104 | extern Color RootColor; 105 | extern Time::point SearchTime; 106 | extern StateStackPtr SetupStates; 107 | 108 | extern void init(); 109 | extern uint64_t perft(Position& pos, Depth depth); 110 | extern void think(); 111 | 112 | } // namespace Search 113 | 114 | #endif // #ifndef SEARCH_H_INCLUDED 115 | -------------------------------------------------------------------------------- /src/thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include // For std::count 21 | #include 22 | 23 | #include "movegen.h" 24 | #include "search.h" 25 | #include "thread.h" 26 | #include "ucioption.h" 27 | 28 | using namespace Search; 29 | 30 | ThreadPool Threads; // Global object 31 | 32 | extern void check_time(); 33 | 34 | namespace { 35 | 36 | // start_routine() is the C function which is called when a new thread 37 | // is launched. It is a wrapper to the virtual function idle_loop(). 38 | 39 | extern "C" { long start_routine(ThreadBase* th) { th->idle_loop(); return 0; } } 40 | 41 | 42 | // Helpers to launch a thread after creation and joining before delete. Must be 43 | // outside Thread c'tor and d'tor because the object will be fully initialized 44 | // when start_routine (and hence virtual idle_loop) is called and when joining. 45 | 46 | template T* new_thread() { 47 | T* th = new T(); 48 | thread_create(th->handle, start_routine, th); // Will go to sleep 49 | return th; 50 | } 51 | 52 | void delete_thread(ThreadBase* th) { 53 | th->exit = true; // Search must be already finished 54 | th->notify_one(); 55 | thread_join(th->handle); // Wait for thread termination 56 | delete th; 57 | } 58 | 59 | } 60 | 61 | 62 | // notify_one() wakes up the thread when there is some work to do 63 | 64 | void ThreadBase::notify_one() { 65 | 66 | mutex.lock(); 67 | sleepCondition.notify_one(); 68 | mutex.unlock(); 69 | } 70 | 71 | 72 | // wait_for() set the thread to sleep until condition 'b' turns true 73 | 74 | void ThreadBase::wait_for(volatile const bool& b) { 75 | 76 | mutex.lock(); 77 | while (!b) sleepCondition.wait(mutex); 78 | mutex.unlock(); 79 | } 80 | 81 | 82 | // Thread c'tor just inits data and does not launch any execution thread. 83 | // Such a thread will only be started when c'tor returns. 84 | 85 | Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC 86 | 87 | searching = false; 88 | maxPly = splitPointsSize = 0; 89 | activeSplitPoint = NULL; 90 | activePosition = NULL; 91 | idx = Threads.size(); // Starts from 0 92 | } 93 | 94 | 95 | // cutoff_occurred() checks whether a beta cutoff has occurred in the 96 | // current active split point, or in some ancestor of the split point. 97 | 98 | bool Thread::cutoff_occurred() const { 99 | 100 | for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint) 101 | if (sp->cutoff) 102 | return true; 103 | 104 | return false; 105 | } 106 | 107 | 108 | // Thread::available_to() checks whether the thread is available to help the 109 | // thread 'master' at a split point. An obvious requirement is that thread must 110 | // be idle. With more than two threads, this is not sufficient: If the thread is 111 | // the master of some split point, it is only available as a slave to the slaves 112 | // which are busy searching the split point at the top of slave's split point 113 | // stack (the "helpful master concept" in YBWC terminology). 114 | 115 | bool Thread::available_to(const Thread* master) const { 116 | 117 | // if (searching) 118 | return false; 119 | 120 | // Make a local copy to be sure it doesn't become zero under our feet while 121 | // testing next condition and so leading to an out of bounds access. 122 | int size = splitPointsSize; 123 | 124 | // No split points means that the thread is available as a slave for any 125 | // other thread otherwise apply the "helpful master" concept if possible. 126 | return !size || splitPoints[size - 1].slavesMask.test(master->idx); 127 | } 128 | 129 | 130 | // TimerThread::idle_loop() is where the timer thread waits msec milliseconds 131 | // and then calls check_time(). If msec is 0 thread sleeps until it's woken up. 132 | 133 | void TimerThread::idle_loop() { 134 | 135 | while (!exit) 136 | { 137 | mutex.lock(); 138 | 139 | if (!exit) 140 | sleepCondition.wait_for(mutex, run ? Resolution : INT_MAX); 141 | 142 | mutex.unlock(); 143 | 144 | if (run) 145 | check_time(); 146 | } 147 | } 148 | 149 | 150 | // MainThread::idle_loop() is where the main thread is parked waiting to be started 151 | // when there is a new search. The main thread will launch all the slave threads. 152 | 153 | void MainThread::idle_loop() { 154 | 155 | while (true) 156 | { 157 | mutex.lock(); 158 | 159 | thinking = false; 160 | 161 | while (!thinking && !exit) 162 | { 163 | Threads.sleepCondition.notify_one(); // Wake up the UI thread if needed 164 | sleepCondition.wait(mutex); 165 | } 166 | 167 | mutex.unlock(); 168 | 169 | if (exit) 170 | return; 171 | 172 | searching = true; 173 | 174 | Search::think(); 175 | 176 | assert(searching); 177 | 178 | searching = false; 179 | } 180 | } 181 | 182 | 183 | // init() is called at startup to create and launch requested threads, that will 184 | // go immediately to sleep. We cannot use a c'tor because Threads is a static 185 | // object and we need a fully initialized engine at this point due to allocation 186 | // of Endgames in Thread c'tor. 187 | 188 | void ThreadPool::init() { 189 | 190 | timer = new_thread(); 191 | push_back(new_thread()); 192 | read_uci_options(); 193 | } 194 | 195 | 196 | // exit() cleanly terminates the threads before the program exits. Cannot be done in 197 | // d'tor because we have to terminate the threads before to free ThreadPool object. 198 | 199 | void ThreadPool::exit() { 200 | 201 | delete_thread(timer); // As first because check_time() accesses threads data 202 | 203 | for (iterator it = begin(); it != end(); ++it) 204 | delete_thread(*it); 205 | } 206 | 207 | 208 | // read_uci_options() updates internal threads parameters from the corresponding 209 | // UCI options and creates/destroys threads to match the requested number. Thread 210 | // objects are dynamically allocated to avoid creating all possible threads 211 | // in advance (which include pawns and material tables), even if only a few 212 | // are to be used. 213 | 214 | void ThreadPool::read_uci_options() { 215 | 216 | minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; 217 | size_t requested = Options["Threads"]; 218 | 219 | assert(requested > 0); 220 | 221 | // If zero (default) then set best minimum split depth automatically 222 | if (!minimumSplitDepth) 223 | minimumSplitDepth = requested < 8 ? 4 * ONE_PLY : 7 * ONE_PLY; 224 | 225 | while (size() < requested) 226 | push_back(new_thread()); 227 | 228 | while (size() > requested) 229 | { 230 | delete_thread(back()); 231 | pop_back(); 232 | } 233 | } 234 | 235 | 236 | // available_slave() tries to find an idle thread which is available as a slave 237 | // for the thread 'master'. 238 | 239 | Thread* ThreadPool::available_slave(const Thread* master) const { 240 | 241 | for (const_iterator it = begin(); it != end(); ++it) 242 | if ((*it)->available_to(master)) 243 | return *it; 244 | 245 | return NULL; 246 | } 247 | 248 | 249 | // split() does the actual work of distributing the work at a node between 250 | // several available threads. If it does not succeed in splitting the node 251 | // (because no idle threads are available), the function immediately returns. 252 | // If splitting is possible, a SplitPoint object is initialized with all the 253 | // data that must be copied to the helper threads and then helper threads are 254 | // told that they have been assigned work. This will cause them to instantly 255 | // leave their idle loops and call search(). When all threads have returned from 256 | // search() then split() returns. 257 | 258 | template 259 | void Thread::split(Position& pos, const Stack* ss, Value alpha, Value beta, Value* bestValue, 260 | Move* bestMove, Depth depth, int moveCount, 261 | MovePicker* movePicker, int nodeType, bool cutNode) { 262 | 263 | assert(pos.pos_is_ok()); 264 | assert(-VALUE_INFINITE < *bestValue && *bestValue <= alpha && alpha < beta && beta <= VALUE_INFINITE); 265 | assert(depth >= Threads.minimumSplitDepth); 266 | assert(searching); 267 | assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD); 268 | 269 | // Pick the next available split point from the split point stack 270 | SplitPoint& sp = splitPoints[splitPointsSize]; 271 | 272 | sp.masterThread = this; 273 | sp.parentSplitPoint = activeSplitPoint; 274 | sp.slavesMask = 0, sp.slavesMask.set(idx); 275 | sp.depth = depth; 276 | sp.bestValue = *bestValue; 277 | sp.bestMove = *bestMove; 278 | sp.alpha = alpha; 279 | sp.beta = beta; 280 | sp.nodeType = nodeType; 281 | sp.cutNode = cutNode; 282 | sp.movePicker = movePicker; 283 | sp.moveCount = moveCount; 284 | sp.pos = &pos; 285 | sp.nodes = 0; 286 | sp.cutoff = false; 287 | sp.ss = ss; 288 | 289 | // Try to allocate available threads and ask them to start searching setting 290 | // 'searching' flag. This must be done under lock protection to avoid concurrent 291 | // allocation of the same slave by another master. 292 | Threads.mutex.lock(); 293 | sp.mutex.lock(); 294 | 295 | sp.allSlavesSearching = true; // Must be set under lock protection 296 | ++splitPointsSize; 297 | activeSplitPoint = &sp; 298 | activePosition = NULL; 299 | 300 | if (!Fake) 301 | for (Thread* slave; (slave = Threads.available_slave(this)) != NULL; ) 302 | { 303 | sp.slavesMask.set(slave->idx); 304 | slave->activeSplitPoint = &sp; 305 | slave->searching = true; // Slave leaves idle_loop() 306 | slave->notify_one(); // Could be sleeping 307 | } 308 | 309 | // Everything is set up. The master thread enters the idle loop, from which 310 | // it will instantly launch a search, because its 'searching' flag is set. 311 | // The thread will return from the idle loop when all slaves have finished 312 | // their work at this split point. 313 | sp.mutex.unlock(); 314 | Threads.mutex.unlock(); 315 | 316 | Thread::idle_loop(); // Force a call to base class idle_loop() 317 | 318 | // In the helpful master concept, a master can help only a sub-tree of its 319 | // split point and because everything is finished here, it's not possible 320 | // for the master to be booked. 321 | assert(!searching); 322 | assert(!activePosition); 323 | 324 | // We have returned from the idle loop, which means that all threads are 325 | // finished. Note that setting 'searching' and decreasing splitPointsSize is 326 | // done under lock protection to avoid a race with Thread::available_to(). 327 | Threads.mutex.lock(); 328 | sp.mutex.lock(); 329 | 330 | searching = true; 331 | --splitPointsSize; 332 | activeSplitPoint = sp.parentSplitPoint; 333 | activePosition = &pos; 334 | pos.set_nodes_searched(pos.nodes_searched() + sp.nodes); 335 | *bestMove = sp.bestMove; 336 | *bestValue = sp.bestValue; 337 | 338 | sp.mutex.unlock(); 339 | Threads.mutex.unlock(); 340 | } 341 | 342 | // Explicit template instantiations 343 | template void Thread::split(Position&, const Stack*, Value, Value, Value*, Move*, Depth, int, MovePicker*, int, bool); 344 | template void Thread::split< true>(Position&, const Stack*, Value, Value, Value*, Move*, Depth, int, MovePicker*, int, bool); 345 | 346 | 347 | // wait_for_think_finished() waits for main thread to go to sleep then returns 348 | 349 | void ThreadPool::wait_for_think_finished() { 350 | } 351 | 352 | 353 | // start_thinking() wakes up the main thread sleeping in MainThread::idle_loop() 354 | // so to start a new search, then returns immediately. 355 | 356 | void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits, StateStackPtr& states) { 357 | 358 | wait_for_think_finished(); 359 | 360 | SearchTime = Time::now(); // As early as possible 361 | 362 | Signals.stopOnPonderhit = Signals.firstRootMove = false; 363 | Signals.stop = Signals.failedLowAtRoot = false; 364 | 365 | RootMoves.clear(); 366 | RootPos = pos; 367 | Limits = limits; 368 | if (states.get()) // If we don't set a new position, preserve current state 369 | { 370 | SetupStates = states; // Ownership transfer here 371 | assert(!states.get()); 372 | } 373 | 374 | for (MoveList it(pos); *it; ++it) 375 | if ( limits.searchmoves.empty() 376 | || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), *it)) 377 | RootMoves.push_back(RootMove(*it)); 378 | 379 | Search::think(); 380 | } 381 | -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef THREAD_H_INCLUDED 21 | #define THREAD_H_INCLUDED 22 | 23 | #include 24 | #include 25 | 26 | #include "material.h" 27 | #include "movepick.h" 28 | #include "pawns.h" 29 | #include "position.h" 30 | #include "search.h" 31 | 32 | const int MAX_THREADS = 128; 33 | const int MAX_SPLITPOINTS_PER_THREAD = 8; 34 | 35 | struct Mutex { 36 | Mutex() { lock_init(l); } 37 | ~Mutex() { lock_destroy(l); } 38 | 39 | void lock() { lock_grab(l); } 40 | void unlock() { lock_release(l); } 41 | 42 | private: 43 | friend struct ConditionVariable; 44 | 45 | Lock l; 46 | }; 47 | 48 | struct ConditionVariable { 49 | ConditionVariable() { cond_init(c); } 50 | ~ConditionVariable() { cond_destroy(c); } 51 | 52 | void wait(Mutex& m) { cond_wait(c, m.l); } 53 | void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); } 54 | void notify_one() { cond_signal(c); } 55 | 56 | private: 57 | WaitCondition c; 58 | }; 59 | 60 | struct Thread; 61 | 62 | struct SplitPoint { 63 | 64 | // Const data after split point has been setup 65 | const Position* pos; 66 | const Search::Stack* ss; 67 | Thread* masterThread; 68 | Depth depth; 69 | Value beta; 70 | int nodeType; 71 | bool cutNode; 72 | 73 | // Const pointers to shared data 74 | MovePicker* movePicker; 75 | SplitPoint* parentSplitPoint; 76 | 77 | // Shared data 78 | Mutex mutex; 79 | std::bitset slavesMask; 80 | volatile bool allSlavesSearching; 81 | volatile uint64_t nodes; 82 | volatile Value alpha; 83 | volatile Value bestValue; 84 | volatile Move bestMove; 85 | volatile int moveCount; 86 | volatile bool cutoff; 87 | }; 88 | 89 | 90 | /// ThreadBase struct is the base of the hierarchy from where we derive all the 91 | /// specialized thread classes. 92 | 93 | struct ThreadBase { 94 | 95 | ThreadBase() : handle(NativeHandle()), exit(false) {} 96 | virtual ~ThreadBase() {} 97 | virtual void idle_loop() = 0; 98 | void notify_one(); 99 | void wait_for(volatile const bool& b); 100 | 101 | Mutex mutex; 102 | ConditionVariable sleepCondition; 103 | NativeHandle handle; 104 | volatile bool exit; 105 | }; 106 | 107 | 108 | /// Thread struct keeps together all the thread related stuff like locks, state 109 | /// and especially split points. We also use per-thread pawn and material hash 110 | /// tables so that once we get a pointer to an entry its life time is unlimited 111 | /// and we don't have to care about someone changing the entry under our feet. 112 | 113 | struct Thread : public ThreadBase { 114 | 115 | Thread(); 116 | virtual void idle_loop(); 117 | bool cutoff_occurred() const; 118 | bool available_to(const Thread* master) const; 119 | 120 | template 121 | void split(Position& pos, const Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove, 122 | Depth depth, int moveCount, MovePicker* movePicker, int nodeType, bool cutNode); 123 | 124 | SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD]; 125 | Material::Table materialTable; 126 | Endgames endgames; 127 | Pawns::Table pawnsTable; 128 | Position* activePosition; 129 | size_t idx; 130 | int maxPly; 131 | SplitPoint* volatile activeSplitPoint; 132 | volatile int splitPointsSize; 133 | volatile bool searching; 134 | }; 135 | 136 | 137 | /// MainThread and TimerThread are derived classes used to characterize the two 138 | /// special threads: the main one and the recurring timer. 139 | 140 | struct MainThread : public Thread { 141 | MainThread() : thinking(true) {} // Avoid a race with start_thinking() 142 | virtual void idle_loop(); 143 | volatile bool thinking; 144 | }; 145 | 146 | struct TimerThread : public ThreadBase { 147 | TimerThread() : run(false) {} 148 | virtual void idle_loop(); 149 | bool run; 150 | static const int Resolution = 5; // msec between two check_time() calls 151 | }; 152 | 153 | 154 | /// ThreadPool struct handles all the threads related stuff like init, starting, 155 | /// parking and, most importantly, launching a slave thread at a split point. 156 | /// All the access to shared thread data is done through this class. 157 | 158 | struct ThreadPool : public std::vector { 159 | 160 | void init(); // No c'tor and d'tor, threads rely on globals that should 161 | void exit(); // be initialized and are valid during the whole thread lifetime. 162 | 163 | MainThread* main() { return static_cast((*this)[0]); } 164 | void read_uci_options(); 165 | Thread* available_slave(const Thread* master) const; 166 | void wait_for_think_finished(); 167 | void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&); 168 | 169 | Depth minimumSplitDepth; 170 | Mutex mutex; 171 | ConditionVariable sleepCondition; 172 | TimerThread* timer; 173 | }; 174 | 175 | extern ThreadPool Threads; 176 | 177 | #endif // #ifndef THREAD_H_INCLUDED 178 | -------------------------------------------------------------------------------- /src/timeman.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "search.h" 25 | #include "timeman.h" 26 | #include "ucioption.h" 27 | 28 | namespace { 29 | 30 | enum TimeType { OptimumTime, MaxTime }; 31 | 32 | const int MoveHorizon = 50; // Plan time management at most this many moves ahead 33 | const double MaxRatio = 7.0; // When in trouble, we can step over reserved time with this ratio 34 | const double StealRatio = 0.33; // However we must not steal time from remaining moves over this ratio 35 | 36 | const double xscale = 9.3; 37 | const double xshift = 59.8; 38 | const double skewfactor = 0.172; 39 | 40 | 41 | // move_importance() is a skew-logistic function based on naive statistical 42 | // analysis of "how many games are still undecided after n half-moves". Game 43 | // is considered "undecided" as long as neither side has >275cp advantage. 44 | // Data was extracted from CCRL game database with some simple filtering criteria. 45 | 46 | double move_importance(int ply) { 47 | 48 | return pow((1 + exp((ply - xshift) / xscale)), -skewfactor) + DBL_MIN; // Ensure non-zero 49 | } 50 | 51 | template 52 | int remaining(int myTime, int movesToGo, int currentPly, int slowMover) 53 | { 54 | const double TMaxRatio = (T == OptimumTime ? 1 : MaxRatio); 55 | const double TStealRatio = (T == OptimumTime ? 0 : StealRatio); 56 | 57 | double thisMoveImportance = (move_importance(currentPly) * slowMover) / 100; 58 | double otherMovesImportance = 0; 59 | 60 | for (int i = 1; i < movesToGo; ++i) 61 | otherMovesImportance += move_importance(currentPly + 2 * i); 62 | 63 | double ratio1 = (TMaxRatio * thisMoveImportance) / (TMaxRatio * thisMoveImportance + otherMovesImportance); 64 | double ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / (thisMoveImportance + otherMovesImportance); 65 | 66 | return int(myTime * std::min(ratio1, ratio2)); 67 | } 68 | 69 | } // namespace 70 | 71 | 72 | void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color us) 73 | { 74 | /* We support four different kinds of time controls: 75 | 76 | increment == 0 && movesToGo == 0 means: x basetime [sudden death!] 77 | increment == 0 && movesToGo != 0 means: x moves in y minutes 78 | increment > 0 && movesToGo == 0 means: x basetime + z increment 79 | increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment 80 | 81 | Time management is adjusted by following UCI parameters: 82 | 83 | emergencyMoveHorizon: Be prepared to always play at least this many moves 84 | emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock 85 | emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move 86 | minThinkingTime : No matter what, use at least this much thinking before doing the move 87 | */ 88 | 89 | int hypMTG, hypMyTime, t1, t2; 90 | 91 | // Read uci parameters 92 | int emergencyMoveHorizon = Options["Emergency Move Horizon"]; 93 | int emergencyBaseTime = Options["Emergency Base Time"]; 94 | int emergencyMoveTime = Options["Emergency Move Time"]; 95 | int minThinkingTime = Options["Minimum Thinking Time"]; 96 | int slowMover = Options["Slow Mover"]; 97 | 98 | // Initialize unstablePvFactor to 1 and search times to maximum values 99 | unstablePvFactor = 1; 100 | optimumSearchTime = maximumSearchTime = std::max(limits.time[us], minThinkingTime); 101 | 102 | // We calculate optimum time usage for different hypothetical "moves to go"-values and choose the 103 | // minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values. 104 | for (hypMTG = 1; hypMTG <= (limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon); ++hypMTG) 105 | { 106 | // Calculate thinking time for hypothetical "moves to go"-value 107 | hypMyTime = limits.time[us] 108 | + limits.inc[us] * (hypMTG - 1) 109 | - emergencyBaseTime 110 | - emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon); 111 | 112 | hypMyTime = std::max(hypMyTime, 0); 113 | 114 | t1 = minThinkingTime + remaining(hypMyTime, hypMTG, currentPly, slowMover); 115 | t2 = minThinkingTime + remaining(hypMyTime, hypMTG, currentPly, slowMover); 116 | 117 | optimumSearchTime = std::min(optimumSearchTime, t1); 118 | maximumSearchTime = std::min(maximumSearchTime, t2); 119 | } 120 | 121 | if (Options["Ponder"]) 122 | optimumSearchTime += optimumSearchTime / 4; 123 | 124 | // Make sure that maxSearchTime is not over absoluteMaxSearchTime 125 | optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime); 126 | } 127 | -------------------------------------------------------------------------------- /src/timeman.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef TIMEMAN_H_INCLUDED 21 | #define TIMEMAN_H_INCLUDED 22 | 23 | /// The TimeManager class computes the optimal time to think depending on the 24 | /// maximum available time, the game move number and other parameters. 25 | 26 | class TimeManager { 27 | public: 28 | void init(const Search::LimitsType& limits, int currentPly, Color us); 29 | void pv_instability(double bestMoveChanges) { unstablePvFactor = 1 + bestMoveChanges; } 30 | int available_time() const { return int(optimumSearchTime * unstablePvFactor * 0.71); } 31 | int maximum_time() const { return maximumSearchTime; } 32 | 33 | private: 34 | int optimumSearchTime; 35 | int maximumSearchTime; 36 | double unstablePvFactor; 37 | }; 38 | 39 | #endif // #ifndef TIMEMAN_H_INCLUDED 40 | -------------------------------------------------------------------------------- /src/tt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "bitboard.h" 24 | #include "tt.h" 25 | 26 | TranspositionTable TT; // Our global transposition table 27 | 28 | 29 | /// TranspositionTable::resize() sets the size of the transposition table, 30 | /// measured in megabytes. Transposition table consists of a power of 2 number 31 | /// of clusters and each cluster consists of ClusterSize number of TTEntry. 32 | 33 | void TranspositionTable::resize(uint64_t mbSize) { 34 | 35 | assert(msb((mbSize << 20) / sizeof(TTEntry)) < 32); 36 | 37 | uint32_t size = ClusterSize << msb((mbSize << 20) / sizeof(TTEntry[ClusterSize])); 38 | 39 | if (hashMask == size - ClusterSize) 40 | return; 41 | 42 | hashMask = size - ClusterSize; 43 | free(mem); 44 | mem = calloc(size * sizeof(TTEntry) + CACHE_LINE_SIZE - 1, 1); 45 | 46 | if (!mem) 47 | { 48 | std::cerr << "Failed to allocate " << mbSize 49 | << "MB for transposition table." << std::endl; 50 | exit(EXIT_FAILURE); 51 | } 52 | 53 | table = (TTEntry*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1)); 54 | } 55 | 56 | 57 | /// TranspositionTable::clear() overwrites the entire transposition table 58 | /// with zeroes. It is called whenever the table is resized, or when the 59 | /// user asks the program to clear the table (from the UCI interface). 60 | 61 | void TranspositionTable::clear() { 62 | 63 | std::memset(table, 0, (hashMask + ClusterSize) * sizeof(TTEntry)); 64 | } 65 | 66 | 67 | /// TranspositionTable::probe() looks up the current position in the 68 | /// transposition table. Returns a pointer to the TTEntry or NULL if 69 | /// position is not found. 70 | 71 | const TTEntry* TranspositionTable::probe(const Key key) const { 72 | 73 | TTEntry* tte = first_entry(key); 74 | uint32_t key32 = key >> 32; 75 | 76 | for (unsigned i = 0; i < ClusterSize; ++i, ++tte) 77 | if (tte->key32 == key32) 78 | { 79 | tte->generation8 = generation; // Refresh 80 | return tte; 81 | } 82 | 83 | return NULL; 84 | } 85 | 86 | 87 | /// TranspositionTable::store() writes a new entry containing position key and 88 | /// valuable information of current position. The lowest order bits of position 89 | /// key are used to decide in which cluster the position will be placed. 90 | /// When a new entry is written and there are no empty entries available in the 91 | /// cluster, it replaces the least valuable of the entries. A TTEntry t1 is considered 92 | /// to be more valuable than a TTEntry t2 if t1 is from the current search and t2 93 | /// is from a previous search, or if the depth of t1 is bigger than the depth of t2. 94 | 95 | void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m, Value statV) { 96 | 97 | TTEntry *tte, *replace; 98 | uint32_t key32 = key >> 32; // Use the high 32 bits as key inside the cluster 99 | 100 | tte = replace = first_entry(key); 101 | 102 | for (unsigned i = 0; i < ClusterSize; ++i, ++tte) 103 | { 104 | if (!tte->key32 || tte->key32 == key32) // Empty or overwrite old 105 | { 106 | if (!m) 107 | m = tte->move(); // Preserve any existing ttMove 108 | 109 | replace = tte; 110 | break; 111 | } 112 | 113 | // Implement replace strategy 114 | if ( ( tte->generation8 == generation || tte->bound() == BOUND_EXACT) 115 | - (replace->generation8 == generation) 116 | - (tte->depth16 < replace->depth16) < 0) 117 | replace = tte; 118 | } 119 | 120 | replace->save(key32, v, b, d, m, generation, statV); 121 | } 122 | -------------------------------------------------------------------------------- /src/tt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef TT_H_INCLUDED 21 | #define TT_H_INCLUDED 22 | 23 | #include "misc.h" 24 | #include "types.h" 25 | 26 | /// The TTEntry is the 14 bytes transposition table entry, defined as below: 27 | /// 28 | /// key 32 bit 29 | /// move 16 bit 30 | /// bound type 8 bit 31 | /// generation 8 bit 32 | /// value 16 bit 33 | /// depth 16 bit 34 | /// eval value 16 bit 35 | 36 | struct TTEntry { 37 | 38 | Move move() const { return (Move )move16; } 39 | Bound bound() const { return (Bound)bound8; } 40 | Value value() const { return (Value)value16; } 41 | Depth depth() const { return (Depth)depth16; } 42 | Value eval_value() const { return (Value)evalValue; } 43 | 44 | private: 45 | friend class TranspositionTable; 46 | 47 | void save(uint32_t k, Value v, Bound b, Depth d, Move m, uint8_t g, Value ev) { 48 | 49 | key32 = (uint32_t)k; 50 | move16 = (uint16_t)m; 51 | bound8 = (uint8_t)b; 52 | generation8 = (uint8_t)g; 53 | value16 = (int16_t)v; 54 | depth16 = (int16_t)d; 55 | evalValue = (int16_t)ev; 56 | } 57 | 58 | uint32_t key32; 59 | uint16_t move16; 60 | uint8_t bound8, generation8; 61 | int16_t value16, depth16, evalValue; 62 | }; 63 | 64 | 65 | /// A TranspositionTable consists of a power of 2 number of clusters and each 66 | /// cluster consists of ClusterSize number of TTEntry. Each non-empty entry 67 | /// contains information of exactly one position. The size of a cluster should 68 | /// not be bigger than a cache line size. In case it is less, it should be padded 69 | /// to guarantee always aligned accesses. 70 | 71 | class TranspositionTable { 72 | 73 | static const unsigned ClusterSize = 4; 74 | 75 | public: 76 | ~TranspositionTable() { free(mem); } 77 | void new_search() { ++generation; } 78 | 79 | const TTEntry* probe(const Key key) const; 80 | TTEntry* first_entry(const Key key) const; 81 | void resize(uint64_t mbSize); 82 | void clear(); 83 | void store(const Key key, Value v, Bound type, Depth d, Move m, Value statV); 84 | 85 | private: 86 | uint32_t hashMask; 87 | TTEntry* table; 88 | void* mem; 89 | uint8_t generation; // Size must be not bigger than TTEntry::generation8 90 | }; 91 | 92 | extern TranspositionTable TT; 93 | 94 | 95 | /// TranspositionTable::first_entry() returns a pointer to the first entry of 96 | /// a cluster given a position. The lowest order bits of the key are used to 97 | /// get the index of the cluster. 98 | 99 | inline TTEntry* TranspositionTable::first_entry(const Key key) const { 100 | 101 | return table + ((uint32_t)key & hashMask); 102 | } 103 | 104 | #endif // #ifndef TT_H_INCLUDED 105 | -------------------------------------------------------------------------------- /src/uci.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "evaluate.h" 26 | #include "notation.h" 27 | #include "position.h" 28 | #include "search.h" 29 | #include "thread.h" 30 | #include "tt.h" 31 | #include "ucioption.h" 32 | 33 | using namespace std; 34 | 35 | extern void benchmark(const Position& pos, istream& is); 36 | 37 | namespace { 38 | 39 | // FEN string of the initial position, normal chess 40 | const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; 41 | 42 | // Keep a track of the position keys along the setup moves (from the start position 43 | // to the position just before the search starts). This is needed by the repetition 44 | // draw detection code. 45 | Search::StateStackPtr SetupStates; 46 | Position currentPos; 47 | 48 | // position() is called when engine receives the "position" UCI command. 49 | // The function sets up the position described in the given FEN string ("fen") 50 | // or the starting position ("startpos") and then makes the moves given in the 51 | // following move list ("moves"). 52 | 53 | void position(Position& pos, istringstream& is) { 54 | 55 | Move m; 56 | string token, fen; 57 | 58 | is >> token; 59 | 60 | if (token == "startpos") 61 | { 62 | fen = StartFEN; 63 | is >> token; // Consume "moves" token if any 64 | } 65 | else if (token == "fen") 66 | while (is >> token && token != "moves") 67 | fen += token + " "; 68 | else 69 | return; 70 | 71 | pos.set(fen, Options["UCI_Chess960"], Threads.main()); 72 | SetupStates = Search::StateStackPtr(new std::stack()); 73 | 74 | // Parse move list (if any) 75 | while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE) 76 | { 77 | SetupStates->push(StateInfo()); 78 | pos.do_move(m, SetupStates->top()); 79 | } 80 | } 81 | 82 | 83 | // setoption() is called when engine receives the "setoption" UCI command. The 84 | // function updates the UCI option ("name") to the given value ("value"). 85 | 86 | void setoption(istringstream& is) { 87 | 88 | string token, name, value; 89 | 90 | is >> token; // Consume "name" token 91 | 92 | // Read option name (can contain spaces) 93 | while (is >> token && token != "value") 94 | name += string(" ", !name.empty()) + token; 95 | 96 | // Read option value (can contain spaces) 97 | while (is >> token) 98 | value += string(" ", !value.empty()) + token; 99 | 100 | if (Options.count(name)) 101 | Options[name] = value; 102 | else 103 | sync_cout << "No such option: " << name << sync_endl; 104 | } 105 | 106 | 107 | // go() is called when engine receives the "go" UCI command. The function sets 108 | // the thinking time and other parameters from the input string, and starts 109 | // the search. 110 | 111 | void go(const Position& pos, istringstream& is) { 112 | 113 | Search::LimitsType limits; 114 | string token; 115 | 116 | while (is >> token) 117 | { 118 | if (token == "searchmoves") 119 | while (is >> token) 120 | limits.searchmoves.push_back(move_from_uci(pos, token)); 121 | 122 | else if (token == "wtime") is >> limits.time[WHITE]; 123 | else if (token == "btime") is >> limits.time[BLACK]; 124 | else if (token == "winc") is >> limits.inc[WHITE]; 125 | else if (token == "binc") is >> limits.inc[BLACK]; 126 | else if (token == "movestogo") is >> limits.movestogo; 127 | else if (token == "depth") is >> limits.depth; 128 | else if (token == "nodes") is >> limits.nodes; 129 | else if (token == "movetime") is >> limits.movetime; 130 | else if (token == "mate") is >> limits.mate; 131 | else if (token == "infinite") limits.infinite = true; 132 | else if (token == "ponder") limits.ponder = true; 133 | } 134 | 135 | Threads.start_thinking(pos, limits, SetupStates); 136 | } 137 | 138 | } // namespace 139 | 140 | 141 | /// Wait for a command from the user, parse this text string as an UCI command, 142 | /// and call the appropriate functions. Also intercepts EOF from stdin to ensure 143 | /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI 144 | /// commands, the function also supports a few debug commands. 145 | 146 | void UCI::commandInit() { 147 | currentPos = Position(StartFEN, false, Threads.main()); // The root position 148 | } 149 | 150 | void UCI::command(const string& cmd) { 151 | istringstream is(cmd); 152 | 153 | string token; 154 | is >> skipws >> token; 155 | 156 | if (token == "quit" || token == "stop" || token == "ponderhit") 157 | { 158 | // The GUI sends 'ponderhit' to tell us to ponder on the same move the 159 | // opponent has played. In case Signals.stopOnPonderhit is set we are 160 | // waiting for 'ponderhit' to stop the search (for instance because we 161 | // already ran out of time), otherwise we should continue searching but 162 | // switch from pondering to normal search. 163 | if (token != "ponderhit" || Search::Signals.stopOnPonderhit) 164 | { 165 | Search::Signals.stop = true; 166 | Threads.main()->notify_one(); // Could be sleeping 167 | } 168 | else 169 | Search::Limits.ponder = false; 170 | } 171 | else if (token == "perft" || token == "divide") 172 | { 173 | int depth; 174 | stringstream ss; 175 | 176 | is >> depth; 177 | ss << Options["Hash"] << " " 178 | << Options["Threads"] << " " << depth << " current " << token; 179 | 180 | benchmark(currentPos, ss); 181 | } 182 | else if (token == "key") 183 | sync_cout << hex << uppercase << setfill('0') 184 | << "position key: " << setw(16) << currentPos.key() 185 | << "\nmaterial key: " << setw(16) << currentPos.material_key() 186 | << "\npawn key: " << setw(16) << currentPos.pawn_key() 187 | << dec << nouppercase << setfill(' ') << sync_endl; 188 | 189 | else if (token == "uci") 190 | sync_cout << "id name " << engine_info(true) 191 | << "\n" << Options 192 | << "\nuciok" << sync_endl; 193 | 194 | else if (token == "eval") 195 | { 196 | Search::RootColor = currentPos.side_to_move(); // Ensure it is set 197 | sync_cout << Eval::trace(currentPos) << sync_endl; 198 | } 199 | else if (token == "ucinewgame") TT.clear(); 200 | else if (token == "go") go(currentPos, is); 201 | else if (token == "position") position(currentPos, is); 202 | else if (token == "setoption") setoption(is); 203 | else if (token == "flip") currentPos.flip(); 204 | else if (token == "bench") benchmark(currentPos, is); 205 | else if (token == "d") sync_cout << currentPos.pretty() << sync_endl; 206 | else if (token == "isready") sync_cout << "readyok" << sync_endl; 207 | else 208 | sync_cout << "Unknown command: " << cmd << sync_endl; 209 | } 210 | -------------------------------------------------------------------------------- /src/ucioption.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "evaluate.h" 26 | #include "misc.h" 27 | #include "thread.h" 28 | #include "tt.h" 29 | #include "ucioption.h" 30 | 31 | using std::string; 32 | 33 | UCI::OptionsMap Options; // Global object 34 | 35 | namespace UCI { 36 | 37 | /// 'On change' actions, triggered by an option's value change 38 | void on_logger(const Option& o) { start_logger(o); } 39 | void on_eval(const Option&) { Eval::init(); } 40 | void on_threads(const Option&) { Threads.read_uci_options(); } 41 | void on_hash_size(const Option& o) { TT.resize(o); } 42 | void on_clear_hash(const Option&) { TT.clear(); } 43 | 44 | 45 | /// Our case insensitive less() function as required by UCI protocol 46 | bool ci_less(char c1, char c2) { return tolower(c1) < tolower(c2); } 47 | 48 | bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { 49 | return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), ci_less); 50 | } 51 | 52 | 53 | /// init() initializes the UCI options to their hard-coded default values 54 | 55 | void init(OptionsMap& o) { 56 | 57 | o["Write Debug Log"] << Option(false, on_logger); 58 | o["Write Search Log"] << Option(false); 59 | o["Search Log Filename"] << Option("SearchLog.txt"); 60 | o["Book File"] << Option("book.bin"); 61 | o["Best Book Move"] << Option(false); 62 | o["Contempt Factor"] << Option(0, -50, 50); 63 | o["Mobility (Midgame)"] << Option(100, 0, 200, on_eval); 64 | o["Mobility (Endgame)"] << Option(100, 0, 200, on_eval); 65 | o["Pawn Structure (Midgame)"] << Option(100, 0, 200, on_eval); 66 | o["Pawn Structure (Endgame)"] << Option(100, 0, 200, on_eval); 67 | o["Passed Pawns (Midgame)"] << Option(100, 0, 200, on_eval); 68 | o["Passed Pawns (Endgame)"] << Option(100, 0, 200, on_eval); 69 | o["Space"] << Option(100, 0, 200, on_eval); 70 | o["Aggressiveness"] << Option(100, 0, 200, on_eval); 71 | o["Cowardice"] << Option(100, 0, 200, on_eval); 72 | o["Min Split Depth"] << Option(0, 0, 12, on_threads); 73 | o["Threads"] << Option(1, 1, MAX_THREADS, on_threads); 74 | o["Hash"] << Option(32, 1, 16384, on_hash_size); 75 | o["Clear Hash"] << Option(on_clear_hash); 76 | o["Ponder"] << Option(true); 77 | o["OwnBook"] << Option(false); 78 | o["MultiPV"] << Option(1, 1, 500); 79 | o["Skill Level"] << Option(20, 0, 20); 80 | o["Emergency Move Horizon"] << Option(40, 0, 50); 81 | o["Emergency Base Time"] << Option(60, 0, 30000); 82 | o["Emergency Move Time"] << Option(30, 0, 5000); 83 | o["Minimum Thinking Time"] << Option(20, 0, 5000); 84 | o["Slow Mover"] << Option(80, 10, 1000); 85 | o["UCI_Chess960"] << Option(false); 86 | } 87 | 88 | 89 | /// operator<<() is used to print all the options default values in chronological 90 | /// insertion order (the idx field) and in the format defined by the UCI protocol. 91 | 92 | std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { 93 | 94 | for (size_t idx = 0; idx < om.size(); ++idx) 95 | for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it) 96 | if (it->second.idx == idx) 97 | { 98 | const Option& o = it->second; 99 | os << "\noption name " << it->first << " type " << o.type; 100 | 101 | if (o.type != "button") 102 | os << " default " << o.defaultValue; 103 | 104 | if (o.type == "spin") 105 | os << " min " << o.min << " max " << o.max; 106 | 107 | break; 108 | } 109 | return os; 110 | } 111 | 112 | 113 | /// Option class constructors and conversion operators 114 | 115 | Option::Option(const char* v, OnChange f) : type("string"), min(0), max(0), on_change(f) 116 | { defaultValue = currentValue = v; } 117 | 118 | Option::Option(bool v, OnChange f) : type("check"), min(0), max(0), on_change(f) 119 | { defaultValue = currentValue = (v ? "true" : "false"); } 120 | 121 | Option::Option(OnChange f) : type("button"), min(0), max(0), on_change(f) 122 | {} 123 | 124 | Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), on_change(f) 125 | { std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); } 126 | 127 | 128 | Option::operator int() const { 129 | assert(type == "check" || type == "spin"); 130 | return (type == "spin" ? atoi(currentValue.c_str()) : currentValue == "true"); 131 | } 132 | 133 | Option::operator std::string() const { 134 | assert(type == "string"); 135 | return currentValue; 136 | } 137 | 138 | 139 | /// operator<<() inits options and assigns idx in the correct printing order 140 | 141 | void Option::operator<<(const Option& o) { 142 | 143 | static size_t insert_order = 0; 144 | 145 | *this = o; 146 | idx = insert_order++; 147 | } 148 | 149 | 150 | /// operator=() updates currentValue and triggers on_change() action. It's up to 151 | /// the GUI to check for option's limits, but we could receive the new value from 152 | /// the user by console window, so let's check the bounds anyway. 153 | 154 | Option& Option::operator=(const string& v) { 155 | 156 | assert(!type.empty()); 157 | 158 | if ( (type != "button" && v.empty()) 159 | || (type == "check" && v != "true" && v != "false") 160 | || (type == "spin" && (atoi(v.c_str()) < min || atoi(v.c_str()) > max))) 161 | return *this; 162 | 163 | if (type != "button") 164 | currentValue = v; 165 | 166 | if (on_change) 167 | on_change(*this); 168 | 169 | return *this; 170 | } 171 | 172 | } // namespace UCI 173 | -------------------------------------------------------------------------------- /src/ucioption.h: -------------------------------------------------------------------------------- 1 | /* 2 | Stockfish, a UCI chess playing engine derived from Glaurung 2.1 3 | Copyright (C) 2004-2008 Tord Romstad (Glaurung author) 4 | Copyright (C) 2008-2014 Marco Costalba, Joona Kiiski, Tord Romstad 5 | 6 | Stockfish is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | Stockfish is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef UCIOPTION_H_INCLUDED 21 | #define UCIOPTION_H_INCLUDED 22 | 23 | #include 24 | #include 25 | 26 | namespace UCI { 27 | 28 | class Option; 29 | 30 | /// Custom comparator because UCI options should be case insensitive 31 | struct CaseInsensitiveLess { 32 | bool operator() (const std::string&, const std::string&) const; 33 | }; 34 | 35 | /// Our options container is actually a std::map 36 | typedef std::map OptionsMap; 37 | 38 | /// Option class implements an option as defined by UCI protocol 39 | class Option { 40 | 41 | typedef void (*OnChange)(const Option&); 42 | 43 | public: 44 | Option(OnChange = NULL); 45 | Option(bool v, OnChange = NULL); 46 | Option(const char* v, OnChange = NULL); 47 | Option(int v, int min, int max, OnChange = NULL); 48 | 49 | Option& operator=(const std::string& v); 50 | void operator<<(const Option& o); 51 | operator int() const; 52 | operator std::string() const; 53 | 54 | private: 55 | friend std::ostream& operator<<(std::ostream&, const OptionsMap&); 56 | 57 | std::string defaultValue, currentValue, type; 58 | int min, max; 59 | size_t idx; 60 | OnChange on_change; 61 | }; 62 | 63 | void init(OptionsMap&); 64 | void commandInit(); 65 | void command(const std::string&); 66 | 67 | } // namespace UCI 68 | 69 | extern UCI::OptionsMap Options; 70 | 71 | #endif // #ifndef UCIOPTION_H_INCLUDED 72 | -------------------------------------------------------------------------------- /stockfishjs: -------------------------------------------------------------------------------- 1 | node $(dirname $0)/src/stockfish.js 2 | --------------------------------------------------------------------------------