mchess-server/chess/king.go
Marco ff2ec599fe Introduce PGN helpers
In order to simplify special moves like en passant or castling for the
client, we want to deliver the board state after every move (and not
only start square and end square).

With PGN we can encode a chess position into a string.
This commit implies changes to logic of the pieces' shortnames. This
will break the client/server connection (at least for promotions).
2023-08-12 11:24:40 +02:00

131 lines
3.5 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.GetAllNonBlockedMoves(board, fromSquare)
}
func (k King) GetColor() types.ChessColor {
return k.Color
}
func (k King) GetAllNonBlockedMoves(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, error) {
if k.hadMovedBefore(board) {
return false, nil
}
valid, dir := k.movedOnValidCastlingSquare(board, move)
if !valid {
return false, nil
}
switch k.Color {
case types.White:
board.state.WhiteKingMoved = true
case types.Black:
board.state.BlackKingMoved = true
}
k.playCastlingOnBoard(board, move, dir)
return true, nil
}
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 (
CastlingRight CastlingDirection = "right"
CastlingLeft CastlingDirection = "left"
)
func (k King) movedOnValidCastlingSquare(b *Board, move types.Move) (bool, CastlingDirection) {
var valid = false
switch k.Color {
case types.White:
castlingSquareRight := types.Coordinate{Col: 7, Row: 1}
castlingSquareLeft := types.Coordinate{Col: 3, Row: 1}
if move.EndSquare == castlingSquareRight &&
b.getPieceAt(castlingSquareRight) == nil &&
b.getPieceAt(*castlingSquareRight.Left(1)) == nil &&
!b.state.WhiteHRookMoved {
return true, CastlingRight
}
if move.EndSquare == castlingSquareLeft &&
b.getPieceAt(castlingSquareLeft) == nil &&
b.getPieceAt(*castlingSquareLeft.Right(1)) == nil &&
b.getPieceAt(*castlingSquareLeft.Left(1)) == nil &&
!b.state.WhiteARookMoved {
return true, CastlingLeft
}
case types.Black:
castlingSquareRight := types.Coordinate{Col: 7, Row: 8}
castlingSquareLeft := types.Coordinate{Col: 3, Row: 8}
if move.EndSquare == castlingSquareRight &&
b.getPieceAt(castlingSquareRight) == nil &&
b.getPieceAt(*castlingSquareRight.Left(1)) == nil &&
!b.state.BlackHRookMoved {
return true, CastlingRight
}
if move.EndSquare == castlingSquareLeft &&
b.getPieceAt(castlingSquareLeft) == nil &&
b.getPieceAt(*castlingSquareLeft.Right(1)) == nil &&
b.getPieceAt(*castlingSquareLeft.Left(1)) == nil &&
!b.state.BlackARookMoved {
return true, CastlingLeft
}
}
return valid, CastlingRight
}
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)
}
}