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 }