Belofte version 2.2.0
A promising chess program using the UCI or Winboard interface
game.cpp
Go to the documentation of this file.
1/*---------------------------------------------------------------------+
2 * File: game.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
10#if defined(__GNUC__)
11#pragma GCC diagnostic push
12#pragma GCC diagnostic ignored "-Weffc++"
13#endif
14
16{
17 newGame();
18}
19
20#if defined(__GNUC__)
21#pragma GCC diagnostic pop
22#endif
23
25{
26 m_result = GR_UNKNOWN;
27 m_pgnTags.clear();
28#if defined(_DEBUG)
29 m_pgnTags["Event"] = "Debugging on " MYOS " " MYPLATFORM;
30#else
31 m_pgnTags["Event"] = "Running on " MYOS " " MYPLATFORM;
32#endif
33 m_pgnTags["Site"] = "";
34 m_pgnTags["Date"] = belofte::currentDate();
35 m_pgnTags["Round"] = "";
36 m_pgnTags["White"] = MYNAME " " MYVERSION " build " MYRELEASEDATE;
37 m_pgnTags["Black"] = MYNAME " " MYVERSION " build " MYRELEASEDATE;
38 m_pgnTags["Result"] = getResult(m_result);
39 m_optTags.clear();
40 m_optTags["eloWhite"] = "";
41 m_optTags["eloBlack"] = "";
42 m_positions.clear();
44}
45
47{
48 m_positions.clear();
49 m_positions.emplace_back(bFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"));
50 m_optTags.erase("SetUp");
51 m_optTags.erase("FEN");
52}
53
54void bGame::setFEN(std::string const& fenstr)
55{
56 m_positions.clear();
57 m_positions.emplace_back(bFen(fenstr));
58 m_optTags["SetUp"] = "1";
59 m_optTags["FEN"] = fenstr;
60}
61
62void bGame::setPlayerName(std::string const& n)
63{
64 if (getCurrentPosition().whiteToMove()) {
65 m_pgnTags["White"] = n;
66 } else {
67 m_pgnTags["Black"] = n;
68 }
69}
70
71/**
72 * Start search thread and exit
73 * in case of batch mode, will wait until end of search
74 */
76{
77 if (App().m_reader.isBatchMode()) {
78 /// in case of batch mode, do not start separate thread for searching
79 /// @todo allow for cancel search with ? / stop command
81 } else {
82 if (getCurrentPosition().whiteToMove()) {
83 std::string player = App().getConfig("enginename", "");
84 if (!player.empty()) m_pgnTags["White"] = player;
85 std::string opponent = App().getConfig("opponent", "");
86 if (!opponent.empty()) m_pgnTags["Black"] = opponent;
87 } else {
88 std::string player = App().getConfig("enginename", "");
89 if (!player.empty()) m_pgnTags["Black"] = player;
90 std::string opponent = App().getConfig("opponent", "");
91 if (!opponent.empty()) m_pgnTags["White"] = opponent;
92 }
93 std::thread th(&bGame::WaitForSearchEnd, std::ref(*this));
94 th.detach();
95 }
96}
97
102
103/**
104 * Called in separate thread, sure to terminate normally
105 */
107{
109 try {
110 bMoveList ml;
112 bMove m(ml[ml.getBestMoveId()]);
113 AppEI()->sendMove(b, m);
114 playGameMove(bCoordMove(m));
115 AppEI()->sendResult(b, getResult());
116 } catch (const noMoveFoundException&) {
117 // ignore error
118 AppEI()->sendError("no move found", "Wait for search");
119 } catch (const gameEndException&) {
120 // we already sent result earlier
121 /// @todo handle sending result here
122 } catch (...) { throw; // push other exceptions down
123 }
124}
125
126/**
127 * do perft search using SearchPerft algorithm at depth
128 */
130{
131 SearchPerft search;
132 return DoPerft(search, d);
133}
134
135/**
136 * do perft search at depth
137 * in case of Perft algorithm, temporarily set evaltype to None
138 */
140{
141 bLevel oldLevel(m_level);
143 m_level.setDepthCommand(d);
144
145 std::string sAlgName = getAlgorithm()->operator std::string();
146 std::string sEval = getEval()->operator std::string();
147
148 if (sAlgName == "Perft") setEval("None");
149
150 int iSearchVerbose = App().sout.getLevel();
151 App().sout.setLevel(-2);
152 int iOutputVerbose = App().bout.getLevel();
153 App().bout.setLevel(-1);
154
155 try {
156 bMoveList ml;
157 sa.setBench();
158 sa.SearchBestMove(b, ml);
159 sa.clearBench();
160 } catch (const noMoveFoundException&) {
161 // ignore error
162 } catch (...) { throw; // push other exceptions down
163 }
164
165 App().bout.setLevel(iOutputVerbose);
166 App().sout.setLevel(iSearchVerbose);
167
168 if (sAlgName == "Perft") setEval(sEval);
169
170 m_level = oldLevel;
171 return sa.getNodes();
172}
173
175{
176 return getEval()->getEvaluation(b, gr) * b.minimizing();
177}
178
180{
181 if (gr == GR_UNKNOWN) return "*";
182 if (bPositionEvaluation::isDrawResult(gr)) return "1/2-1/2";
183 if ((gr >= GR_WHITEMATES) && (gr <= GR_WHITEWINS_FLAG)) return "1-0";
184 return "0-1";
185}
186
188{
189 m_result = gr;
190 m_pgnTags["Result"] = getResult(m_result);
191}
192
193/**
194 * all moves in a single string
195 * @return false if one move cannot be played
196 */
197bool bGame::playGameMoveSeries(std::string const& coordmoves)
198{
199 std::vector<std::string> vstrings = belofte::stringSplit(coordmoves, " ");
200
201 return std::all_of(vstrings.begin(), vstrings.end(),
202 [this](std::string const& s)
203 { return this->playGameMove(bCoordMove(s)) || this->playPGNMoves(s); });
204}
205
206/**
207 * apply move, it will change the current board by updating the move played
208 * it will also add the new board to the game positions list
209 */
210bool bGame::playGameMove(bCoordMove const& coordmove)
211{
212 bBoard const& b = getCurrentPosition();
213 bMoveList ml;
214 ml.clearNeedSorted();
215 ml.clearKeepScores();
216 ml.generateMoves(b);
217 movenum_t n_moves = ml.getNumberOfMoves();
218 for (ml.curmoveid = 1; ml.curmoveid <= n_moves; ++ml.curmoveid) {
219 bMove const& m(ml[ml.curmoveid]);
220 bCoordMove cm(m);
221 if (cm == coordmove) {
222 bBoard newboard(b);
223 newboard.applyMove(m);
224 newboard.setMove(m.getFromTo());
225 newboard.calcGameStage();
226 m_positions.push_back(newboard);
227 bScore sc = Game()->EvalForPlayer(newboard, GR_UNSET);
230 } else if (bSearchScore::isUndefinedScore(sc)) {
231 // skip
232 } else if (sc == -SCORE_MATE) {
234 } else if (sc == SCORE_MATE) {
236 }
237 return true;
238 }
239 }
240 return false;
241}
242
243/**
244 * apply move, it will change the current board by updating the move played
245 * it will also add the new board to the game positions list
246 * @return true if at least a single move has been applied to position
247 */
248bool bGame::playPGNMoves(std::string const& sPGNMoveList)
249{
250 auto filterMoveNum = [](const std::string& str) -> std::string {
251 // filter out move-number, score (*,1-0,1/2-1/2) and newlines
252 size_t n = str.find_first_not_of("0123456789. */-\r\n\t");
253 return (n == std::string::npos) ? "" : str.substr(n);
254 };
255
256 bool hasPlayedMove = false;
257
258 std::regex commentsPatern("\\{[^}]*\\}");
259 std::string sMoveList = std::regex_replace(sPGNMoveList, commentsPatern, "");
260 std::regex alternativesPatern("\\([^)]*\\)");
261 sMoveList = std::regex_replace(sPGNMoveList, alternativesPatern, "");
262 belofte::stringList sMoves = belofte::stringSplit(sMoveList, " ");
263 if (sMoves.size() > 0) {
264 for (auto it = sMoves.begin(); it != sMoves.end(); ++it) {
265 bBoard const& b = getCurrentPosition();
266 bMoveList ml;
267 movenum_t n_moves = ml.generateMoves(b);
268 std::string sMove = filterMoveNum(*it);
269 for (ml.curmoveid = 1; ml.curmoveid <= n_moves; ++ml.curmoveid) {
270 bMove const& m(ml[ml.curmoveid]);
271 bPgnMove pm(b, m.getBMoveT());
272 if (pm == sMove) {
273 bCoordMove cm(m);
274 if (playGameMove(cm)) hasPlayedMove = true;
275 }
276 }
277 }
278 }
279
280 return hasPlayedMove;
281}
282
283/**
284 * required for Winboard protocol, not supported in UCI (except debug)
285 */
286void bGame::revertGameMove(std::string const& reason)
287{
288 if (m_positions.size() > 1) {
289 m_positions.pop_back();
292 } else {
293 AppEI()->sendError("cannot undo move", reason);
294 }
295}
296
297/**
298 * do actual epd position test
299 */
301{
302 bMove m;
303
304 int iOldSoutLevel = App().sout.getLevel();
305 App().sout.setLevel(-2);
306
307 newGame();
308 setFEN(fen);
310 try {
311 bMoveList ml;
313 m = ml[ml.getBestMoveId()];
314 } catch (const noMoveFoundException&) {
315 // not returning no move found
316 } catch (...) { throw; // push other exceptions down
317 }
318
319 App().sout.setLevel(iOldSoutLevel);
320 return m;
321}
322
323/// @todo Look at using stream and << operator instead of string
324std::string bGame::movesinpgnformat() const
325{
326 std::stringstream sMoves;
327 std::stringstream sMovePrefix;
328
329 if (m_positions.size() > 1) {
330 if (m_positions[0].blackToMove()) {
331 sMovePrefix << m_positions[0].getMoveNumber() << "... ";
332 }
333
334 for (unsigned int i = 1; i < m_positions.size(); ++i) {
335 bBoard newboard(m_positions[i]);
336 bBoard ob(m_positions[i - 1]);
337 if (newboard.getMove()) {
338 if (ob.whiteToMove()) {
339 sMovePrefix << newboard.getMoveNumber() << ". ";
340 }
341 bPgnMove pm(ob, newboard.getMove());
342 sMoves << sMovePrefix.str() << pm << " ";
343 sMovePrefix.str("");
344 }
345 }
346 }
347
348 sMoves << getResult(getResult());
349 return sMoves.str();
350}
351
352/// @todo Look at using stream and << operator instead of std::string
353bGame::operator std::string() const
354{
355 std::string sGameHeader;
356
357 // Export tags (7-tag roster)
358 for (auto const& x : m_pgnTags) {
359 if (isStandardPgn() || x.second.size()) {
360 sGameHeader += "[" + x.first + " \"" + x.second + "\"]" + "\n";
361 }
362 }
363
364 // only in extended PGN format, for values that are present
365 for (auto const& x : m_optTags) {
366 if (x.second.size()) {
367 sGameHeader += "[" + x.first + " \"" + x.second + "\"]" + "\n";
368 }
369 }
370 return sGameHeader + "\n" + movesinpgnformat();
371}
372
373// eof
appInstance & App()
Definition belofte.cpp:242
engineInterface * AppEI()
Definition belofte.cpp:248
bGame * Game()
Definition belofte.cpp:253
This is the main include file, needs to be included before any other include.
#define MYRELEASEDATE
Definition belofte.h:45
uint_fast8_t movenum_t
Definition belofte.h:103
#define MYVERSION
Definition belofte.h:34
#define MYNAME
Definition belofte.h:32
int_fast8_t depth_t
Definition belofte.h:106
outputWriter sout
normal output
Definition belofte.h:179
outputWriter bout
Definition belofte.h:178
int64_t getConfig(std::string const &s, int64_t v)
Definition belofte.cpp:199
constexpr bool whiteToMove() const
Definition basicboard.h:162
constexpr bScore minimizing() const
Definition basicboard.h:172
constexpr bmove_t getBMoveT() const
Definition basicmove.h:72
board
Definition board.h:45
void clearMove()
Definition board.h:89
void setEval(std::string const &e)
bSearchAlgorithm * getAlgorithm() const
bPositionEvaluation * getEval() const
simple coordmove, with 4 characters, or 5 characters in case of promotion mostly used for interface
Definition coordmove.h:15
FEN string.
Definition fen.h:14
bMove getEpdMoveInPosition(bFen const &fen)
do actual epd position test
Definition game.cpp:300
void setResult(gameResult_t gr)
Definition game.cpp:187
void setPlayerName(std::string const &n)
Definition game.cpp:62
constexpr bool isStandardPgn() const
Definition game.h:78
int64_t DoPerft(bSearchAlgorithm &sa, depth_t const d)
do perft search at depth in case of Perft algorithm, temporarily set evaltype to None
Definition game.cpp:139
void WaitForSearchEnd()
Called in separate thread, sure to terminate normally.
Definition game.cpp:106
bool playPGNMoves(std::string const &sPGNMoveList)
apply move, it will change the current board by updating the move played it will also add the new boa...
Definition game.cpp:248
void AbortSearch()
Definition game.cpp:98
void newGame()
Definition game.cpp:24
void revertGameMove(std::string const &reason)
required for Winboard protocol, not supported in UCI (except debug)
Definition game.cpp:286
bLevel & getLevel()
Definition game.h:59
void DoSearch()
Start search thread and exit in case of batch mode, will wait until end of search.
Definition game.cpp:75
bGame()
Definition game.cpp:15
bool playGameMoveSeries(std::string const &coordmoves)
all moves in a single string
Definition game.cpp:197
void setFEN(std::string const &fenstr)
Definition game.cpp:54
int64_t DoPerftCommand(depth_t const d)
do perft search using SearchPerft algorithm at depth
Definition game.cpp:129
gameResult_t getResult() const
Definition game.h:41
bScore EvalForPlayer(bBoard const &b, gameResult_t gr)
Definition game.cpp:174
bBoard & getCurrentPosition()
Definition game.h:54
void setFENInitialPos()
Definition game.cpp:46
Definition level.h:48
void flagLevelChanged()
Definition level.h:68
Definition move.h:13
void clearNeedSorted()
Definition movelist.h:96
movenum_t generateMoves(bBasicBoard const &b)
generate moves if not yet generated
Definition movelist.cpp:417
void clearKeepScores()
Definition movelist.h:100
constexpr movenum_t getBestMoveId() const
Definition movelist.h:87
constexpr movenum_t getNumberOfMoves() const
Definition movelist.h:49
movenum_t curmoveid
Definition movelist.h:104
PgnMove is for user-interface only.
Definition pgnmove.h:14
static bool isDrawResult(gameResult_t const gr)
Definition eval.h:67
virtual bScore getEvaluation(bBoard const &b, gameResult_t gr) const
get final score (+-SCORE_MATE, SCORE_THEORETIC_DRAW) or 0
Definition eval.cpp:429
constexpr int64_t getNodes() const
Definition search.h:109
void clearBench()
Definition search.h:138
void InterruptSearch()
Definition search.h:116
void SearchBestMove(bBoard &b, bMoveList &ml)
Generic search, will call (non-)recursive method per algorithm only when there are moves to be played...
Definition search.cpp:18
void setBench()
Definition search.h:136
static constexpr bool isDrawScore(bScore const score)
constexpr bool isUndefinedScore() const
Definition searchscore.h:70
virtual void sendResult(bBoard const &b, gameResult_t const gr) const
virtual void sendMove(bBoard &b, bMove const &m)
virtual void sendError(std::string const &error, std::string const &description)
int getLevel() const
void setLevel(int const l)
@ GR_UNSET
Definition eval.h:32
@ GR_DRAW_OTHER
Definition eval.h:35
@ GR_WHITEWINS_FLAG
Definition eval.h:36
@ GR_UNKNOWN
Definition eval.h:33
@ GR_WHITEMATES
Definition eval.h:36
@ GR_BLACKMATES
Definition eval.h:37
constexpr bScore SCORE_MATE
Definition eval.h:19
enum gameResult gameResult_t
Definition eval.h:40
int16_t bScore
Definition eval.h:11
#define MYPLATFORM
no matching platform
Definition myplatform.h:73
#define MYOS
no matching OS
Definition myplatform.h:117
stringList const stringSplit(std::string src, std::string const &delim)
Split delimited long string into a vector.
Definition util.cpp:148
std::vector< std::string > stringList
Definition util.h:48
std::string currentDate()
Definition util.cpp:292