stellar

UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE |

game.cpp (3962B)


1 #include "game.hpp" 2 3 #include "board.hpp" 4 #include "logger.hpp" 5 #include "timer.hpp" 6 7 #include <format> 8 9 bool Game::san = true; 10 const std::string Game::startPosition = start_position; 11 12 uint16_t Game::id_t = 0; 13 Game::~Game() { logger::log(std::format("Game {}: destroyed", id), logger::Debug); } 14 Game::Game(const uint16_t match_id, const std::string white, const std::string black, const std::string fen) 15 : match_id(match_id), white(white), black(black), fen(fen) { 16 logger::log(std::format("Game {}: started", id), logger::Debug); 17 } 18 19 const std::string Game::get_moves(void) const { 20 std::string res; 21 if (list.size()) res += (std::string)list[0]; 22 for (int i = 1; i < list.size(); i++) 23 res += " " + (std::string)list[i]; 24 return res; 25 } 26 27 const std::string Game::to_san(const Board &board, const Move move) { 28 Board copy = board; 29 if (!move.make(copy)) { 30 logger::log("illegal move", logger::Critical); 31 throw std::runtime_error("illegal move"); 32 } 33 34 if (move.is_castle_king()) return "O-O"; 35 if (move.is_castle_queen()) return "O-O-O"; 36 37 const piece::Type piece = board.get_square_piece_type(move.source()); 38 const piece::Type target = board.get_square_piece_type(move.target()); 39 40 std::string res; 41 if (piece != piece::PAWN) { 42 U64 potential = board.get_bitboard_square_land(move.target(), piece, board.get_side()); 43 44 if (bit::count(potential) > 1) { 45 int file[9] = {0}, rank[9] = {0}; 46 uint8_t square_i; 47 bitboard_for_each_bit(square_i, potential) { 48 const std::string crd = square::to_coordinates(static_cast<square::Square>(square_i)); 49 file[crd[0] & 0x3]++; 50 rank[crd[1] & 0x3]++; 51 } 52 53 const std::string crd = square::to_coordinates(move.source()); 54 if (file[crd[0] & 0x3] == 1) res += crd[0]; 55 else if (rank[crd[1] & 0x3] == 1) 56 res += crd[1]; 57 else 58 res += crd; 59 } 60 61 res += piece::get_code(piece, color::WHITE); 62 if (target != piece::NONE) res += "x"; 63 res += square::to_coordinates(move.target()); 64 } else { 65 if (target != piece::NONE) res += std::format("{}x", square::to_coordinates(move.source())[0]); 66 res += square::to_coordinates(move.target()); 67 if (move.is_promote()) res += piece::get_code(move.promoted(), color::WHITE); 68 if (move.is_enpassant()) res += " e.p."; 69 } 70 71 if (!MoveList(copy, false, true).size()) res += "#"; 72 else if (copy.is_check()) 73 res += "+"; 74 75 return res; 76 } 77 78 std::ostream &operator<<(std::ostream &os, const Game &game) { 79 static const std::string name[] = {"death", "time forfeit", "rules infraction", "repetition"}; 80 os << std::format("[Event \"Match {}\"]", game.match_id); 81 os << std::format("\n[Site \"{}\"]", "Stellar Arena"); 82 os << std::format("\n[Date \"{}\"]", timer::get_ms()); 83 os << std::format("\n[Round \"{}\"]", game.id); 84 os << std::format("\n[White \"{}\"]", game.get_white()); 85 os << std::format("\n[Black \"{}\"]", game.get_black()); 86 os << std::format("\n[Result \"{}-{}\"]", (int)game.is_win_white(), (int)game.is_win_black()); 87 os << std::format("\n[Termination \"{}\"]", name[to_underlying(game.get_terminate())]); 88 if (game.fen != Game::startPosition) { 89 os << std::format("\n[SetUp \"1\"]"); 90 os << std::format("\n[FEN \"{}\"]", game.fen); 91 } 92 os << '\n'; 93 94 if (!game.list.size()) return os; 95 Board board(game.fen); 96 97 const color::Color side = board.get_side(); 98 if (side == color::BLACK) os << std::format("1. ... "); 99 for (int i = 0; i < game.list.size(); i++) { 100 if (i % 2 == to_underlying(side)) os << std::format("{}. ", i / 2 + 1); 101 os << std::format("{} ", Game::san ? Game::to_san(board, game.list[i]) : (std::string)game.list[i]); 102 game.list[i].make(board); 103 } 104 105 return os; 106 }