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