mchess-server/chess/board.go

125 lines
3.7 KiB
Go

package chess
import (
"local/m/mchess_server/types"
"github.com/samber/lo"
)
type Board map[types.Coordinate]Piece
func (b Board) Init() {
var coord types.Coordinate
for i := 1; i <= 8; i++ {
coord.Row = 2
coord.Col = i
b[coord] = Pawn{Color: types.White, HasMoved: false}
coord.Row = 7
coord.Col = i
b[coord] = Pawn{Color: types.Black, HasMoved: false}
}
b[types.Coordinate{Row: 1, Col: 1}] = Rook{Color: types.White}
b[types.Coordinate{Row: 1, Col: 2}] = Knight{Color: types.White}
b[types.Coordinate{Row: 1, Col: 3}] = Bishop{Color: types.White}
b[types.Coordinate{Row: 1, Col: 4}] = Queen{Color: types.White}
b[types.Coordinate{Row: 1, Col: 5}] = King{Color: types.White}
b[types.Coordinate{Row: 1, Col: 6}] = Bishop{Color: types.White}
b[types.Coordinate{Row: 1, Col: 7}] = Knight{Color: types.White}
b[types.Coordinate{Row: 1, Col: 8}] = Rook{Color: types.White}
b[types.Coordinate{Row: 8, Col: 1}] = Rook{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 2}] = Knight{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 3}] = Bishop{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 4}] = Queen{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 5}] = King{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 6}] = Bishop{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 7}] = Knight{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 8}] = Rook{Color: types.Black}
}
func (b Board) CheckMove(move types.Move) (bool, string) {
pieceAtStartSquare := b.getPieceAt(move.StartSquare)
if pieceAtStartSquare == nil {
return false, "no piece at start square"
}
movingColor := pieceAtStartSquare.GetColor()
pieceAtEndSquare := b.getPieceAt(move.EndSquare)
if pieceAtEndSquare != nil {
if pieceAtEndSquare.GetColor() == pieceAtStartSquare.GetColor() {
return false, "same-coloured piece at end square"
}
}
// At the moment, we do not need to check if the correct color is moving,
//since we are only reading moves from the player whose turn it is.
legal := lo.Contains(pieceAtStartSquare.GetAllLegalAndIllegalMoves(b, move.StartSquare), move.EndSquare)
if !legal {
return false, "not a legal square"
}
//Check if king of moving color is in check -> move not allowed
//Do that by checking if the king is in a square attacked by the other color.
ownKingCoordinate := b.getSquareOfPiece(King{Color: movingColor})
if ownKingCoordinate == nil {
return false, string(movingColor) + " king not found"
}
kingIsAttacked := b.isSquareAttacked(*ownKingCoordinate, movingColor.Opposite())
if kingIsAttacked {
return false, "king is attacked after move"
}
//Check for checkmate
//Is every square that the king can move to attacked? And can no other
//piece block? -> checkmate
//only check if paths of attacking pieces can be blocked
//Maybe for checking checkmate, we have to check the 'path' in which the
//checkmate is given
// |K| | | | |Q|
// in this scenaria the path are all the squares between queen and king.
// If a piece can be moved into the path, it is no checkmate
//We play the move
delete(b, move.StartSquare)
b[move.EndSquare] = pieceAtStartSquare
pieceAtStartSquare.AfterMoveAction()
return true, ""
}
func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
for k, v := range b {
if v == piece {
return &k
}
}
return nil
}
func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColor) bool {
var attackedSquares []types.Coordinate
for square, piece := range b {
attackedSquares = append(attackedSquares, piece.GetAllLegalAndIllegalMoves(b, square)...)
}
return lo.Contains(attackedSquares, square)
}
func (b Board) getPieceAt(coord types.Coordinate) Piece {
piece, found := b[coord]
if !found {
return nil
}
return piece
}