diff --git a/chess/board.go b/chess/board.go index 0695c34..e85c84e 100644 --- a/chess/board.go +++ b/chess/board.go @@ -57,20 +57,18 @@ func (b *Board) Init() { b.position[types.Coordinate{Row: 8, Col: 8}] = Rook{Color: types.Black} } -func (b *Board) CheckAndPlay(move types.Move) (bool, string) { - // We make a copy of the original board to play moves on it, - // We can play the move on it and then check if it is invalid +func (b *Board) CheckAndPlay(move types.Move) (bool, Violation) { tempBoard := b.getCopyOfBoard() //Check start square of move pieceAtStartSquare := tempBoard.getPieceAt(move.StartSquare) if pieceAtStartSquare == nil { - return false, "no piece at start square" + return false, NoPieceAtStartSquare } move.ColorMoved = pieceAtStartSquare.GetColor() if move.ColorMoved != tempBoard.colorToMove { - return false, "wrong color moved" + return false, WrongColorMoved } move.PieceMoved = GetShortNameForPiece(pieceAtStartSquare) @@ -78,19 +76,17 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) { pieceAtEndSquare := tempBoard.getPieceAt(move.EndSquare) if pieceAtEndSquare != nil { if pieceAtEndSquare.GetColor() == pieceAtStartSquare.GetColor() { - return false, "same-coloured piece at end square" + return false, TargetSquareIsOccupied } } - wasSpecialMove := tempBoard.handleSpecialMove(move) - - if !wasSpecialMove { - // 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. + wasSpecialMove, err := tempBoard.handleSpecialMove(move) + + if !wasSpecialMove { allMovesExceptBlocked := pieceAtStartSquare.GetAllNonBlockedMoves(tempBoard, move.StartSquare) legal := lo.Contains(allMovesExceptBlocked, move.EndSquare) if !legal { - return false, "not a legal square" + return false, InvalidMove } //We play the move on the temporary board @@ -100,25 +96,12 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) { kingAttacked, err := tempBoard.isKingOfMovingColorInCheck(move.ColorMoved) if err != nil { - return false, "something went wrong" + return false, SomethingWentWrong } if kingAttacked { - return false, "king would be in check after move" + return false, KingInCheck } - //Check for checkmat&e - //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 on the real board b.position = tempBoard.position b.history = tempBoard.history @@ -202,18 +185,19 @@ func (p Position) getCopyOfPosition() Position { return position } -func (b *Board) handleSpecialMove(move types.Move) bool { +func (b *Board) handleSpecialMove(move types.Move) (bool, error) { var was bool + var err error var pieceAtStartSquare = b.getPieceAt(move.StartSquare) switch piece := pieceAtStartSquare.(type) { case Pawn: - was = piece.HandlePossiblePromotion(b, move) + was, err = piece.HandlePossiblePromotion(b, move) if !was { - was = piece.HandleEnPassant(b, move, b.getLastMove()) + was, err = piece.HandleEnPassant(b, move, b.getLastMove()) } case King: - was = piece.HandleCastling(b, move) + was, err = piece.HandleCastling(b, move) } - return was + return was, err } diff --git a/chess/game.go b/chess/game.go index 5af9643..114111c 100644 --- a/chess/game.go +++ b/chess/game.go @@ -75,13 +75,13 @@ func (game *Game) Handle() { gameState = CheckMove case CheckMove: - valid, reason := game.board.CheckAndPlay(receivedMove) + valid, ruleViolation := game.board.CheckAndPlay(receivedMove) if valid { gameState = CheckPlayerChange } else { - log.Println("invalid move because " + reason) - invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, reason) + log.Println(err) + invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, ruleViolation.String()) if err != nil { log.Println("Error marshalling 'colorDetermined' message for player 1", err) return diff --git a/chess/king.go b/chess/king.go index 2891db2..844824c 100644 --- a/chess/king.go +++ b/chess/king.go @@ -29,14 +29,14 @@ func (k King) AfterMoveAction(board *Board, fromSquare types.Coordinate) { } } -func (k King) HandleCastling(board *Board, move types.Move) bool { +func (k King) HandleCastling(board *Board, move types.Move) (bool,error) { if k.hadMovedBefore(board) { - return false + return false, nil } valid, dir := k.movedOnValidCastlingSquare(board, move) if !valid { - return false + return false, nil } switch k.Color { @@ -47,7 +47,7 @@ func (k King) HandleCastling(board *Board, move types.Move) bool { } k.playCastlingOnBoard(board, move, dir) - return true + return true, nil } func (k King) hadMovedBefore(b *Board) bool { diff --git a/chess/pawn.go b/chess/pawn.go index 916363f..95f9de8 100644 --- a/chess/pawn.go +++ b/chess/pawn.go @@ -32,7 +32,7 @@ func (p Pawn) GetColor() types.ChessColor { return p.Color } -func (p *Pawn) HandlePossiblePromotion(b *Board, move types.Move) bool { +func (p *Pawn) HandlePossiblePromotion(b *Board, move types.Move) (bool,error) { var isPromotionMove bool var promotionToPiece types.PieceShortName @@ -62,14 +62,14 @@ func (p *Pawn) HandlePossiblePromotion(b *Board, move types.Move) bool { b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved) } - return isPromotionMove + return isPromotionMove, nil } -func (p *Pawn) HandleEnPassant(b *Board, move, lastMove types.Move) bool { +func (p *Pawn) HandleEnPassant(b *Board, move, lastMove types.Move) (bool, error){ var wasEnPassant bool if lastMove.PieceMoved != types.PawnShortName { - return false + return false, nil } switch move.ColorMoved { @@ -126,7 +126,7 @@ func (p *Pawn) HandleEnPassant(b *Board, move, lastMove types.Move) bool { b.position[move.EndSquare] = GetPieceForShortName(move.PieceMoved, move.ColorMoved) } - return wasEnPassant + return wasEnPassant, nil } func (p Pawn) getAllMoves(fromSquare types.Coordinate) []types.Coordinate { theoreticalMoves := make([]types.Coordinate, 0, 4) diff --git a/chess/violation.go b/chess/violation.go new file mode 100644 index 0000000..82ad7d4 --- /dev/null +++ b/chess/violation.go @@ -0,0 +1,16 @@ +package chess + +type Violation string + +var ( + InvalidMove Violation = "invalid move" + NoPieceAtStartSquare Violation = "no piece at start square" + WrongColorMoved Violation = "wrong color moved" + TargetSquareIsOccupied Violation = "target square is occupied" + KingInCheck Violation = "king would be in check after move" + SomethingWentWrong Violation = "something went wrong" +) + +func (v Violation) String() string { + return string(v) +}