mchess-server/chess/king.go

175 lines
5.2 KiB
Go

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)
}
}