1 /* Copyright (C) 2007-2011 Vincent Ollivier
3 * Purple Haze is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * Purple Haze is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Use lazy move generation to get the next move.
26 * Best and killers moves are added first to the moves array and we start
27 * with the best move. We then generate the captures but only if there have
28 * been no cut-off with the best move.
30 * MVV/LVA is used to pickup the best captures first by selection sort and
31 * next we try the killer moves (stored near the beginning of the moves array)
32 * before the bad captures. Which are none by the way with MVV/LVA but in
33 * the future SEE will be used for that.
35 * Finally when there is no captures left and no cut-off occurred we generate
36 * the remaining quiets moves and try them with no particular order.
38 ExtendedMove
Moves::next()
40 if (!use_lazy_generation
) {
41 if (i
== 0) generate(); // generate() will change the value of 'n'
43 if (i
== n
) return ExtendedMove();
47 switch (generation_state
) {
49 if (i
< size
[BEST
]) return moves
[i
++];
50 generation_state
= GOOD_CAPTURES
;
52 i
= size
[BEST
] + size
[KILLERS
]; // Jump to the first good capture
54 if (i
< (size
[BEST
] + size
[KILLERS
] + size
[GOOD_CAPTURES
])) break;
55 generation_state
= KILLERS
;
56 i
= size
[BEST
]; // Jump to the first killer
58 if (i
< (size
[BEST
] + size
[KILLERS
])) return moves
[i
++];
59 generation_state
= BAD_CAPTURES
;
60 i
= size
[BEST
] + size
[KILLERS
] + size
[GOOD_CAPTURES
];
63 generation_state
= QUIET_MOVES
;
66 if (i
< n
) return moves
[i
++];
68 return ExtendedMove();
71 // If we are here, next() should return a capture
72 // FIXME: Review this assert
73 assert(generation_state
== GOOD_CAPTURES
);
75 // Find the best remaining capture by selection sort
77 for (auto j
= i
+ 1; j
< n
; ++j
) {
78 if (moves
[j
].value() > moves
[max
].value()) {
83 // Swap it with the current one
85 ExtendedMove tmp
= std::move(moves
[i
]);
86 moves
[i
] = std::move(moves
[max
]);
87 moves
[max
] = std::move(tmp
);
94 void Moves::add(Move move
, MovesState mt
)
96 if (!use_lazy_generation
) {
97 moves
[n
++] = ExtendedMove(move
, 0);
101 if (move
.is_null()) return;
103 // Don't add again best and killer moves
104 auto end
= size
[BEST
] + size
[KILLERS
];
105 for (auto j
= 0; j
< end
; ++j
) if (moves
[j
] == move
) return;
107 // Calculate the move's score
115 score
= KILLERS_SCORE
- size
[KILLERS
];
119 //assert(generation_state > KILLERS);
120 //size[generation_state]++; // If move is a capture or a quiet move
123 switch (generation_state
) {
126 score
= mvv_lva_score(move
);
127 size
[generation_state
]++;
131 size
[generation_state
]++;
134 //assert(mt < GOOD_CAPTURES);
135 //size[mt]++; // If move is a best or killer move
139 // Add the move and its score to moves list
140 moves
[n
++] = ExtendedMove(move
, score
);
143 Score
Moves::mvv_lva_scores
[][NB_PIECE_TYPES
] = { { 0 } };
146 * PxK = 94, NxK = 92, BxK = 90, RxK = 88, QxK = 86, KxK = 84, PxQ = 78,
147 * NxQ = 76, BxQ = 74, RxQ = 72, QxQ = 70, KxQ = 68, PxR = 62, NxR = 60,
148 * BxR = 58, RxR = 56, QxR = 54, KxR = 52, PxB = 46, NxB = 44, BxB = 42,
149 * RxB = 40, QxB = 38, KxB = 36, PxN = 30, NxN = 28, BxN = 26, RxN = 24,
150 * QxN = 22, KxN = 20, PxP = 14, NxP = 12, BxP = 10, RxP = 8, QxP = 6,
153 void Moves::init_mvv_lva_scores()
155 for (const PieceType
& v
: PIECE_TYPES
) {
156 for (const PieceType
& a
: PIECE_TYPES
) {
157 mvv_lva_scores
[v
][a
] = (16 * v
) - (2 * a
);
162 Score
Moves::mvv_lva_score(Move move
)
164 assert(move
.is_capture());
165 PieceType a
= board
[move
.orig()].type();
166 PieceType v
= board
[move
.dest()].type();
167 if (move
.is_en_passant()) return mvv_lva_scores
[PAWN
][a
];
168 return mvv_lva_scores
[v
][a
];