/
expertdaniil
/
Chess
Обзор
Документация
Войти
/
expertdaniil
/
Chess
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Chess_Apply.cpp
165 строк
6 KB
expertdaniil
upload files
22 янв 2026, 15:44
Верифицирован
22 янв 2026, 15:44
a081d0c
Код
Авторство
О чём код?
#include "Chess_Apply.h" #include <stdexcept> ChessUndo ChessApplier::ApplyMove(ChessState& st, const Move& mv, const RulesConfig& rules) { if (!mv.isValid() || !ChessState::inBoundsSq(mv.from) || !ChessState::inBoundsSq(mv.to)) { throw std::runtime_error("ApplyMove error"); } const Piece moving = st.pieceAt(mv.from); if (moving.isEmpty()) throw std::runtime_error("ApplyMove empty piece"); if (moving.side != st.sideToMove()) throw std::runtime_error("ApplyMove wrong side"); ChessUndo u; u.prevSideToMove = st.sideToMove(); u.prevCastling = st.castling(); u.prevEnPassantSquare = st.enPassantSquare(); u.fromSq = mv.from; u.toSq = mv.to; u.prevFromPiece = st.pieceAt(mv.from); u.prevToPiece = st.pieceAt(mv.to); st.setEnPassantSquare(-1); applyEnPassantIfNeeded(st, mv, u, rules); applyBasicMove(st, mv); applyCastlingIfNeeded(st, mv, u, rules); applyPromotionIfNeeded(st, mv, rules); updateMetaAfterMove(st, mv); st.setSideToMove(Opposite(st.sideToMove())); return u; } void ChessApplier::UndoMove(ChessState& st, const ChessUndo& u) { st.setSideToMove(u.prevSideToMove); st.setCastling(u.prevCastling); st.setEnPassantSquare(u.prevEnPassantSquare); if (ChessState::inBoundsSq(u.fromSq)) st.pieceAt(u.fromSq) = u.prevFromPiece; if (ChessState::inBoundsSq(u.toSq)) st.pieceAt(u.toSq) = u.prevToPiece; if (u.rookMoved) { if (ChessState::inBoundsSq(u.rookFromSq)) st.pieceAt(u.rookFromSq) = u.prevRookFrom; if (ChessState::inBoundsSq(u.rookToSq)) st.pieceAt(u.rookToSq) = u.prevRookTo; } if (u.epCapture) { if (ChessState::inBoundsSq(u.epCapturedSq)) st.pieceAt(u.epCapturedSq) = u.prevEpCapturedPiece; } } void ChessApplier::applyBasicMove(ChessState& st, const Move& mv) { st.pieceAt(mv.to) = st.pieceAt(mv.from); st.clearSquare(mv.from); } void ChessApplier::applyEnPassantIfNeeded(ChessState& st, const Move& mv, ChessUndo& u, const RulesConfig& rules) { if (!mv.isEnPassant) return; if (!rules.allowEnPassant) throw std::runtime_error("EP not allowed"); const Piece mover = st.pieceAt(mv.from); if (mover.kind != PieceKind::Pawn) throw std::runtime_error("EP: mover not pawn"); const int fr = ChessState::row(mv.from); const int tc = ChessState::col(mv.to); const int capturedSq = ChessState::pack(fr, tc); u.epCapture = true; u.epCapturedSq = capturedSq; u.prevEpCapturedPiece = st.pieceAt(capturedSq); st.clearSquare(capturedSq); } void ChessApplier::applyCastlingIfNeeded(ChessState& st, const Move& mv, ChessUndo& u, const RulesConfig& rules) { if (!mv.isCastle) return; if (!rules.allowCastling) throw std::runtime_error("Castling not allowed"); const Piece king = st.pieceAt(mv.to); if (king.kind != PieceKind::King) throw std::runtime_error("Castle: king missing"); const int r = ChessState::row(mv.to); const int fromC = ChessState::col(mv.from); const int toC = ChessState::col(mv.to); int rookFrom = -1, rookTo = -1; if (fromC == 4 && toC == 6) { rookFrom = ChessState::pack(r, 7); rookTo = ChessState::pack(r, 5); } else if (fromC == 4 && toC == 2) { rookFrom = ChessState::pack(r, 0); rookTo = ChessState::pack(r, 3); } else { throw std::runtime_error("Castle: unexpected king move"); } u.rookMoved = true; u.rookFromSq = rookFrom; u.rookToSq = rookTo; u.prevRookFrom = st.pieceAt(rookFrom); u.prevRookTo = st.pieceAt(rookTo); st.pieceAt(rookTo) = st.pieceAt(rookFrom); st.clearSquare(rookFrom); } void ChessApplier::applyPromotionIfNeeded(ChessState& st, const Move& mv, const RulesConfig& rules) { if (!mv.isPromotion) return; if (!rules.allowPromotion) throw std::runtime_error("Promotion not allowed"); Piece& p = st.pieceAt(mv.to); if (p.kind != PieceKind::Pawn) throw std::runtime_error("Promotion: not pawn"); if (mv.promoKind == PieceKind::None || mv.promoKind == PieceKind::Pawn || mv.promoKind == PieceKind::King) { throw std::runtime_error("Promotion: invalid kind"); } p.kind = mv.promoKind; } static bool isStartRookSquare(int sq, Side s, bool& isKingSide) { if (s == Side::White) { if (sq == ChessState::pack(0,7)) { isKingSide = true; return true; } if (sq == ChessState::pack(0,0)) { isKingSide = false; return true; } } else { if (sq == ChessState::pack(7,7)) { isKingSide = true; return true; } if (sq == ChessState::pack(7,0)) { isKingSide = false; return true; } } return false; } void ChessApplier::updateMetaAfterMove(ChessState& st, const Move& mv) { CastlingRights cr = st.castling(); const Piece moved = st.pieceAt(mv.to); const Side s = moved.side; if (moved.kind == PieceKind::King) { if (s == Side::White) { cr.wK = false; cr.wQ = false; } else { cr.bK = false; cr.bQ = false; } } if (moved.kind == PieceKind::Rook) { bool kingSide = false; if (isStartRookSquare(mv.from, s, kingSide)) { if (s == Side::White) { if (kingSide) cr.wK = false; else cr.wQ = false; } else { if (kingSide) cr.bK = false; else cr.bQ = false; } } } st.setCastling(cr); if (mv.isDoublePush) { const int fr = ChessState::row(mv.from); const int fc = ChessState::col(mv.from); const int tr = ChessState::row(mv.to); const int midR = (fr + tr) / 2; st.setEnPassantSquare(ChessState::pack(midR, fc)); } }