Implement en passant and much more!
This commit is contained in:
parent
9793c37582
commit
f79e5be008
197
chess/board.go
197
chess/board.go
@ -6,67 +6,76 @@ import (
|
||||
"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
|
||||
|
||||
for i := 1; i <= 8; i++ {
|
||||
coord.Row = 2
|
||||
coord.Col = i
|
||||
b[coord] = Pawn{Color: types.White}
|
||||
b.position[coord] = Pawn{Color: types.White}
|
||||
|
||||
coord.Row = 7
|
||||
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[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.position[types.Coordinate{Row: 1, Col: 1}] = Rook{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 2}] = Knight{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 3}] = Bishop{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 4}] = Queen{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 5}] = King{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 6}] = Bishop{Color: types.White}
|
||||
b.position[types.Coordinate{Row: 1, Col: 7}] = Knight{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[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}
|
||||
b.position[types.Coordinate{Row: 8, Col: 1}] = Rook{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 2}] = Knight{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 3}] = Bishop{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 4}] = Queen{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 5}] = King{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 6}] = Bishop{Color: types.Black}
|
||||
b.position[types.Coordinate{Row: 8, Col: 7}] = Knight{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 can play the move on it and then check if it is invalid
|
||||
tempBoard := b.getCopyOfBoard()
|
||||
|
||||
//Check start square of move
|
||||
pieceAtStartSquare := b.getPieceAt(move.StartSquare)
|
||||
pieceAtStartSquare := tempBoard.getPieceAt(move.StartSquare)
|
||||
if pieceAtStartSquare == nil {
|
||||
return false, "no piece at start square"
|
||||
}
|
||||
movingColor := pieceAtStartSquare.GetColor()
|
||||
move.ColorMoved = pieceAtStartSquare.GetColor()
|
||||
move.PieceMoved = GetShortNameForPiece(pieceAtStartSquare)
|
||||
|
||||
//Check end square of move
|
||||
pieceAtEndSquare := b.getPieceAt(move.EndSquare)
|
||||
pieceAtEndSquare := tempBoard.getPieceAt(move.EndSquare)
|
||||
if pieceAtEndSquare != nil {
|
||||
if pieceAtEndSquare.GetColor() == pieceAtStartSquare.GetColor() {
|
||||
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,
|
||||
//since we are only reading moves from the player whose turn it is.
|
||||
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
|
||||
delete(tempBoard, move.StartSquare)
|
||||
tempBoard[move.EndSquare] = pieceAtStartSquare
|
||||
delete(tempBoard.position, move.StartSquare)
|
||||
tempBoard.position[move.EndSquare] = pieceAtStartSquare
|
||||
}
|
||||
|
||||
//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 := tempBoard.getSquareOfPiece(King{Color: movingColor})
|
||||
ownKingCoordinate := tempBoard.getSquareOfPiece(King{Color: move.ColorMoved})
|
||||
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 {
|
||||
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
|
||||
|
||||
//We play the move on the real board
|
||||
b = tempBoard
|
||||
b.position = tempBoard.position
|
||||
b.history = tempBoard.history
|
||||
b.appendMoveToHistory(move)
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (b Board) getSquareOfPiece(piece Piece) *types.Coordinate {
|
||||
for k, v := range b {
|
||||
for k, v := range b.position {
|
||||
if v == piece {
|
||||
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 {
|
||||
var attackedSquares []types.Coordinate
|
||||
|
||||
for square, piece := range b {
|
||||
for square, piece := range b.position {
|
||||
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 {
|
||||
piece, found := b[coord]
|
||||
piece, found := b.position[coord]
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
@ -139,17 +150,59 @@ func (b Board) getPieceAt(coord types.Coordinate) 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 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()
|
||||
|
||||
if messageContainsPromotion {
|
||||
promotionToPiece = *move.PromotionToPiece
|
||||
}
|
||||
|
||||
switch color {
|
||||
switch move.ColorMoved {
|
||||
case types.White:
|
||||
if move.StartSquare.Row == types.RangeLastValid-1 &&
|
||||
move.EndSquare.Row == types.RangeLastValid {
|
||||
@ -164,19 +217,63 @@ func (b Board) handlePossiblePromotion(move types.Move, color types.ChessColor)
|
||||
}
|
||||
|
||||
if isPromotionMove {
|
||||
delete(b, move.StartSquare)
|
||||
b[move.EndSquare] = GetPieceForShortName(promotionToPiece)
|
||||
delete(b.position, move.StartSquare)
|
||||
b.position[move.EndSquare] = GetPieceForShortName(promotionToPiece, move.ColorMoved)
|
||||
}
|
||||
|
||||
return isPromotionMove, promotionToPiece
|
||||
return isPromotionMove
|
||||
}
|
||||
|
||||
func (b Board) getCopyOfBoard() Board {
|
||||
board := make(map[types.Coordinate]Piece)
|
||||
func (b *Board) handleEnPassant(move, lastMove types.Move) bool {
|
||||
var wasEnPassant bool
|
||||
|
||||
for coord, piece := range b {
|
||||
board[coord] = piece
|
||||
if lastMove.PieceMoved != types.PawnShortName {
|
||||
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
|
||||
}
|
||||
|
@ -8,64 +8,191 @@ import (
|
||||
)
|
||||
|
||||
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[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White}
|
||||
board[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 1, Row: 2}] = Pawn{Color: types.White}
|
||||
board.position[types.Coordinate{Col: 2, Row: 4}] = Pawn{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{
|
||||
StartSquare: types.Coordinate{Col: 1, Row: 1},
|
||||
EndSquare: types.Coordinate{Col: 1, Row: 2},
|
||||
StartSquare: 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)
|
||||
}
|
||||
|
||||
func Test_CheckMove_invalidPawnMoves(t *testing.T) {
|
||||
var board = make(Board)
|
||||
func Test_CheckMove_enPassant(t *testing.T) {
|
||||
var board = newBoard()
|
||||
|
||||
board[types.Coordinate{Col: 2, Row: 5}] = Pawn{Color: types.White}
|
||||
board[types.Coordinate{Col: 1, Row: 5}] = King{Color: types.White}
|
||||
board[types.Coordinate{Col: 7, Row: 5}] = Queen{Color: types.Black}
|
||||
board[types.Coordinate{Col: 8, Row: 5}] = King{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 6, Row: 4}] = Pawn{Color: types.Black}
|
||||
board.position[types.Coordinate{Col: 5, Row: 2}] = Pawn{Color: types.White}
|
||||
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{
|
||||
StartSquare: types.Coordinate{Col: 2, Row: 5},
|
||||
EndSquare: types.Coordinate{Col: 2, Row: 6},
|
||||
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) {
|
||||
testBoard := board.getCopyOfBoard()
|
||||
testBoard[types.Coordinate{Col: 2, Row: 6}] = Pawn{Color: types.Black}
|
||||
legalMove, _ := testBoard.CheckMove(move)
|
||||
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{
|
||||
StartSquare: types.Coordinate{Col: 2, Row: 5},
|
||||
EndSquare: types.Coordinate{Col: 2, Row: 6},
|
||||
}
|
||||
legalMove, _ := board.CheckAndPlay(move)
|
||||
assert.False(t, legalMove)
|
||||
})
|
||||
|
||||
t.Run("king of moving color is in check after move", func(t *testing.T) {
|
||||
good, _ := board.CheckMove(move)
|
||||
assert.False(t, good)
|
||||
t.Run("pawn moves to the side", func(t *testing.T) {
|
||||
var board = newBoard()
|
||||
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) {
|
||||
var board Board = make(Board)
|
||||
var board Board = newBoard()
|
||||
|
||||
board[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: 7}] = Pawn{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{
|
||||
StartSquare: types.Coordinate{Col: 1, Row: 7},
|
||||
EndSquare: types.Coordinate{Col: 1, Row: 8},
|
||||
PromotionToPiece: &shortName,
|
||||
}
|
||||
|
||||
good, reason := board.CheckMove(move)
|
||||
good, reason := board.CheckAndPlay(move)
|
||||
|
||||
assert.Empty(t, reason)
|
||||
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)
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package chess
|
||||
|
||||
import (
|
||||
"log"
|
||||
"mchess_server/api"
|
||||
"mchess_server/types"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@ -25,7 +25,7 @@ const (
|
||||
func NewGame() *Game {
|
||||
var game Game = Game{
|
||||
id: uuid.New(),
|
||||
board: make(map[types.Coordinate]Piece),
|
||||
board: newBoard(),
|
||||
}
|
||||
game.board.Init()
|
||||
|
||||
@ -75,7 +75,7 @@ func (game *Game) Handle() {
|
||||
gameState = CheckMove
|
||||
|
||||
case CheckMove:
|
||||
valid, reason := game.board.CheckMove(receivedMove)
|
||||
valid, reason := game.board.CheckAndPlay(receivedMove)
|
||||
|
||||
if valid {
|
||||
gameState = CheckPlayerChange
|
||||
|
@ -9,22 +9,41 @@ type Piece interface {
|
||||
GetColor() types.ChessColor
|
||||
}
|
||||
|
||||
func GetPieceForShortName(name types.PieceShortName) Piece {
|
||||
func GetPieceForShortName(name types.PieceShortName, color types.ChessColor) Piece {
|
||||
var piece Piece
|
||||
|
||||
switch name {
|
||||
case 'p':
|
||||
piece = Pawn{}
|
||||
piece = Pawn{Color: color}
|
||||
case 'q':
|
||||
piece = Queen{}
|
||||
piece = Queen{Color: color}
|
||||
case 'k':
|
||||
piece = King{}
|
||||
piece = King{Color: color}
|
||||
case 'b':
|
||||
piece = Bishop{}
|
||||
piece = Bishop{Color: color}
|
||||
case 'r':
|
||||
piece = Rook{}
|
||||
piece = Rook{Color: color}
|
||||
case 'n':
|
||||
piece = Knight{}
|
||||
piece = Knight{Color: color}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
package types
|
||||
|
||||
type Move struct {
|
||||
StartSquare Coordinate `json:"startSquare"`
|
||||
EndSquare Coordinate `json:"endSquare"`
|
||||
PromotionToPiece *PieceShortName `json:"promotionToPiece,omitempty"`
|
||||
StartSquare Coordinate `json:"startSquare"`
|
||||
EndSquare Coordinate `json:"endSquare"`
|
||||
PieceMoved PieceShortName
|
||||
ColorMoved ChessColor
|
||||
PromotionToPiece *PieceShortName `json:"promotionToPiece,omitempty"`
|
||||
}
|
||||
|
||||
func (m Move) IsPromotionMove() bool {
|
||||
if m.PromotionToPiece != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return m.PromotionToPiece != nil
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ package types
|
||||
type PieceShortName rune
|
||||
|
||||
const (
|
||||
Pawn PieceShortName = 'p'
|
||||
Rook PieceShortName = 'r'
|
||||
Knight PieceShortName = 'n'
|
||||
Bishop PieceShortName = 'b'
|
||||
Queen PieceShortName = 'q'
|
||||
King PieceShortName = 'k'
|
||||
PawnShortName PieceShortName = 'p'
|
||||
RookShortName PieceShortName = 'r'
|
||||
KnightShortName PieceShortName = 'n'
|
||||
BishopShortName PieceShortName = 'b'
|
||||
QueenShortName PieceShortName = 'q'
|
||||
KingShortName PieceShortName = 'k'
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user