Restructure special move handling.
This commit is contained in:
parent
a93b1a1aca
commit
81898d150b
@ -57,20 +57,18 @@ func (b *Board) Init() {
|
|||||||
b.position[types.Coordinate{Row: 8, Col: 8}] = Rook{Color: types.Black}
|
b.position[types.Coordinate{Row: 8, Col: 8}] = Rook{Color: types.Black}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
|
func (b *Board) CheckAndPlay(move types.Move) (bool, Violation) {
|
||||||
// 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
|
|
||||||
tempBoard := b.getCopyOfBoard()
|
tempBoard := b.getCopyOfBoard()
|
||||||
|
|
||||||
//Check start square of move
|
//Check start square of move
|
||||||
pieceAtStartSquare := tempBoard.getPieceAt(move.StartSquare)
|
pieceAtStartSquare := tempBoard.getPieceAt(move.StartSquare)
|
||||||
if pieceAtStartSquare == nil {
|
if pieceAtStartSquare == nil {
|
||||||
return false, "no piece at start square"
|
return false, NoPieceAtStartSquare
|
||||||
}
|
}
|
||||||
|
|
||||||
move.ColorMoved = pieceAtStartSquare.GetColor()
|
move.ColorMoved = pieceAtStartSquare.GetColor()
|
||||||
if move.ColorMoved != tempBoard.colorToMove {
|
if move.ColorMoved != tempBoard.colorToMove {
|
||||||
return false, "wrong color moved"
|
return false, WrongColorMoved
|
||||||
}
|
}
|
||||||
move.PieceMoved = GetShortNameForPiece(pieceAtStartSquare)
|
move.PieceMoved = GetShortNameForPiece(pieceAtStartSquare)
|
||||||
|
|
||||||
@ -78,19 +76,17 @@ func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
|
|||||||
pieceAtEndSquare := tempBoard.getPieceAt(move.EndSquare)
|
pieceAtEndSquare := tempBoard.getPieceAt(move.EndSquare)
|
||||||
if pieceAtEndSquare != nil {
|
if pieceAtEndSquare != nil {
|
||||||
if pieceAtEndSquare.GetColor() == pieceAtStartSquare.GetColor() {
|
if pieceAtEndSquare.GetColor() == pieceAtStartSquare.GetColor() {
|
||||||
return false, "same-coloured piece at end square"
|
return false, TargetSquareIsOccupied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasSpecialMove := tempBoard.handleSpecialMove(move)
|
wasSpecialMove, err := tempBoard.handleSpecialMove(move)
|
||||||
|
|
||||||
if !wasSpecialMove {
|
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.
|
|
||||||
allMovesExceptBlocked := pieceAtStartSquare.GetAllNonBlockedMoves(tempBoard, move.StartSquare)
|
allMovesExceptBlocked := pieceAtStartSquare.GetAllNonBlockedMoves(tempBoard, move.StartSquare)
|
||||||
legal := lo.Contains(allMovesExceptBlocked, move.EndSquare)
|
legal := lo.Contains(allMovesExceptBlocked, move.EndSquare)
|
||||||
if !legal {
|
if !legal {
|
||||||
return false, "not a legal square"
|
return false, InvalidMove
|
||||||
}
|
}
|
||||||
|
|
||||||
//We play the move on the temporary board
|
//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)
|
kingAttacked, err := tempBoard.isKingOfMovingColorInCheck(move.ColorMoved)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "something went wrong"
|
return false, SomethingWentWrong
|
||||||
}
|
}
|
||||||
if kingAttacked {
|
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
|
//We play the move on the real board
|
||||||
b.position = tempBoard.position
|
b.position = tempBoard.position
|
||||||
b.history = tempBoard.history
|
b.history = tempBoard.history
|
||||||
@ -202,18 +185,19 @@ func (p Position) getCopyOfPosition() Position {
|
|||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Board) handleSpecialMove(move types.Move) bool {
|
func (b *Board) handleSpecialMove(move types.Move) (bool, error) {
|
||||||
var was bool
|
var was bool
|
||||||
|
var err error
|
||||||
var pieceAtStartSquare = b.getPieceAt(move.StartSquare)
|
var pieceAtStartSquare = b.getPieceAt(move.StartSquare)
|
||||||
|
|
||||||
switch piece := pieceAtStartSquare.(type) {
|
switch piece := pieceAtStartSquare.(type) {
|
||||||
case Pawn:
|
case Pawn:
|
||||||
was = piece.HandlePossiblePromotion(b, move)
|
was, err = piece.HandlePossiblePromotion(b, move)
|
||||||
if !was {
|
if !was {
|
||||||
was = piece.HandleEnPassant(b, move, b.getLastMove())
|
was, err = piece.HandleEnPassant(b, move, b.getLastMove())
|
||||||
}
|
}
|
||||||
case King:
|
case King:
|
||||||
was = piece.HandleCastling(b, move)
|
was, err = piece.HandleCastling(b, move)
|
||||||
}
|
}
|
||||||
return was
|
return was, err
|
||||||
}
|
}
|
||||||
|
@ -75,13 +75,13 @@ func (game *Game) Handle() {
|
|||||||
gameState = CheckMove
|
gameState = CheckMove
|
||||||
|
|
||||||
case CheckMove:
|
case CheckMove:
|
||||||
valid, reason := game.board.CheckAndPlay(receivedMove)
|
valid, ruleViolation := game.board.CheckAndPlay(receivedMove)
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
gameState = CheckPlayerChange
|
gameState = CheckPlayerChange
|
||||||
} else {
|
} else {
|
||||||
log.Println("invalid move because " + reason)
|
log.Println(err)
|
||||||
invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, reason)
|
invalidMoveMessage, err := api.GetInvalidMoveMessage(receivedMove, ruleViolation.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
|
log.Println("Error marshalling 'colorDetermined' message for player 1", err)
|
||||||
return
|
return
|
||||||
|
@ -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) {
|
if k.hadMovedBefore(board) {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
valid, dir := k.movedOnValidCastlingSquare(board, move)
|
valid, dir := k.movedOnValidCastlingSquare(board, move)
|
||||||
if !valid {
|
if !valid {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch k.Color {
|
switch k.Color {
|
||||||
@ -47,7 +47,7 @@ func (k King) HandleCastling(board *Board, move types.Move) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
k.playCastlingOnBoard(board, move, dir)
|
k.playCastlingOnBoard(board, move, dir)
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k King) hadMovedBefore(b *Board) bool {
|
func (k King) hadMovedBefore(b *Board) bool {
|
||||||
|
@ -32,7 +32,7 @@ func (p Pawn) GetColor() types.ChessColor {
|
|||||||
return p.Color
|
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 isPromotionMove bool
|
||||||
var promotionToPiece types.PieceShortName
|
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)
|
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
|
var wasEnPassant bool
|
||||||
|
|
||||||
if lastMove.PieceMoved != types.PawnShortName {
|
if lastMove.PieceMoved != types.PawnShortName {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch move.ColorMoved {
|
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)
|
b.position[move.EndSquare] = GetPieceForShortName(move.PieceMoved, move.ColorMoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
return wasEnPassant
|
return wasEnPassant, nil
|
||||||
}
|
}
|
||||||
func (p Pawn) getAllMoves(fromSquare types.Coordinate) []types.Coordinate {
|
func (p Pawn) getAllMoves(fromSquare types.Coordinate) []types.Coordinate {
|
||||||
theoreticalMoves := make([]types.Coordinate, 0, 4)
|
theoreticalMoves := make([]types.Coordinate, 0, 4)
|
||||||
|
16
chess/violation.go
Normal file
16
chess/violation.go
Normal file
@ -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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user