package chess import ( "mchess_server/types" ) type King struct { Color types.ChessColor } func (k King) GetAllAttackedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate { return k.GetAllNonBlockedSquares(board, fromSquare) } func (k King) GetColor() types.ChessColor { return k.Color } func (k King) GetAllNonBlockedSquares(board Board, fromSquare types.Coordinate) []types.Coordinate { return board.GetNonBlockedKingMoves(fromSquare) } func (k King) AfterMoveAction(board *Board, fromSquare types.Coordinate) { switch k.Color { case types.Black: board.state.BlackKingMoved = true case types.White: board.state.WhiteKingMoved = true } } func (k King) HandleCastling(board *Board, move types.Move) (bool, Violation) { if !k.isMoveCastlingMove(board, move) { return false, "" } if k.hadMovedBefore(board) { return false, "" } if board.isSquareAttacked(move.StartSquare, k.Color.Opposite()) { return false, CastlingWhileKingInCheck } valid, dir := k.isCastlingAllowed(board, move) if !valid { return false, "" } k.playCastlingOnBoard(board, move, dir) return true, "" } func (k King) hadMovedBefore(b *Board) bool { var hasMoved bool switch k.Color { case types.White: hasMoved = b.state.WhiteKingMoved case types.Black: hasMoved = b.state.BlackKingMoved } return hasMoved } type CastlingDirection string const ( NoDirection CastlingDirection = "" CastlingRight CastlingDirection = "right" CastlingLeft CastlingDirection = "left" ) func (k King) isMoveCastlingMove(b *Board, move types.Move) bool { var destinationSquareForKingRight types.Coordinate var destinationSquareForKingLeft types.Coordinate switch k.Color { case types.White: destinationSquareForKingRight = types.Coordinate{Col: 7, Row: 1} destinationSquareForKingLeft = types.Coordinate{Col: 3, Row: 1} case types.Black: destinationSquareForKingRight = types.Coordinate{Col: 7, Row: 8} destinationSquareForKingLeft = types.Coordinate{Col: 3, Row: 8} } if move.EndSquare == destinationSquareForKingRight || move.EndSquare == destinationSquareForKingLeft { return true } return false } func (k King) isCastlingAllowed(b *Board, move types.Move) (bool, CastlingDirection) { var valid = false switch k.Color { case types.White: destinationSquareForKingRight := types.Coordinate{Col: 7, Row: 1} destinationSquareForKingLeft := types.Coordinate{Col: 3, Row: 1} if move.EndSquare == destinationSquareForKingRight && b.getPieceAt(destinationSquareForKingRight) == nil && b.getPieceAt(*destinationSquareForKingRight.Left(1)) == nil && !b.isSquareAttacked(destinationSquareForKingRight, types.Black) && !b.isSquareAttacked(*destinationSquareForKingRight.Left(1), types.Black) && !b.state.WhiteHRookMoved { _, ok := b.getPieceAt(types.Coordinate{Col: 8, Row: 1}).(Rook) if ok { return true, CastlingRight } } if move.EndSquare == destinationSquareForKingLeft && b.getPieceAt(destinationSquareForKingLeft) == nil && b.getPieceAt(*destinationSquareForKingLeft.Right(1)) == nil && b.getPieceAt(*destinationSquareForKingLeft.Left(1)) == nil && !b.isSquareAttacked(destinationSquareForKingLeft, types.Black) && !b.isSquareAttacked(*destinationSquareForKingLeft.Right(1), types.Black) && !b.state.WhiteARookMoved { _, ok := b.getPieceAt(types.Coordinate{Col: 1, Row: 1}).(Rook) if ok { return true, CastlingLeft } } case types.Black: destinationSquareForKingRight := types.Coordinate{Col: 7, Row: 8} destinationSquareForKingLeft := types.Coordinate{Col: 3, Row: 8} if move.EndSquare == destinationSquareForKingRight && b.getPieceAt(destinationSquareForKingRight) == nil && b.getPieceAt(*destinationSquareForKingRight.Left(1)) == nil && !b.isSquareAttacked(destinationSquareForKingRight, types.White) && !b.isSquareAttacked(*destinationSquareForKingRight.Left(1), types.White) && !b.state.BlackHRookMoved { _, ok := b.getPieceAt(types.Coordinate{Col: 8, Row: 8}).(Rook) if ok { return true, CastlingRight } } if move.EndSquare == destinationSquareForKingLeft && b.getPieceAt(destinationSquareForKingLeft) == nil && b.getPieceAt(*destinationSquareForKingLeft.Right(1)) == nil && b.getPieceAt(*destinationSquareForKingLeft.Left(1)) == nil && !b.isSquareAttacked(destinationSquareForKingLeft, types.White) && !b.isSquareAttacked(*destinationSquareForKingLeft.Right(1), types.White) && !b.state.BlackARookMoved { _, ok := b.getPieceAt(types.Coordinate{Col: 1, Row: 8}).(Rook) if ok { return true, CastlingLeft } } } return valid, NoDirection } func (k King) playCastlingOnBoard(board *Board, move types.Move, dir CastlingDirection) { onRow := move.StartSquare.Row switch dir { case CastlingRight: delete(board.position, types.Coordinate{Col: 8, Row: onRow}) delete(board.position, types.Coordinate{Col: 5, Row: onRow}) board.position[types.Coordinate{Col: 7, Row: onRow}] = King{Color: k.Color} board.position[types.Coordinate{Col: 6, Row: onRow}] = Rook(k) case CastlingLeft: delete(board.position, types.Coordinate{Col: 1, Row: onRow}) delete(board.position, types.Coordinate{Col: 5, Row: onRow}) board.position[types.Coordinate{Col: 3, Row: onRow}] = King{Color: k.Color} board.position[types.Coordinate{Col: 4, Row: onRow}] = Rook(k) } }