Belofte version 2.1.8
A promising chess program using the UCI or Winboard interface
movelist.cpp
Go to the documentation of this file.
1/*---------------------------------------------------------------------+
2 * File: movelist.cpp
3 * Project: part of belofte - A Promising Chess Program
4 * Author: yves
5 * SPDX-License-Identifier: GPL-2.0-only
6+----------------------------------------------------------------------*/
7
8#include "belofte.h"
9
11 : m_lmoves{}
12{
13}
14
16 : m_lmoves{}
17{
19}
20
22{
23 m_lmoves.clear();
24}
25
26//-----------------------------------------------------------------------
27
28void bMoveList::addMoveAndSetScore(bBoard const& b, bMove const& m,
29 bool const check)
30{
31 bScore sc = 0;
32 bMove nm(m);
33 if (check) {
34 nm.setCheck();
35 bBoard nb(b, const_cast<bMove const&>(nm));
36 if (!nb.atLeastOneMovePossible())
37 nm.setGameEnd();
38 }
39
40 if (nm.getGameEnd()) {
41 sc = SCORE_MATE;
42 } else {
43 // malus points for moving own piece, except for pawn
45 if (nm.isCapture()) {
47 }
50 if (nm.isPromotion()) {
51 sc += 300;
52 if (nm.isMajorPromotion()) sc += 500;
53 }
54 if (nm.isPawnMove() && (b.getStage() == bGameStage::ST_PAWNENDING)) sc += 10;
55 if (nm.isCheck()) sc += 80; // check is less than a pawn, we prefer captures
56 if (nm.isCastleMove()) sc += 250; // malus for king move 200, so half a pawn
57 }
58 if (nm.isNonSilent()) m_nQSMoves++;
59#if !defined(INCOMPLETE_C11)
60 if (m_bestmoveid && (sc >= m_lmoves[m_bestmoveid - 1].getScore())) {
61 // this move is better or equal than all previous moves, so insert it at front
62 m_lmoves.insert(m_lmoves.begin(), nm);
63 setScoreOfMove(1, sc);
64 } else {
65#endif
66 m_lmoves.emplace_back(nm);
67 setScoreOfMove(static_cast<movenum_t>(m_lmoves.size()), sc);
68#if !defined(INCOMPLETE_C11)
69 }
70#endif
71}
72
73/**
74 * Only add move to movelist if valid
75 * @param b board on which move is calculated
76 * @param m move to be added
77 * @return number of moves added (1), meaning player is not in check after move
78 */
80{
81 bBoard newboard(b, m);
82 bWhiteKing const* wking = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
83 if (wking->isAttacked(newboard, newboard.getWhiteKingPos())) return 0;
84 bBlackKing const* bking = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
85 addMoveAndSetScore(b, m, bking->isAttacked(newboard, newboard.getBlackKingPos()));
86 return 1;
87}
88
90{
91 bMove m(cf, to);
92 m.setCapture();
93 return addWhiteMoveIfValid(b, m);
94}
95
96/**
97 * Only add move to movelist if valid
98 * @param b board on which move is calculated
99 * @param m move to be added
100 * @return number of moves added (1), meaning player is not in check after move
101 */
103{
104 bBoard newboard(b, m);
105 bBlackKing const* bking = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
106 if (bking->isAttacked(newboard, newboard.getBlackKingPos())) return 0;
107 bWhiteKing const* wking = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
108 addMoveAndSetScore(b, m, wking->isAttacked(newboard, newboard.getWhiteKingPos()));
109 return 1;
110}
111
113{
114 bMove m(cf, to);
115 m.setCapture();
116 return addBlackMoveIfValid(b, m);
117}
118
119/**
120 * Only add move to movelist if valid
121 * @param b board on which move is calculated
122 * @param m move to be added
123 * @return number of moves added (4), meaning, player is not in check after move
124 */
126{
127 bBoard newboard(b, m);
128 bWhiteKing const* wking = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
129 if (wking->isAttacked(newboard, newboard.getWhiteKingPos())) return 0;
130
131 bBlackKing const* bking = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
132
133 // we are promoting, but did apply a dummy move on top
134 // so modify dest board with custom pieces and check for in check
135 bMove newmove(m);
136 case_t to = m.to();
137 case_t bKingPos = newboard.getBlackKingPos();
138
139 // TODO: optimize in case of uncover check just by moving pawn
140 newboard.setPiece(to, tPiece::W_QUEEN);
141 bool oppInCheckByQueen = bking->isAttacked(newboard, bKingPos);
142 newmove.setPromotion(tPPiece::N_P_QUEEN); addMoveAndSetScore(b, newmove, oppInCheckByQueen);
143
144 newboard.setPiece(to, tPiece::W_KNIGHT);
145 bool oppInCheck = bking->isAttacked(newboard, bKingPos);
146 newmove.setPromotion(tPPiece::N_P_KNIGHT); addMoveAndSetScore(b, newmove, oppInCheck);
147
148 newboard.setPiece(to, tPiece::W_ROOK);
149 // do not re-evaluate check by rook if queen did not give check
150 oppInCheck = oppInCheckByQueen && bking->isAttacked(newboard, bKingPos);
151 newmove.setPromotion(tPPiece::N_P_ROOK); addMoveAndSetScore(b, newmove, oppInCheck);
152
153 newboard.setPiece(to, tPiece::W_BISHOP);
154 oppInCheck = oppInCheckByQueen && bking->isAttacked(newboard, bKingPos);
155 newmove.setPromotion(tPPiece::N_P_BISHOP); addMoveAndSetScore(b, newmove, oppInCheck);
156 return 4;
157}
158
159/**
160 * Only add move to movelist if valid
161 * @param b board on which move is calculated
162 * @param m move to be added
163 * @return number of moves added (4), meaning, player is not in check after move
164 */
166{
167 bBoard newboard(b, m);
168 bBlackKing const* bking = static_cast<bBlackKing *>(bPiece::getPieceClass(tPiece::B_KING));
169 if (bking->isAttacked(newboard, newboard.getBlackKingPos())) return 0;
170
171 bWhiteKing const* wking = static_cast<bWhiteKing *>(bPiece::getPieceClass(tPiece::W_KING));
172
173 // we are promoting, but did apply a dummy move on top
174 // so modify dest board with custom pieces and check for in check
175 bMove newmove(m);
176 case_t to = m.to();
177 case_t wKingPos = newboard.getWhiteKingPos();
178
179 // TODO: optimize in case of uncover check just by moving pawn
180 newboard.setPiece(to, tPiece::B_QUEEN);
181 bool oppInCheckByQueen = wking->isAttacked(newboard, wKingPos);
182 newmove.setPromotion(tPPiece::N_P_QUEEN); addMoveAndSetScore(b, newmove, oppInCheckByQueen);
183
184 newboard.setPiece(to, tPiece::B_KNIGHT);
185 bool oppInCheck = wking->isAttacked(newboard, wKingPos);
186 newmove.setPromotion(tPPiece::N_P_KNIGHT); addMoveAndSetScore(b, newmove, oppInCheck);
187
188 newboard.setPiece(to, tPiece::B_ROOK);
189 // do not re-evaluate check by rook if queen did not give check
190 oppInCheck = oppInCheckByQueen && wking->isAttacked(newboard, wKingPos);
191 newmove.setPromotion(tPPiece::N_P_ROOK); addMoveAndSetScore(b, newmove, oppInCheck);
192
193 newboard.setPiece(to, tPiece::B_BISHOP);
194 oppInCheck = oppInCheckByQueen && wking->isAttacked(newboard, wKingPos);
195 newmove.setPromotion(tPPiece::N_P_BISHOP); addMoveAndSetScore(b, newmove, oppInCheck);
196 return 4;
197}
198
199//-----------------------------------------------------------------------
200
201/**
202 * Store score of move
203 * @param moveid of move to be stored [1 -> max number of moves]
204 * @param score to be stored
205 * @return moveid of new best move if updated, or zero if no update
206 */
208{
209 if (m_bestmoveid) {
210 if (score > m_lmoves[m_bestmoveid - 1].getScore()) {
211 // improvement
212 m_bestmoveid = moveid;
213 m_isSorted = false;
214 }
215 } else {
216 // no bestmove id stored yet
217 m_bestmoveid = moveid;
218 m_isSorted = false;
219 }
220 m_lmoves[moveid - 1].setScore(score);
221
222 return m_bestmoveid;
223}
224
226{
227 size_t nS = m_lmoves.size();
228 if (nS) {
229 if (!m_isSorted) {
230 if (nS >= 5) {
231 if (m_nQSMoves) {
232 // only interested in 2 best scores in case of QS moves
233 std::partial_sort(m_lmoves.begin(), m_lmoves.begin() + 2, m_lmoves.end(),
234 [](bMove const& a, bMove const& b) { return a > b; });
235 } else {
236 // only interested in 4 best scores
237 std::partial_sort(m_lmoves.begin(), m_lmoves.begin() + 4, m_lmoves.end(),
238 [](bMove const& a, bMove const& b) { return a > b; });
239 }
240 } else {
241 // sort all in case of 1 to 4 elements
242 std::sort(m_lmoves.begin(), m_lmoves.end(),
243 [](bMove const& a, bMove const& b) { return a > b; });
244 }
245 m_isSorted = true;
246 m_bestmoveid = 1;
247 }
248 } else {
249 m_bestmoveid = 0;
250 }
251 return m_bestmoveid;
252}
253
254//-----------------------------------------------------------------------
255
256/**
257 * generate moves if not yet generated
258 */
260{
261 if (!m_isGenerated) {
262 m_isGenerated = true;
263 side_t sidetomove = b.getColourToMove();
264 if (sidetomove == tSide::SIDE_WHITE) {
265 for (case_t iCase = 0; iCase < 64; ++iCase) {
266 piece_t p = b.getPiece(iCase);
267 if (bPiece::isWhitePiece(p)) {
268 (bPiece::getPieceClass(p))->GenerateMoves(b, iCase, *this);
269 }
270 }
271 } else {
272 for (case_t iCase = 64; iCase > 0;) {
273 --iCase;
274 piece_t p = b.getPiece(iCase);
275 if (bPiece::isBlackPiece(p)) {
276 (bPiece::getPieceClass(p))->GenerateMoves(b, iCase, *this);
277 }
278 }
279 }
280 }
281 return static_cast<movenum_t>(m_lmoves.size());
282}
283
285{
286 m_lmoves.clear();
287 m_isGenerated = false;
288 m_isSorted = false;
289 m_nQSMoves = 0;
290 m_bestmoveid = 0;
291}
292
293/**
294 * see if at least one move can be played e.g. (stale-)mate eval
295 */
297{
298 if (m_isGenerated) return (m_lmoves.size() > 0);
299
300 bBoard nb(b);
302 for (case_t iCase = 0; iCase < 64; ++iCase) {
303 piece_t p = nb.getPiece(iCase);
304 if (bPiece::isWhitePiece(p)) {
305 if (bPiece::getPieceClass(p)->hasValidMovePreflightCheck(nb, iCase))
306 return true;
307 }
308 }
309 } else {
310 for (case_t iCase = 64; iCase > 0;) {
311 --iCase;
312 piece_t p = nb.getPiece(iCase);
313 if (bPiece::isBlackPiece(p)) {
314 if (bPiece::getPieceClass(p)->hasValidMovePreflightCheck(nb, iCase))
315 return true;
316 }
317 }
318 }
319 return false;
320}
321
322bMove const& bMoveList::operator[](movenum_t const moveid) const
323{
324 return m_lmoves[moveid - 1];
325}
326
328{
329 return m_lmoves[moveid - 1].getBasicMoveT();
330}
331
333{
334 return static_cast<movenum_t>(m_lmoves.size());
335}
336
337/** return number of non silent moves
338*/
340{
341 return m_nQSMoves;
342}
343
344//-----------------------------------------------------------------------
345
346std::ostream& operator<<(std::ostream& os, bMoveList const& ml)
347{
348 os << "#" << static_cast<int>(ml.getNumberOfMoves()) << " ";
349 for (bMove const& m: ml.m_lmoves) {
350 os << m << m.getMoveEvalStr() << " ";
351 }
352 return os;
353}
354
355// eof
This is the main include file, needs to be included before any other include.
uint16_t basicmove_t
Definition belofte.h:107
uint_fast8_t movenum_t
Definition belofte.h:109
uint8_t case_t
Definition belofte.h:106
int16_t bScore
void setPiece(case_t const bc, piece_t const piece)
used for promotion move generation
Definition board.cpp:190
piece_t getPiece(case_t const bc) const
1 for white, 2 for black
Definition board.cpp:157
side_t getColourToMove() const
Definition board.h:82
case_t getBlackKingPos() const
Definition board.h:103
case_t getWhiteKingPos() const
Definition board.h:102
basicmove_t getBasicMoveT() const
Definition move.h:38
MEMBER_CONSTEXPR case_t to() const
Definition move.h:29
bool isAttacked(bBoard const &b, case_t const &cf) const override
Definition piece.cpp:284
board
Definition board.h:147
bGameStage getStage() const
Definition board.h:177
Definition move.h:69
void setCapture()
Definition move.h:88
std::string getMoveEvalStr() const
Definition move.cpp:116
void setPromotion(const ppiece_t p)
Definition move.h:85
movenum_t addWhiteCaptureIfValid(bBoard const &b, case_t const &cf, case_t const &to)
Definition movelist.cpp:89
movenum_t addBlackPromotionIfValid(bBoard const &b, bMove const &m)
Only add move to movelist if valid.
Definition movelist.cpp:165
void emptyMoveList()
Definition movelist.cpp:284
movelist_t m_lmoves
Definition movelist.h:49
movenum_t setScoreOfMove(movenum_t const moveid, bScore const score)
Store score of move.
Definition movelist.cpp:207
movenum_t addWhitePromotionIfValid(bBoard const &b, bMove const &m)
Only add move to movelist if valid.
Definition movelist.cpp:125
movenum_t sortMoves()
Definition movelist.cpp:225
movenum_t addBlackCaptureIfValid(bBoard const &b, case_t const &cf, case_t const &to)
Definition movelist.cpp:112
movenum_t getNumberOfQSMoves() const
return number of non silent moves
Definition movelist.cpp:339
movenum_t getNumberOfMoves() const
Definition movelist.cpp:332
movenum_t addBlackMoveIfValid(bBoard const &b, bMove const &m)
Only add move to movelist if valid.
Definition movelist.cpp:102
movenum_t addWhiteMoveIfValid(bBoard const &b, bMove const &m)
Only add move to movelist if valid.
Definition movelist.cpp:79
movenum_t generateMoves(bBoard const &b)
generate moves if not yet generated
Definition movelist.cpp:259
bool atLeastOneMovePossible(bBoard const &b) const
see if at least one move can be played e.g.
Definition movelist.cpp:296
basicmove_t getMoveT(movenum_t const moveid) const
Definition movelist.cpp:327
bMove const & operator[](movenum_t const moveid) const
Definition movelist.cpp:322
static bPiece * getPieceClass(piece_t const piece)
static class member function
Definition piece.cpp:130
static bool isBlackPiece(piece_t const p)
static class member function
Definition piece.cpp:213
static bool isWhitePiece(piece_t const p)
static class member function
Definition piece.cpp:206
static bScore pieceValue(piece_t const p)
Definition eval.cpp:347
static bScore centerplay_pieceValue(case_t const p)
Definition eval.cpp:357
static bScore mymove_pieceValue(piece_t const p)
Definition eval.cpp:352
bool isAttacked(bBoard const &b, case_t const &cf) const override
Check if piece on position is attacked, start with piece always on board and then with pieces with gr...
Definition piece.cpp:237
constexpr bScore SCORE_MATE
Definition eval.h:23
std::ostream & operator<<(std::ostream &os, bMoveList const &ml)
Definition movelist.cpp:346
enum tSide side_t
Definition piece.h:66
@ W_KNIGHT
Definition piece.h:39
@ B_BISHOP
Definition piece.h:40
@ W_ROOK
Definition piece.h:39
@ B_ROOK
Definition piece.h:40
@ W_QUEEN
Definition piece.h:39
@ B_KING
Definition piece.h:40
@ B_KNIGHT
Definition piece.h:40
@ W_KING
Definition piece.h:39
@ B_QUEEN
Definition piece.h:40
@ W_BISHOP
Definition piece.h:39
enum tPiece piece_t
Definition piece.h:44
@ N_P_KNIGHT
Definition piece.h:48
@ N_P_QUEEN
Definition piece.h:48
@ N_P_ROOK
Definition piece.h:48
@ N_P_BISHOP
Definition piece.h:48
@ SIDE_WHITE