2008-08-31 23:59:13 -06:00
|
|
|
/*
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
Add NNUE evaluation
This patch ports the efficiently updatable neural network (NNUE) evaluation to Stockfish.
Both the NNUE and the classical evaluations are available, and can be used to
assign a value to a position that is later used in alpha-beta (PVS) search to find the
best move. The classical evaluation computes this value as a function of various chess
concepts, handcrafted by experts, tested and tuned using fishtest. The NNUE evaluation
computes this value with a neural network based on basic inputs. The network is optimized
and trained on the evalutions of millions of positions at moderate search depth.
The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward.
It can be evaluated efficiently on CPUs, and exploits the fact that only parts
of the neural network need to be updated after a typical chess move.
[The nodchip repository](https://github.com/nodchip/Stockfish) provides additional
tools to train and develop the NNUE networks.
This patch is the result of contributions of various authors, from various communities,
including: nodchip, ynasu87, yaneurao (initial port and NNUE authors), domschl, FireFather,
rqs, xXH4CKST3RXx, tttak, zz4032, joergoster, mstembera, nguyenpham, erbsenzaehler,
dorzechowski, and vondele.
This new evaluation needed various changes to fishtest and the corresponding infrastructure,
for which tomtor, ppigazzini, noobpwnftw, daylen, and vondele are gratefully acknowledged.
The first networks have been provided by gekkehenker and sergiovieri, with the latter
net (nn-97f742aaefcd.nnue) being the current default.
The evaluation function can be selected at run time with the `Use NNUE` (true/false) UCI option,
provided the `EvalFile` option points the the network file (depending on the GUI, with full path).
The performance of the NNUE evaluation relative to the classical evaluation depends somewhat on
the hardware, and is expected to improve quickly, but is currently on > 80 Elo on fishtest:
60000 @ 10+0.1 th 1
https://tests.stockfishchess.org/tests/view/5f28fe6ea5abc164f05e4c4c
ELO: 92.77 +-2.1 (95%) LOS: 100.0%
Total: 60000 W: 24193 L: 8543 D: 27264
Ptnml(0-2): 609, 3850, 9708, 10948, 4885
40000 @ 20+0.2 th 8
https://tests.stockfishchess.org/tests/view/5f290229a5abc164f05e4c58
ELO: 89.47 +-2.0 (95%) LOS: 100.0%
Total: 40000 W: 12756 L: 2677 D: 24567
Ptnml(0-2): 74, 1583, 8550, 7776, 2017
At the same time, the impact on the classical evaluation remains minimal, causing no significant
regression:
sprt @ 10+0.1 th 1
https://tests.stockfishchess.org/tests/view/5f2906a2a5abc164f05e4c5b
LLR: 2.94 (-2.94,2.94) {-6.00,-4.00}
Total: 34936 W: 6502 L: 6825 D: 21609
Ptnml(0-2): 571, 4082, 8434, 3861, 520
sprt @ 60+0.6 th 1
https://tests.stockfishchess.org/tests/view/5f2906cfa5abc164f05e4c5d
LLR: 2.93 (-2.94,2.94) {-6.00,-4.00}
Total: 10088 W: 1232 L: 1265 D: 7591
Ptnml(0-2): 49, 914, 3170, 843, 68
The needed networks can be found at https://tests.stockfishchess.org/nns
It is recommended to use the default one as indicated by the `EvalFile` UCI option.
Guidelines for testing new nets can be found at
https://github.com/glinscott/fishtest/wiki/Creating-my-first-test#nnue-net-tests
Integration has been discussed in various issues:
https://github.com/official-stockfish/Stockfish/issues/2823
https://github.com/official-stockfish/Stockfish/issues/2728
The integration branch will be closed after the merge:
https://github.com/official-stockfish/Stockfish/pull/2825
https://github.com/official-stockfish/Stockfish/tree/nnue-player-wip
closes https://github.com/official-stockfish/Stockfish/pull/2912
This will be an exciting time for computer chess, looking forward to seeing the evolution of
this approach.
Bench: 4746616
2020-08-05 09:11:15 -06:00
|
|
|
Copyright (C) 2004-2020 The Stockfish developers (see AUTHORS file)
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
2008-08-31 23:59:13 -06:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2008-10-20 13:57:13 -06:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
2008-08-31 23:59:13 -06:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2008-10-20 13:57:13 -06:00
|
|
|
|
2008-08-31 23:59:13 -06:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-01-05 02:50:51 -07:00
|
|
|
#include <cassert>
|
2008-08-31 23:59:13 -06:00
|
|
|
|
|
|
|
#include "movegen.h"
|
2011-07-16 15:59:14 -06:00
|
|
|
#include "position.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
|
|
|
|
namespace {
|
2008-10-18 09:37:49 -06:00
|
|
|
|
2017-12-04 09:52:31 -07:00
|
|
|
template<GenType Type, Direction D>
|
2016-07-03 02:35:44 -06:00
|
|
|
ExtMove* make_promotions(ExtMove* moveList, Square to, Square ksq) {
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2014-12-24 03:36:04 -07:00
|
|
|
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
Simplify make_promotions()
Remove special case handling of QUIET_CHECKS in make_promotions()
STC https://tests.stockfishchess.org/tests/view/5f055dbb59f6f035328945fb
LLR: 2.98 (-2.94,2.94) {-1.50,0.50}
Total: 42808 W: 8177 L: 8054 D: 26577
Ptnml(0-2): 665, 4890, 10201, 4953, 695
LTC https://tests.stockfishchess.org/tests/view/5f06231a59f6f03532894661
LLR: 2.96 (-2.94,2.94) {-1.50,0.50}
Total: 9616 W: 1214 L: 1111 D: 7291
Ptnml(0-2): 53, 821, 2965, 908, 61
closes https://github.com/official-stockfish/Stockfish/pull/2800
Bench: 4576410
2020-07-05 16:17:04 -06:00
|
|
|
{
|
2016-09-23 11:28:34 -06:00
|
|
|
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
|
Simplify make_promotions()
Remove special case handling of QUIET_CHECKS in make_promotions()
STC https://tests.stockfishchess.org/tests/view/5f055dbb59f6f035328945fb
LLR: 2.98 (-2.94,2.94) {-1.50,0.50}
Total: 42808 W: 8177 L: 8054 D: 26577
Ptnml(0-2): 665, 4890, 10201, 4953, 695
LTC https://tests.stockfishchess.org/tests/view/5f06231a59f6f03532894661
LLR: 2.96 (-2.94,2.94) {-1.50,0.50}
Total: 9616 W: 1214 L: 1111 D: 7291
Ptnml(0-2): 53, 821, 2965, 908, 61
closes https://github.com/official-stockfish/Stockfish/pull/2800
Bench: 4576410
2020-07-05 16:17:04 -06:00
|
|
|
if (attacks_bb<KNIGHT>(to) & ksq)
|
|
|
|
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
|
|
|
}
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2014-12-24 03:36:04 -07:00
|
|
|
if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2016-09-23 11:28:34 -06:00
|
|
|
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
|
|
|
|
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
|
Simplify make_promotions()
Remove special case handling of QUIET_CHECKS in make_promotions()
STC https://tests.stockfishchess.org/tests/view/5f055dbb59f6f035328945fb
LLR: 2.98 (-2.94,2.94) {-1.50,0.50}
Total: 42808 W: 8177 L: 8054 D: 26577
Ptnml(0-2): 665, 4890, 10201, 4953, 695
LTC https://tests.stockfishchess.org/tests/view/5f06231a59f6f03532894661
LLR: 2.96 (-2.94,2.94) {-1.50,0.50}
Total: 9616 W: 1214 L: 1111 D: 7291
Ptnml(0-2): 53, 821, 2965, 908, 61
closes https://github.com/official-stockfish/Stockfish/pull/2800
Bench: 4576410
2020-07-05 16:17:04 -06:00
|
|
|
if (!(attacks_bb<KNIGHT>(to) & ksq))
|
|
|
|
*moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
|
2012-01-04 06:10:53 -07:00
|
|
|
}
|
2012-01-14 15:01:09 -07:00
|
|
|
|
2015-09-27 02:53:39 -06:00
|
|
|
return moveList;
|
2012-01-04 06:10:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
template<Color Us, GenType Type>
|
2016-07-03 02:35:44 -06:00
|
|
|
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2020-03-30 14:45:35 -06:00
|
|
|
constexpr Color Them = ~Us;
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
|
|
|
constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
2019-10-31 10:17:46 -06:00
|
|
|
constexpr Direction Up = pawn_push(Us);
|
2018-03-18 16:38:58 -06:00
|
|
|
constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST);
|
|
|
|
constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2019-10-18 18:20:38 -06:00
|
|
|
const Square ksq = pos.square<KING>(Them);
|
2014-12-24 03:36:04 -07:00
|
|
|
Bitboard emptySquares;
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-05-01 05:01:38 -06:00
|
|
|
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
|
|
|
|
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target:
|
|
|
|
Type == CAPTURES ? target : pos.pieces(Them));
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-01-04 08:40:12 -07:00
|
|
|
// Single and double pawn pushes, no promotions
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type != CAPTURES)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2012-09-09 06:30:22 -06:00
|
|
|
emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2016-09-23 11:28:34 -06:00
|
|
|
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
|
|
|
|
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type == EVASIONS) // Consider only blocking squares
|
2012-01-04 08:40:12 -07:00
|
|
|
{
|
2012-01-05 02:50:51 -07:00
|
|
|
b1 &= target;
|
2012-01-04 08:40:12 -07:00
|
|
|
b2 &= target;
|
|
|
|
}
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type == QUIET_CHECKS)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2020-05-28 09:48:31 -06:00
|
|
|
b1 &= pawn_attacks_bb(Them, ksq);
|
|
|
|
b2 &= pawn_attacks_bb(Them, ksq);
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-01-04 08:40:12 -07:00
|
|
|
// Add pawn pushes which give discovered check. This is possible only
|
2012-01-04 06:10:53 -07:00
|
|
|
// if the pawn is not on the same file as the enemy king, because we
|
2012-01-04 08:40:12 -07:00
|
|
|
// don't generate captures. Note that a possible discovery check
|
2013-12-02 11:04:09 -07:00
|
|
|
// promotion has been already generated amongst the captures.
|
2019-01-14 07:03:31 -07:00
|
|
|
Bitboard dcCandidateQuiets = pos.blockers_for_king(Them) & pawnsNotOn7;
|
|
|
|
if (dcCandidateQuiets)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2019-01-14 07:03:31 -07:00
|
|
|
Bitboard dc1 = shift<Up>(dcCandidateQuiets) & emptySquares & ~file_bb(ksq);
|
2016-09-23 11:28:34 -06:00
|
|
|
Bitboard dc2 = shift<Up>(dc1 & TRank3BB) & emptySquares;
|
2012-01-04 06:10:53 -07:00
|
|
|
|
|
|
|
b1 |= dc1;
|
|
|
|
b2 |= dc2;
|
|
|
|
}
|
|
|
|
}
|
2012-01-04 08:40:12 -07:00
|
|
|
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b1)
|
|
|
|
{
|
|
|
|
Square to = pop_lsb(&b1);
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(to - Up, to);
|
2014-03-09 04:03:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
while (b2)
|
|
|
|
{
|
|
|
|
Square to = pop_lsb(&b2);
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(to - Up - Up, to);
|
2014-03-09 04:03:02 -06:00
|
|
|
}
|
2012-01-04 06:10:53 -07:00
|
|
|
}
|
|
|
|
|
2012-01-04 08:40:12 -07:00
|
|
|
// Promotions and underpromotions
|
2019-01-01 05:35:53 -07:00
|
|
|
if (pawnsOn7)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type == CAPTURES)
|
2012-03-18 04:10:12 -06:00
|
|
|
emptySquares = ~pos.pieces();
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type == EVASIONS)
|
2012-01-04 08:40:12 -07:00
|
|
|
emptySquares &= target;
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2018-02-21 13:46:25 -07:00
|
|
|
Bitboard b1 = shift<UpRight>(pawnsOn7) & enemies;
|
|
|
|
Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies;
|
|
|
|
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
|
2014-12-24 03:36:04 -07:00
|
|
|
|
|
|
|
while (b1)
|
2018-02-21 13:46:25 -07:00
|
|
|
moveList = make_promotions<Type, UpRight>(moveList, pop_lsb(&b1), ksq);
|
2014-12-24 03:36:04 -07:00
|
|
|
|
|
|
|
while (b2)
|
2018-02-21 13:46:25 -07:00
|
|
|
moveList = make_promotions<Type, UpLeft >(moveList, pop_lsb(&b2), ksq);
|
2014-12-24 03:36:04 -07:00
|
|
|
|
|
|
|
while (b3)
|
2018-02-21 13:46:25 -07:00
|
|
|
moveList = make_promotions<Type, Up >(moveList, pop_lsb(&b3), ksq);
|
2012-01-04 08:40:12 -07:00
|
|
|
}
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-01-04 08:40:12 -07:00
|
|
|
// Standard and en-passant captures
|
2012-06-24 03:08:16 -06:00
|
|
|
if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
|
2012-01-04 08:40:12 -07:00
|
|
|
{
|
2018-02-21 13:46:25 -07:00
|
|
|
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
|
|
|
|
Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies;
|
2012-01-17 13:31:49 -07:00
|
|
|
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b1)
|
|
|
|
{
|
|
|
|
Square to = pop_lsb(&b1);
|
2018-02-21 13:46:25 -07:00
|
|
|
*moveList++ = make_move(to - UpRight, to);
|
2014-03-09 04:03:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
while (b2)
|
|
|
|
{
|
|
|
|
Square to = pop_lsb(&b2);
|
2018-02-21 13:46:25 -07:00
|
|
|
*moveList++ = make_move(to - UpLeft, to);
|
2014-03-09 04:03:02 -06:00
|
|
|
}
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2012-01-04 08:40:12 -07:00
|
|
|
if (pos.ep_square() != SQ_NONE)
|
2012-01-04 06:10:53 -07:00
|
|
|
{
|
2012-01-17 13:31:49 -07:00
|
|
|
assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6));
|
2012-01-04 08:40:12 -07:00
|
|
|
|
|
|
|
// An en passant capture can be an evasion only if the checking piece
|
|
|
|
// is the double pushed pawn and so is in the target. Otherwise this
|
|
|
|
// is a discovery check and we are forced to do otherwise.
|
2013-06-16 02:08:44 -06:00
|
|
|
if (Type == EVASIONS && !(target & (pos.ep_square() - Up)))
|
2014-12-07 16:53:33 -07:00
|
|
|
return moveList;
|
2012-01-04 08:40:12 -07:00
|
|
|
|
2020-05-28 09:48:31 -06:00
|
|
|
b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square());
|
2012-01-04 08:40:12 -07:00
|
|
|
|
|
|
|
assert(b1);
|
|
|
|
|
|
|
|
while (b1)
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make<ENPASSANT>(pop_lsb(&b1), pos.ep_square());
|
2012-01-04 06:10:53 -07:00
|
|
|
}
|
|
|
|
}
|
2012-01-04 08:40:12 -07:00
|
|
|
|
2014-12-07 16:53:33 -07:00
|
|
|
return moveList;
|
2012-01-04 06:10:53 -07:00
|
|
|
}
|
2009-02-10 09:31:07 -07:00
|
|
|
|
2009-02-10 09:44:55 -07:00
|
|
|
|
2020-06-03 18:06:49 -06:00
|
|
|
template<Color Us, PieceType Pt, bool Checks>
|
|
|
|
ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
|
2012-08-22 03:13:09 -06:00
|
|
|
|
2019-10-18 18:20:38 -06:00
|
|
|
static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
|
2011-01-05 01:49:58 -07:00
|
|
|
|
Remove piece lists
This patch removes the incrementally updated piece lists from the Position object.
This has been tried before but always failed. My reasons for trying again are:
* 32-bit systems (including phones) are now much less important than they were some years ago (and are absent from fishtest);
* NNUE may have made SF less finely tuned to the order in which moves were generated.
STC:
LLR: 2.94 (-2.94,2.94) {-1.25,0.25}
Total: 55272 W: 5260 L: 5216 D: 44796
Ptnml(0-2): 208, 4147, 18898, 4159, 224
https://tests.stockfishchess.org/tests/view/5fc2986a42a050a89f02c926
LTC:
LLR: 2.96 (-2.94,2.94) {-0.75,0.25}
Total: 16600 W: 673 L: 608 D: 15319
Ptnml(0-2): 14, 533, 7138, 604, 11
https://tests.stockfishchess.org/tests/view/5fc2f98342a050a89f02c95c
closes https://github.com/official-stockfish/Stockfish/pull/3247
Bench: 3940967
2020-11-29 04:05:26 -07:00
|
|
|
Bitboard bb = pos.pieces(Us, Pt);
|
|
|
|
|
|
|
|
while (bb) {
|
|
|
|
Square from = pop_lsb(&bb);
|
2011-01-05 01:49:58 -07:00
|
|
|
|
2012-09-09 06:30:22 -06:00
|
|
|
if (Checks)
|
2012-08-22 03:13:09 -06:00
|
|
|
{
|
|
|
|
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
|
2020-05-28 09:48:31 -06:00
|
|
|
&& !(attacks_bb<Pt>(from) & target & pos.check_squares(Pt)))
|
2012-08-22 03:13:09 -06:00
|
|
|
continue;
|
2011-01-05 01:49:58 -07:00
|
|
|
|
2020-06-03 18:06:49 -06:00
|
|
|
if (pos.blockers_for_king(~Us) & from)
|
2012-08-22 03:13:09 -06:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-05 01:49:58 -07:00
|
|
|
|
2020-05-28 09:48:31 -06:00
|
|
|
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
|
2009-02-10 09:44:55 -07:00
|
|
|
|
2012-09-09 06:30:22 -06:00
|
|
|
if (Checks)
|
2016-08-27 02:05:42 -06:00
|
|
|
b &= pos.check_squares(Pt);
|
2012-01-04 06:10:53 -07:00
|
|
|
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b)
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(from, pop_lsb(&b));
|
2012-08-22 01:29:49 -06:00
|
|
|
}
|
2012-01-14 15:01:09 -07:00
|
|
|
|
2014-12-07 16:53:33 -07:00
|
|
|
return moveList;
|
2011-01-05 01:49:58 -07:00
|
|
|
}
|
2009-09-23 04:29:10 -06:00
|
|
|
|
2012-09-09 06:30:22 -06:00
|
|
|
|
Retire FORCE_INLINE
No speed regression on my machine (i7-3770k, gcc 4.9.1, linux 3.16):
stat test master diff
mean 2,482,415 2,474,987 7,906
stdev 4,603 5,644 2,497
speedup 0.32%
P(speedup>0) 100.0%
Fishtest 9+0.03:
ELO: 0.26 +-1.8 (95%) LOS: 61.2%
Total: 60000 W: 12437 L: 12392 D: 35171
No functional change.
Resolves #334
2015-04-15 14:21:45 -06:00
|
|
|
template<Color Us, GenType Type>
|
2020-05-23 05:26:13 -06:00
|
|
|
ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
|
2019-01-02 00:31:03 -07:00
|
|
|
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
|
2020-05-23 05:26:13 -06:00
|
|
|
Bitboard target;
|
|
|
|
|
|
|
|
switch (Type)
|
|
|
|
{
|
|
|
|
case CAPTURES:
|
|
|
|
target = pos.pieces(~Us);
|
|
|
|
break;
|
|
|
|
case QUIETS:
|
|
|
|
case QUIET_CHECKS:
|
|
|
|
target = ~pos.pieces();
|
|
|
|
break;
|
|
|
|
case EVASIONS:
|
|
|
|
{
|
|
|
|
Square checksq = lsb(pos.checkers());
|
|
|
|
target = between_bb(pos.square<KING>(Us), checksq) | checksq;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NON_EVASIONS:
|
|
|
|
target = ~pos.pieces(Us);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
static_assert(true, "Unsupported type in generate_all()");
|
|
|
|
}
|
2012-09-09 06:30:22 -06:00
|
|
|
|
2016-07-03 02:35:44 -06:00
|
|
|
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
|
2020-06-03 18:06:49 -06:00
|
|
|
moveList = generate_moves<Us, KNIGHT, Checks>(pos, moveList, target);
|
|
|
|
moveList = generate_moves<Us, BISHOP, Checks>(pos, moveList, target);
|
|
|
|
moveList = generate_moves<Us, ROOK, Checks>(pos, moveList, target);
|
|
|
|
moveList = generate_moves<Us, QUEEN, Checks>(pos, moveList, target);
|
2012-09-09 06:30:22 -06:00
|
|
|
|
|
|
|
if (Type != QUIET_CHECKS && Type != EVASIONS)
|
2013-01-26 14:07:28 -07:00
|
|
|
{
|
2015-08-04 01:00:52 -06:00
|
|
|
Square ksq = pos.square<KING>(Us);
|
2020-05-28 09:48:31 -06:00
|
|
|
Bitboard b = attacks_bb<KING>(ksq) & target;
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b)
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(ksq, pop_lsb(&b));
|
2012-09-09 06:30:22 -06:00
|
|
|
|
2020-03-11 16:27:51 -06:00
|
|
|
if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING))
|
2020-07-11 08:59:33 -06:00
|
|
|
for (CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
|
2020-03-11 16:27:51 -06:00
|
|
|
if (!pos.castling_impeded(cr) && pos.can_castle(cr))
|
|
|
|
*moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(cr));
|
2012-09-09 06:30:22 -06:00
|
|
|
}
|
|
|
|
|
2014-12-07 16:53:33 -07:00
|
|
|
return moveList;
|
2012-09-09 06:30:22 -06:00
|
|
|
}
|
|
|
|
|
2012-01-04 06:10:53 -07:00
|
|
|
} // namespace
|
2008-08-31 23:59:13 -06:00
|
|
|
|
|
|
|
|
Simplify make_promotions()
Remove special case handling of QUIET_CHECKS in make_promotions()
STC https://tests.stockfishchess.org/tests/view/5f055dbb59f6f035328945fb
LLR: 2.98 (-2.94,2.94) {-1.50,0.50}
Total: 42808 W: 8177 L: 8054 D: 26577
Ptnml(0-2): 665, 4890, 10201, 4953, 695
LTC https://tests.stockfishchess.org/tests/view/5f06231a59f6f03532894661
LLR: 2.96 (-2.94,2.94) {-1.50,0.50}
Total: 9616 W: 1214 L: 1111 D: 7291
Ptnml(0-2): 53, 821, 2965, 908, 61
closes https://github.com/official-stockfish/Stockfish/pull/2800
Bench: 4576410
2020-07-05 16:17:04 -06:00
|
|
|
/// <CAPTURES> Generates all pseudo-legal captures plus queen and checking knight promotions
|
|
|
|
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions(except checking knight)
|
2019-02-08 02:36:03 -07:00
|
|
|
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
|
2011-01-05 11:47:01 -07:00
|
|
|
///
|
2019-02-08 02:36:03 -07:00
|
|
|
/// Returns a pointer to the end of the move list.
|
2011-01-05 11:47:01 -07:00
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
template<GenType Type>
|
2014-12-07 16:53:33 -07:00
|
|
|
ExtMove* generate(const Position& pos, ExtMove* moveList) {
|
2010-08-06 05:01:21 -06:00
|
|
|
|
2019-10-18 18:20:38 -06:00
|
|
|
static_assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS, "Unsupported type in generate()");
|
2012-12-25 09:59:35 -07:00
|
|
|
assert(!pos.checkers());
|
2010-08-06 05:01:21 -06:00
|
|
|
|
|
|
|
Color us = pos.side_to_move();
|
2012-01-03 07:16:01 -07:00
|
|
|
|
2020-05-23 05:26:13 -06:00
|
|
|
return us == WHITE ? generate_all<WHITE, Type>(pos, moveList)
|
|
|
|
: generate_all<BLACK, Type>(pos, moveList);
|
2010-08-06 05:01:21 -06:00
|
|
|
}
|
|
|
|
|
2011-04-13 03:54:41 -06:00
|
|
|
// Explicit template instantiations
|
2013-07-19 02:27:15 -06:00
|
|
|
template ExtMove* generate<CAPTURES>(const Position&, ExtMove*);
|
|
|
|
template ExtMove* generate<QUIETS>(const Position&, ExtMove*);
|
|
|
|
template ExtMove* generate<NON_EVASIONS>(const Position&, ExtMove*);
|
2011-01-05 11:47:01 -07:00
|
|
|
|
2010-08-06 05:01:21 -06:00
|
|
|
|
Simplify make_promotions()
Remove special case handling of QUIET_CHECKS in make_promotions()
STC https://tests.stockfishchess.org/tests/view/5f055dbb59f6f035328945fb
LLR: 2.98 (-2.94,2.94) {-1.50,0.50}
Total: 42808 W: 8177 L: 8054 D: 26577
Ptnml(0-2): 665, 4890, 10201, 4953, 695
LTC https://tests.stockfishchess.org/tests/view/5f06231a59f6f03532894661
LLR: 2.96 (-2.94,2.94) {-1.50,0.50}
Total: 9616 W: 1214 L: 1111 D: 7291
Ptnml(0-2): 53, 821, 2965, 908, 61
closes https://github.com/official-stockfish/Stockfish/pull/2800
Bench: 4576410
2020-07-05 16:17:04 -06:00
|
|
|
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures.
|
|
|
|
/// Returns a pointer to the end of the move list.
|
2011-01-05 11:00:30 -07:00
|
|
|
template<>
|
2014-12-07 16:53:33 -07:00
|
|
|
ExtMove* generate<QUIET_CHECKS>(const Position& pos, ExtMove* moveList) {
|
2008-10-17 07:11:19 -06:00
|
|
|
|
2012-12-25 09:59:35 -07:00
|
|
|
assert(!pos.checkers());
|
2008-10-17 07:11:19 -06:00
|
|
|
|
2013-07-29 11:01:50 -06:00
|
|
|
Color us = pos.side_to_move();
|
2020-04-12 12:30:08 -06:00
|
|
|
Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN);
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2012-01-08 07:08:20 -07:00
|
|
|
while (dc)
|
2009-11-01 02:40:14 -07:00
|
|
|
{
|
2012-07-08 01:30:37 -06:00
|
|
|
Square from = pop_lsb(&dc);
|
2012-01-08 07:08:20 -07:00
|
|
|
PieceType pt = type_of(pos.piece_on(from));
|
2012-01-05 01:27:50 -07:00
|
|
|
|
2020-05-28 09:48:31 -06:00
|
|
|
Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces();
|
2012-01-05 01:27:50 -07:00
|
|
|
|
|
|
|
if (pt == KING)
|
2020-05-28 09:48:31 -06:00
|
|
|
b &= ~attacks_bb<QUEEN>(pos.square<KING>(~us));
|
2012-01-05 01:27:50 -07:00
|
|
|
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b)
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(from, pop_lsb(&b));
|
2009-11-01 02:40:14 -07:00
|
|
|
}
|
|
|
|
|
2020-05-23 05:26:13 -06:00
|
|
|
return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList)
|
|
|
|
: generate_all<BLACK, QUIET_CHECKS>(pos, moveList);
|
2008-08-31 23:59:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
/// generate<EVASIONS> generates all pseudo-legal check evasions when the side
|
2011-12-04 02:53:40 -07:00
|
|
|
/// to move is in check. Returns a pointer to the end of the move list.
|
2011-01-05 11:00:30 -07:00
|
|
|
template<>
|
2014-12-07 16:53:33 -07:00
|
|
|
ExtMove* generate<EVASIONS>(const Position& pos, ExtMove* moveList) {
|
2008-10-17 07:11:19 -06:00
|
|
|
|
2012-12-25 09:59:35 -07:00
|
|
|
assert(pos.checkers());
|
2008-10-17 07:11:19 -06:00
|
|
|
|
2008-10-19 01:27:24 -06:00
|
|
|
Color us = pos.side_to_move();
|
2015-08-04 01:00:52 -06:00
|
|
|
Square ksq = pos.square<KING>(us);
|
2011-12-03 03:56:11 -07:00
|
|
|
Bitboard sliderAttacks = 0;
|
2014-04-28 02:30:06 -06:00
|
|
|
Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2013-12-02 11:04:09 -07:00
|
|
|
// Find all the squares attacked by slider checkers. We will remove them from
|
|
|
|
// the king evasions in order to skip known illegal moves, which avoids any
|
|
|
|
// useless legality checks later on.
|
2014-03-09 04:48:41 -06:00
|
|
|
while (sliders)
|
2020-06-06 21:25:32 -06:00
|
|
|
sliderAttacks |= line_bb(ksq, pop_lsb(&sliders)) & ~pos.checkers();
|
2009-02-07 05:11:52 -07:00
|
|
|
|
2009-09-21 11:07:11 -06:00
|
|
|
// Generate evasions for king, capture and non capture moves
|
2020-05-28 09:48:31 -06:00
|
|
|
Bitboard b = attacks_bb<KING>(ksq) & ~pos.pieces(us) & ~sliderAttacks;
|
2014-03-09 04:03:02 -06:00
|
|
|
while (b)
|
2015-02-01 08:32:21 -07:00
|
|
|
*moveList++ = make_move(ksq, pop_lsb(&b));
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2014-03-09 04:48:41 -06:00
|
|
|
if (more_than_one(pos.checkers()))
|
2014-12-07 16:53:33 -07:00
|
|
|
return moveList; // Double check, only a king move can save the day
|
2009-11-02 08:33:54 -07:00
|
|
|
|
2012-09-09 06:30:22 -06:00
|
|
|
// Generate blocking evasions or captures of the checking piece
|
2020-05-23 05:26:13 -06:00
|
|
|
return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList)
|
|
|
|
: generate_all<BLACK, EVASIONS>(pos, moveList);
|
2008-08-31 23:59:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-24 03:08:16 -06:00
|
|
|
/// generate<LEGAL> generates all the legal moves in the given position
|
2011-01-05 11:47:01 -07:00
|
|
|
|
|
|
|
template<>
|
2014-12-07 16:53:33 -07:00
|
|
|
ExtMove* generate<LEGAL>(const Position& pos, ExtMove* moveList) {
|
2008-10-17 07:11:19 -06:00
|
|
|
|
2018-02-26 17:18:33 -07:00
|
|
|
Color us = pos.side_to_move();
|
|
|
|
Bitboard pinned = pos.blockers_for_king(us) & pos.pieces(us);
|
|
|
|
Square ksq = pos.square<KING>(us);
|
2014-12-24 03:36:04 -07:00
|
|
|
ExtMove* cur = moveList;
|
2009-03-02 08:20:00 -07:00
|
|
|
|
2014-12-24 03:36:04 -07:00
|
|
|
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
|
|
|
|
: generate<NON_EVASIONS>(pos, moveList);
|
|
|
|
while (cur != moveList)
|
2015-02-01 08:32:21 -07:00
|
|
|
if ( (pinned || from_sq(*cur) == ksq || type_of(*cur) == ENPASSANT)
|
2016-07-03 02:35:44 -06:00
|
|
|
&& !pos.legal(*cur))
|
2015-02-01 08:32:21 -07:00
|
|
|
*cur = (--moveList)->move;
|
2011-04-13 03:54:41 -06:00
|
|
|
else
|
2013-10-02 22:01:38 -06:00
|
|
|
++cur;
|
2009-11-06 06:33:34 -07:00
|
|
|
|
2014-12-24 03:36:04 -07:00
|
|
|
return moveList;
|
2008-08-31 23:59:13 -06:00
|
|
|
}
|