Implement en passant and much more!

This commit is contained in:
Marco 2023-06-26 00:51:20 +02:00
parent 9793c37582
commit f79e5be008
6 changed files with 343 additions and 101 deletions

View File

@ -6,67 +6,76 @@ import (
"github.com/samber/lo" "github.com/samber/lo"
) )
type Board map[types.Coordinate]Piece type Position map[types.Coordinate]Piece
func (b Board) Init() { type Board struct {
position Position
history []types.Move
}
func newBoard() Board {
return Board{
position: make(Position),
history: make([]types.Move, 0),
}
}
func (b *Board) Init() {
var coord types.Coordinate var coord types.Coordinate
for i := 1; i <= 8; i++ { for i := 1; i <= 8; i++ {
coord.Row = 2 coord.Row = 2
coord.Col = i coord.Col = i
b[coord] = Pawn{Color: types.White} b.position[coord] = Pawn{Color: types.White}
coord.Row = 7 coord.Row = 7
coord.Col = i coord.Col = i
b[coord] = Pawn{Color: types.Black} b.position[coord] = Pawn{Color: types.Black}
} }
b[types.Coordinate{Row: 1, Col: 1}] = Rook{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 1}] = Rook{Color: types.White}
b[types.Coordinate{Row: 1, Col: 2}] = Knight{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 2}] = Knight{Color: types.White}
b[types.Coordinate{Row: 1, Col: 3}] = Bishop{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 3}] = Bishop{Color: types.White}
b[types.Coordinate{Row: 1, Col: 4}] = Queen{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 4}] = Queen{Color: types.White}
b[types.Coordinate{Row: 1, Col: 5}] = King{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 5}] = King{Color: types.White}
b[types.Coordinate{Row: 1, Col: 6}] = Bishop{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 6}] = Bishop{Color: types.White}
b[types.Coordinate{Row: 1, Col: 7}] = Knight{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 7}] = Knight{Color: types.White}
b[types.Coordinate{Row: 1, Col: 8}] = Rook{Color: types.White} b.position[types.Coordinate{Row: 1, Col: 8}] = Rook{Color: types.White}
b[types.Coordinate{Row: 8, Col: 1}] = Rook{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 1}] = Rook{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 2}] = Knight{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 2}] = Knight{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 3}] = Bishop{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 3}] = Bishop{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 4}] = Queen{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 4}] = Queen{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 5}] = King{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 5}] = King{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 6}] = Bishop{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 6}] = Bishop{Color: types.Black}
b[types.Coordinate{Row: 8, Col: 7}] = Knight{Color: types.Black} b.position[types.Coordinate{Row: 8, Col: 7}] = Knight{Color: types.Black}
b[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) CheckMove(move types.Move) (bool, string) { func (b *Board) CheckAndPlay(move types.Move) (bool, string) {
// We make a copy of the original board to play moves on it, // 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 // 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 := b.getPieceAt(move.StartSquare) pieceAtStartSquare := tempBoard.getPieceAt(move.StartSquare)
if pieceAtStartSquare == nil { if pieceAtStartSquare == nil {
return false, "no piece at start square" return false, "no piece at start square"
} }
movingColor := pieceAtStartSquare.GetColor() move.ColorMoved = pieceAtStartSquare.GetColor()
move.PieceMoved = GetShortNameForPiece(pieceAtStartSquare)
//Check end square of move //Check end square of move
pieceAtEndSquare := b.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, "same-coloured piece at end square"
} }
} }
var wasPromotionMove bool
// var piece types.PieceShortName
switch pieceAtStartSquare.(type) {
case Pawn:
wasPromotionMove, _ = tempBoard.handlePossiblePromotion(move, movingColor)
}
if !wasPromotionMove { wasSpecialMove := tempBoard.handleSpecialMove(move)
if !wasSpecialMove {
// At the moment, we do not need to check if the correct color is moving, // 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. //since we are only reading moves from the player whose turn it is.
allMovesExceptBlocked := pieceAtStartSquare.GetAllMovesButBlocked(tempBoard, move.StartSquare) allMovesExceptBlocked := pieceAtStartSquare.GetAllMovesButBlocked(tempBoard, move.StartSquare)
@ -76,18 +85,18 @@ func (b Board) CheckMove(move types.Move) (bool, string) {
} }
//We play the move on the temporary board //We play the move on the temporary board
delete(tempBoard, move.StartSquare) delete(tempBoard.position, move.StartSquare)
tempBoard[move.EndSquare] = pieceAtStartSquare tempBoard.position[move.EndSquare] = pieceAtStartSquare
} }
//Check if king of moving color is in check -> move not allowed //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. //Do that by checking if the king is in a square attacked by the other color.
ownKingCoordinate := tempBoard.getSquareOfPiece(King{Color: movingColor}) ownKingCoordinate := tempBoard.getSquareOfPiece(King{Color: move.ColorMoved})
if ownKingCoordinate == nil { if ownKingCoordinate == nil {
return false, string(movingColor) + " king not found" return false, string(move.ColorMoved) + " king not found"
} }
kingIsAttacked := tempBoard.isSquareAttacked(*ownKingCoordinate, movingColor.Opposite()) kingIsAttacked := tempBoard.isSquareAttacked(*ownKingCoordinate, move.ColorMoved.Opposite())
if kingIsAttacked { if kingIsAttacked {
return false, "king is attacked after move" return false, "king is attacked after move"
} }
@ -106,13 +115,15 @@ func (b Board) CheckMove(move types.Move) (bool, string) {
// If a piece can be moved into the path, it is no checkmate // 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 = tempBoard b.position = tempBoard.position
b.history = tempBoard.history
b.appendMoveToHistory(move)
return true, "" return true, ""
} }
func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate { func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
for k, v := range b { for k, v := range b.position {
if v == piece { if v == piece {
return &k return &k
} }
@ -123,7 +134,7 @@ func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColor) bool { func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColor) bool {
var attackedSquares []types.Coordinate var attackedSquares []types.Coordinate
for square, piece := range b { for square, piece := range b.position {
attackedSquares = append(attackedSquares, piece.GetAllMovesButBlocked(b, square)...) attackedSquares = append(attackedSquares, piece.GetAllMovesButBlocked(b, square)...)
} }
@ -131,7 +142,7 @@ func (b Board) isSquareAttacked(square types.Coordinate, byColor types.ChessColo
} }
func (b Board) getPieceAt(coord types.Coordinate) Piece { func (b Board) getPieceAt(coord types.Coordinate) Piece {
piece, found := b[coord] piece, found := b.position[coord]
if !found { if !found {
return nil return nil
} }
@ -139,17 +150,59 @@ func (b Board) getPieceAt(coord types.Coordinate) Piece {
return piece return piece
} }
func (b Board) handlePossiblePromotion(move types.Move, color types.ChessColor) (bool, types.PieceShortName) { func (b *Board) appendMoveToHistory(move types.Move) {
b.history = append(b.history, move)
}
func (b Board) getLastMove() types.Move {
if len(b.history) < 1 {
return types.Move{}
}
return b.history[len(b.history)-1]
}
func (b Board) getCopyOfBoard() Board {
return Board{
position: b.position.getCopyOfPosition(),
history: b.history,
}
}
func (p Position) getCopyOfPosition() Position {
position := make(Position)
for coord, piece := range p {
position[coord] = piece
}
return position
}
func (b *Board) handleSpecialMove(move types.Move) bool {
var was bool
var pieceAtStartSquare = b.getPieceAt(move.StartSquare)
switch pieceAtStartSquare.(type) {
case Pawn:
was = b.handlePossiblePromotion(move)
if !was {
was = b.handleEnPassant(move, b.getLastMove())
}
}
return was
}
func (b *Board) handlePossiblePromotion(move types.Move) bool {
var isPromotionMove bool var isPromotionMove bool
var promotionToPiece types.PieceShortName var promotionToPiece types.PieceShortName
//TODO(m): What if message does not contain a promotion, but should be because a pawn is moved to the end square
messageContainsPromotion := move.IsPromotionMove() messageContainsPromotion := move.IsPromotionMove()
if messageContainsPromotion { if messageContainsPromotion {
promotionToPiece = *move.PromotionToPiece promotionToPiece = *move.PromotionToPiece
} }
switch color { switch move.ColorMoved {
case types.White: case types.White:
if move.StartSquare.Row == types.RangeLastValid-1 && if move.StartSquare.Row == types.RangeLastValid-1 &&
move.EndSquare.Row == types.RangeLastValid { move.EndSquare.Row == types.RangeLastValid {
@ -164,19 +217,63 @@ func (b Board) handlePossiblePromotion(move types.Move, color types.ChessColor)
} }
if isPromotionMove { if isPromotionMove {
delete(b, move.StartSquare) delete(b.position, move.StartSquare)
b[move.EndSquare] = GetPieceForShortName(promotionToPiece) b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved)
} }
return isPromotionMove, promotionToPiece return isPromotionMove
} }
func (b Board) getCopyOfBoard() Board { func (b *Board) handleEnPassant(move, lastMove types.Move) bool {
board := make(map[types.Coordinate]Piece) var wasEnPassant bool
for coord, piece := range b { if lastMove.PieceMoved != types.PawnShortName {
board[coord] = piece return false
} }
return board switch move.ColorMoved {
case types.White:
if lastMove.StartSquare.Row != 7 || lastMove.EndSquare.Row != 5 {
wasEnPassant = false
}
if move.StartSquare.Row != 5 {
wasEnPassant = false
}
if move.EndSquare.Row != 6 {
wasEnPassant = false
}
if move.StartSquare.Col == lastMove.EndSquare.Col+1 &&
move.EndSquare.Col == lastMove.EndSquare.Col {
wasEnPassant = true
}
if move.StartSquare.Col == lastMove.EndSquare.Col-1 &&
move.EndSquare.Col == lastMove.EndSquare.Col {
wasEnPassant = true
}
case types.Black:
if lastMove.StartSquare.Row != 2 || lastMove.EndSquare.Row != 4 {
wasEnPassant = false
}
if move.StartSquare.Row != 4 {
wasEnPassant = false
}
if move.EndSquare.Row != 3 {
wasEnPassant = false
}
if move.StartSquare.Col == lastMove.EndSquare.Col+1 &&
move.EndSquare.Col == lastMove.EndSquare.Col {
wasEnPassant = true
}
if move.StartSquare.Col == lastMove.EndSquare.Col-1 &&
move.EndSquare.Col == lastMove.EndSquare.Col {
wasEnPassant = true
}
}
if wasEnPassant { //play the move
delete(b.position, lastMove.EndSquare)
b.position[move.EndSquare] = GetPieceForShortName(move.PieceMoved, move.ColorMoved)
}
return wasEnPassant
} }

View File

@ -8,64 +8,191 @@ import (
) )
func Test_CheckMove_validPawnMove(t *testing.T) { func Test_CheckMove_validPawnMove(t *testing.T) {
var board = make(Board) var board = newBoard()
board[types.Coordinate{Col: 1, Row: 1}] = Pawn{Color: types.White} board.position[types.Coordinate{Col: 1, Row: 2}] = Pawn{Color: types.White}
board[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White} board.position[types.Coordinate{Col: 2, Row: 4}] = Pawn{Color: types.Black}
board[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black} board.position[types.Coordinate{Col: 5, Row: 1}] = King{Color: types.White}
board.position[types.Coordinate{Col: 5, Row: 8}] = King{Color: types.Black}
move := types.Move{ move := types.Move{
StartSquare: types.Coordinate{Col: 1, Row: 1}, StartSquare: types.Coordinate{Col: 1, Row: 2},
EndSquare: types.Coordinate{Col: 1, Row: 2}, EndSquare: types.Coordinate{Col: 1, Row: 3},
} }
good, _ := board.CheckMove(move) good, _ := board.CheckAndPlay(move)
assert.True(t, good)
//we take the pawn
secondMove := types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 4},
EndSquare: types.Coordinate{Col: 1, Row: 3},
}
good, _ = board.CheckAndPlay(secondMove)
assert.True(t, good) assert.True(t, good)
} }
func Test_CheckMove_invalidPawnMoves(t *testing.T) { func Test_CheckMove_enPassant(t *testing.T) {
var board = make(Board) var board = newBoard()
board[types.Coordinate{Col: 2, Row: 5}] = Pawn{Color: types.White} board.position[types.Coordinate{Col: 6, Row: 4}] = Pawn{Color: types.Black}
board[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White} board.position[types.Coordinate{Col: 5, Row: 2}] = Pawn{Color: types.White}
board[types.Coordinate{Col: 7, Row: 5}] = Queen{Color: types.Black} board.position[types.Coordinate{Col: 5, Row: 1}] = King{Color: types.White}
board[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black} board.position[types.Coordinate{Col: 5, Row: 8}] = King{Color: types.Black}
move := types.Move{
StartSquare: types.Coordinate{Col: 5, Row: 2},
EndSquare: types.Coordinate{Col: 5, Row: 4},
}
good, reason := board.CheckAndPlay(move)
assert.True(t, good)
assert.Empty(t, reason)
assert.Equal(t, Pawn{Color: types.White}, board.position[types.Coordinate{Col: 5, Row: 4}])
newMove := types.Move{
StartSquare: types.Coordinate{Col: 6, Row: 4},
EndSquare: types.Coordinate{Col: 5, Row: 3},
}
good, reason = board.CheckAndPlay(newMove)
assert.True(t, good)
assert.Empty(t, reason)
// the black pawn is on its correct square
assert.Equal(t, Pawn{Color: types.Black}, board.position[types.Coordinate{Col: 5, Row: 3}])
//the white pawn is gone
assert.Nil(t, board.position[types.Coordinate{Col: 5, Row: 4}])
}
func Test_CheckMove_invalidPawnMoves(t *testing.T) {
t.Run("pawn is blocked", func(t *testing.T) {
var board = newBoard()
board.position[types.Coordinate{Col: 2, Row: 5}] = Pawn{Color: types.White}
board.position[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White}
board.position[types.Coordinate{Col: 7, Row: 5}] = Queen{Color: types.Black}
board.position[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black}
board.position[types.Coordinate{Col: 2, Row: 6}] = Pawn{Color: types.Black}
move := types.Move{ move := types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 5}, StartSquare: types.Coordinate{Col: 2, Row: 5},
EndSquare: types.Coordinate{Col: 2, Row: 6}, EndSquare: types.Coordinate{Col: 2, Row: 6},
} }
legalMove, _ := board.CheckAndPlay(move)
t.Run("pawn is blocked", func(t *testing.T) {
testBoard := board.getCopyOfBoard()
testBoard[types.Coordinate{Col: 2, Row: 6}] = Pawn{Color: types.Black}
legalMove, _ := testBoard.CheckMove(move)
assert.False(t, legalMove) assert.False(t, legalMove)
}) })
t.Run("king of moving color is in check after move", func(t *testing.T) { t.Run("pawn moves to the side", func(t *testing.T) {
good, _ := board.CheckMove(move) var board = newBoard()
assert.False(t, good) boardBeforeMove := board
board.position[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White}
board.position[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black}
board.position[types.Coordinate{Col: 2, Row: 5}] = Pawn{Color: types.White}
move := types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 5},
EndSquare: types.Coordinate{Col: 3, Row: 5},
}
legal, _ := board.CheckAndPlay(move)
assert.False(t, legal)
assert.Equal(t, boardBeforeMove, board)
move = types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 5},
EndSquare: types.Coordinate{Col: 1, Row: 5},
}
legal, _ = board.CheckAndPlay(move)
assert.False(t, legal)
assert.Equal(t, boardBeforeMove, board)
move = types.Move{
StartSquare: types.Coordinate{Col: 2, Row: 5},
EndSquare: types.Coordinate{Col: 6, Row: 5},
}
legal, _ = board.CheckAndPlay(move)
assert.False(t, legal)
assert.Equal(t, boardBeforeMove, board)
}) })
// t.Run("king of moving color is in check after move", func(t *testing.T) {
// good, _ := board.CheckMove(move)
// assert.False(t, good)
// })
} }
func Test_CheckMove_validPromotion(t *testing.T) { func Test_CheckMove_validPromotion(t *testing.T) {
var board Board = make(Board) var board Board = newBoard()
board[types.Coordinate{Col: 1, Row: 7}] = Pawn{Color: types.White} board.position[types.Coordinate{Col: 1, Row: 7}] = Pawn{Color: types.White}
board[types.Coordinate{Col: 1, Row: 1}] = King{Color: types.White} board.position[types.Coordinate{Col: 1, Row: 1}] = King{Color: types.White}
board[types.Coordinate{Col: 8, Row: 7}] = King{Color: types.Black} board.position[types.Coordinate{Col: 8, Row: 7}] = King{Color: types.Black}
shortName := types.Queen shortName := types.QueenShortName
move := types.Move{ move := types.Move{
StartSquare: types.Coordinate{Col: 1, Row: 7}, StartSquare: types.Coordinate{Col: 1, Row: 7},
EndSquare: types.Coordinate{Col: 1, Row: 8}, EndSquare: types.Coordinate{Col: 1, Row: 8},
PromotionToPiece: &shortName, PromotionToPiece: &shortName,
} }
good, reason := board.CheckAndPlay(move)
good, reason := board.CheckMove(move)
assert.Empty(t, reason) assert.Empty(t, reason)
assert.True(t, good) assert.True(t, good)
assert.Equal(t, Queen{Color: types.White}, board.getPieceAt(types.Coordinate{Row: 8, Col: 1}))
}
func Test_CheckMove_HistoryWorks(t *testing.T) {
var board = newBoard()
board.position[types.Coordinate{Col: 3, Row: 7}] = Pawn{Color: types.Black}
board.position[types.Coordinate{Col: 1, Row: 2}] = Pawn{Color: types.White}
board.position[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White}
board.position[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black}
firstMove := types.Move{
StartSquare: types.Coordinate{Col: 1, Row: 2},
EndSquare: types.Coordinate{Col: 1, Row: 3},
}
secondMove := types.Move{
StartSquare: types.Coordinate{Col: 3, Row: 7},
EndSquare: types.Coordinate{Col: 3, Row: 5},
}
thirdMove := types.Move{
StartSquare: types.Coordinate{Col: 1, Row: 3},
EndSquare: types.Coordinate{Col: 1, Row: 4},
}
good, _ := board.CheckAndPlay(firstMove)
assert.True(t, good)
good, _ = board.CheckAndPlay(secondMove)
assert.True(t, good)
good, _ = board.CheckAndPlay(thirdMove)
assert.True(t, good)
expectedHistory := []types.Move{
{
StartSquare: types.Coordinate{Col: 1, Row: 2},
EndSquare: types.Coordinate{Col: 1, Row: 3},
PieceMoved: 'p',
ColorMoved: "white",
},
{
StartSquare: types.Coordinate{Col: 3, Row: 7},
EndSquare: types.Coordinate{Col: 3, Row: 5},
PieceMoved: 'p',
ColorMoved: "black",
},
{
StartSquare: types.Coordinate{Col: 1, Row: 3},
EndSquare: types.Coordinate{Col: 1, Row: 4},
PieceMoved: 'p',
ColorMoved: "white",
},
}
assert.Equal(t, expectedHistory, board.history)
} }

View File

@ -1,9 +1,9 @@
package chess package chess
import ( import (
"log"
"mchess_server/api" "mchess_server/api"
"mchess_server/types" "mchess_server/types"
"log"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
@ -25,7 +25,7 @@ const (
func NewGame() *Game { func NewGame() *Game {
var game Game = Game{ var game Game = Game{
id: uuid.New(), id: uuid.New(),
board: make(map[types.Coordinate]Piece), board: newBoard(),
} }
game.board.Init() game.board.Init()
@ -75,7 +75,7 @@ func (game *Game) Handle() {
gameState = CheckMove gameState = CheckMove
case CheckMove: case CheckMove:
valid, reason := game.board.CheckMove(receivedMove) valid, reason := game.board.CheckAndPlay(receivedMove)
if valid { if valid {
gameState = CheckPlayerChange gameState = CheckPlayerChange

View File

@ -9,22 +9,41 @@ type Piece interface {
GetColor() types.ChessColor GetColor() types.ChessColor
} }
func GetPieceForShortName(name types.PieceShortName) Piece { func GetPieceForShortName(name types.PieceShortName, color types.ChessColor) Piece {
var piece Piece var piece Piece
switch name { switch name {
case 'p': case 'p':
piece = Pawn{} piece = Pawn{Color: color}
case 'q': case 'q':
piece = Queen{} piece = Queen{Color: color}
case 'k': case 'k':
piece = King{} piece = King{Color: color}
case 'b': case 'b':
piece = Bishop{} piece = Bishop{Color: color}
case 'r': case 'r':
piece = Rook{} piece = Rook{Color: color}
case 'n': case 'n':
piece = Knight{} piece = Knight{Color: color}
} }
return piece return piece
} }
func GetShortNameForPiece(piece Piece) types.PieceShortName {
var name types.PieceShortName
switch piece.(type) {
case Pawn:
name = 'p'
case Queen:
name = 'q'
case King:
name = 'k'
case Bishop:
name = 'b'
case Rook:
name = 'r'
case Knight:
name = 'n'
}
return name
}

View File

@ -3,12 +3,11 @@ package types
type Move struct { type Move struct {
StartSquare Coordinate `json:"startSquare"` StartSquare Coordinate `json:"startSquare"`
EndSquare Coordinate `json:"endSquare"` EndSquare Coordinate `json:"endSquare"`
PieceMoved PieceShortName
ColorMoved ChessColor
PromotionToPiece *PieceShortName `json:"promotionToPiece,omitempty"` PromotionToPiece *PieceShortName `json:"promotionToPiece,omitempty"`
} }
func (m Move) IsPromotionMove() bool { func (m Move) IsPromotionMove() bool {
if m.PromotionToPiece != nil { return m.PromotionToPiece != nil
return true
}
return false
} }

View File

@ -3,10 +3,10 @@ package types
type PieceShortName rune type PieceShortName rune
const ( const (
Pawn PieceShortName = 'p' PawnShortName PieceShortName = 'p'
Rook PieceShortName = 'r' RookShortName PieceShortName = 'r'
Knight PieceShortName = 'n' KnightShortName PieceShortName = 'n'
Bishop PieceShortName = 'b' BishopShortName PieceShortName = 'b'
Queen PieceShortName = 'q' QueenShortName PieceShortName = 'q'
King PieceShortName = 'k' KingShortName PieceShortName = 'k'
) )