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 (cur
== 0) generate(); // generate() will change the value of 'n'
43 if (cur
== end
) return ExtendedMove();
47 switch (generation_state
) {
49 if (cur
< size
[BEST
]) {
52 generation_state
= GOOD_CAPTURES
;
54 cur
= size
[BEST
] + size
[KILLERS
]; // Jump to first good capture
56 if (cur
< (size
[BEST
] + size
[KILLERS
] + size
[GOOD_CAPTURES
])) {
59 generation_state
= KILLERS
;
60 cur
= size
[BEST
]; // Jump to the first killer
62 if (cur
< (size
[BEST
] + size
[KILLERS
])) {
65 generation_state
= BAD_CAPTURES
;
66 cur
= size
[BEST
] + size
[KILLERS
] + size
[GOOD_CAPTURES
];
71 generation_state
= QUIET_MOVES
;
78 return ExtendedMove();
81 // If we are here, next() should return a capture
82 assert(state() == GOOD_CAPTURES
|| state() == BAD_CAPTURES
);
84 // Find the best remaining capture by selection sort
86 for (int i
= cur
+ 1; i
< end
; ++i
) {
87 if (moves
[i
].value() > moves
[max
].value()) {
92 // Swap it with the current one
94 ExtendedMove tmp
= std::move(moves
[cur
]);
95 moves
[cur
] = std::move(moves
[max
]);
96 moves
[max
] = std::move(tmp
);
103 void Moves::add(Move move
, MovesState mt
)
105 if (!use_lazy_generation
) {
106 moves
[end
++] = ExtendedMove(move
, 0);
110 if (move
.is_null()) return;
112 // Don't add again best and killer moves
113 const int n
= size
[BEST
] + size
[KILLERS
];
114 for (int i
= 0; i
< n
; ++i
) if (moves
[i
] == move
) return;
116 // Calculate the move's score
124 score
= KILLERS_SCORE
- size
[KILLERS
];
128 //assert(generation_state > KILLERS);
129 //size[generation_state]++; // If move is a capture or a quiet move
132 switch (generation_state
) {
135 score
= mvv_lva_score(move
);
136 size
[generation_state
]++;
140 size
[generation_state
]++;
143 //assert(mt < GOOD_CAPTURES);
144 //size[mt]++; // If move is a best or killer move
148 // Add the move and its score to moves list
149 moves
[end
++] = ExtendedMove(move
, score
);
152 Score
Moves::mvv_lva_scores
[][NB_PIECE_TYPES
] = { { 0 } };
157 * PxP = 7, PxN = 15, PxB = 23, PxR = 31, PxQ = 39, PxK = 47
158 * NxP = 6, NxN = 14, NxB = 22, NxR = 30, NxQ = 38, NxK = 46
159 * BxP = 5, BxN = 13, BxB = 21, BxR = 29, BxQ = 37, BxK = 45
160 * RxP = 4, RxN = 12, RxB = 20, RxR = 28, RxQ = 36, RxK = 44
161 * QxP = 3, QxN = 11, QxB = 19, QxR = 27, QxQ = 35, QxK = 43
162 * KxP = 2, KxN = 10, KxB = 18, KxR = 26, KxQ = 34, KxK = 42
164 void Moves::init_mvv_lva_scores()
166 for (const PieceType
& a
: PIECE_TYPES
) {
167 for (const PieceType
& v
: PIECE_TYPES
) {
168 mvv_lva_scores
[a
][v
] = (8 * v
) - a
;
173 Score
Moves::mvv_lva_score(Move move
)
175 assert(move
.is_capture());
176 PieceType a
= board
[move
.orig()].type();
177 PieceType v
= move
.is_en_passant() ? PAWN
: board
[move
.dest()].type();
178 return mvv_lva_scores
[a
][v
];