Add pawn promotion

This commit is contained in:
ekzyis 2024-09-26 07:32:43 +02:00
parent d98c0c221d
commit aa072ca4aa
2 changed files with 67 additions and 3 deletions

View File

@ -277,16 +277,21 @@ func (b *Board) Move(move string) error {
// see https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Disambiguating_moves
fromX int
fromY int
promotion string
collisionPiece *Piece
err error
)
if parts := strings.Split(move, "="); len(parts) > 1 {
promotion = parts[1]
move = parts[0]
}
if piece, fromX, fromY, to, err = parseMove(move); err != nil {
return err
}
// TODO: parse ambiguous captures for all pieces
// TODO: parse promotions
// TODO: parse checks e.g. e5+
// TODO: parse checkmates e.g. e5#
// TODO: parse O-O as kingside castle and O-O-O as queenside castle
@ -305,7 +310,7 @@ func (b *Board) Move(move string) error {
switch strings.ToLower(piece) {
case "p":
return b.movePawn(to, fromX, fromY)
return b.movePawn(to, fromX, fromY, promotion)
case "r":
return b.moveRook(to, false, fromX, fromY)
case "b":
@ -480,7 +485,7 @@ func (b *Board) validateMove(search PieceName, fromX int, fromY int) func(*Piece
}
}
func (b *Board) movePawn(position string, fromX int, fromY int) error {
func (b *Board) movePawn(position string, fromX int, fromY int, promotion string) error {
var (
toX int
toY int
@ -513,6 +518,9 @@ func (b *Board) movePawn(position string, fromX int, fromY int) error {
b.tiles[fromX][fromY] = nil
b.tiles[toX][toY] = piece
if promotion != "" {
return b.promotePawn(toX, toY, promotion)
}
return nil
}
@ -532,6 +540,9 @@ func (b *Board) movePawn(position string, fromX int, fromY int) error {
if piece != nil && piece.Name == Pawn && piece.Color == b.turn {
b.tiles[toX][yPrev] = nil
b.tiles[toX][toY] = piece
if promotion != "" {
return b.promotePawn(toX, toY, promotion)
}
return nil
}
@ -545,12 +556,32 @@ func (b *Board) movePawn(position string, fromX int, fromY int) error {
if piece != nil && piece.Name == Pawn && piece.Color == b.turn {
b.tiles[toX][yPrev] = nil
b.tiles[toX][toY] = piece
if promotion != "" {
return b.promotePawn(toX, toY, promotion)
}
return nil
}
return fmt.Errorf("no pawn found that can move to %s", position)
}
func (b *Board) promotePawn(x int, y int, name string) error {
switch strings.ToLower(name) {
case "q":
b.tiles[x][y] = &Piece{Name: Queen, Color: b.turn}
case "r":
b.tiles[x][y] = &Piece{Name: Rook, Color: b.turn}
case "b":
b.tiles[x][y] = &Piece{Name: Bishop, Color: b.turn}
case "n":
b.tiles[x][y] = &Piece{Name: Knight, Color: b.turn}
default:
return fmt.Errorf("invalid promotion: %s", name)
}
return nil
}
func (b *Board) moveRook(position string, queen bool, fromX int, fromY int) error {
var (
x int

View File

@ -130,6 +130,39 @@ func TestBoardMovePawnCapture(t *testing.T) {
assertPiece(t, b, "e4", chess.Pawn, chess.Light)
}
func TestBoardPawnPromotion(t *testing.T) {
t.Parallel()
b := chess.NewBoard()
b.Parse("a4 e6 a5 e5 a6 e4 axb7 e3 bxa8=Q")
assertPiece(t, b, "a8", chess.Queen, chess.Light)
assertNoPiece(t, b, "b7")
b = chess.NewBoard()
b.Parse("a4 e6 a5 e5 a6 e4 axb7 e3 bxa8=R")
assertPiece(t, b, "a8", chess.Rook, chess.Light)
assertNoPiece(t, b, "b7")
b = chess.NewBoard()
b.Parse("a4 e6 a5 e5 a6 e4 axb7 e3 bxa8=B")
assertPiece(t, b, "a8", chess.Bishop, chess.Light)
assertNoPiece(t, b, "b7")
b = chess.NewBoard()
b.Parse("a4 e6 a5 e5 a6 e4 axb7 e3 bxa8=N")
assertPiece(t, b, "a8", chess.Knight, chess.Light)
assertNoPiece(t, b, "b7")
b = chess.NewBoard()
b.Parse("a4 e6 a5 e5 a6 e4 axb7 e3")
assertMoveError(t, b, "bxa8=K", "invalid promotion: K")
}
func TestBoardMoveKnight(t *testing.T) {
t.Parallel()