Check for collisions with own pieces on target

This commit is contained in:
ekzyis 2024-09-26 00:13:21 +02:00
parent 4e12b40478
commit d3966685db
3 changed files with 106 additions and 20 deletions

View File

@ -269,19 +269,22 @@ func (b *Board) Parse(pgn string) error {
return nil
}
func (b *Board) Move(position string) error {
func (b *Board) Move(move string) error {
var (
err error
piece string
targetPosition string
// the column from which the piece is captured.
// for example, this would be 'e' for exd4 and 'e' for Nexd4.
captureFrom string
captureFrom string
collisionPiece *Piece
err error
)
if strings.Contains(position, "x") {
if strings.Contains(move, "x") {
// capture move
parts := strings.Split(position, "x")
parts := strings.Split(move, "x")
if len(parts) != 2 {
return fmt.Errorf("invalid move: %s", position)
return fmt.Errorf("invalid move: %s", move)
}
if len(parts[0]) == 2 {
// example: Nexd4
@ -295,10 +298,10 @@ func (b *Board) Move(position string) error {
captureFrom = ""
}
} else {
return fmt.Errorf("invalid move: %s", position)
return fmt.Errorf("invalid move: %s", move)
}
position = strings.Replace(position, captureFrom+"x", "", 1)
move = strings.Replace(move, captureFrom+"x", "", 1)
}
// TODO: parse captures e.g. exd5 or Nxd5
@ -310,25 +313,36 @@ func (b *Board) Move(position string) error {
// TODO: make sure king is not in check after move
// ( this avoids moving into check and moving a piece that exposes the king to check e.g. pinned pieces )
if len(position) == 2 {
err = b.movePawn(position, captureFrom)
} else if len(position) == 3 {
switch strings.ToLower(position[0:1]) {
if len(move) == 2 {
err = b.movePawn(move, captureFrom)
} else if len(move) == 3 {
piece = move[0:1]
targetPosition = move[1:3]
// collision detection
if collisionPiece, err = b.getCollision(targetPosition); err != nil {
return fmt.Errorf("invalid move %s: %v", move, err)
} else if collisionPiece != nil {
return fmt.Errorf("invalid move %s: position %s blocked by %s", move, targetPosition, collisionPiece)
}
switch strings.ToLower(piece) {
case "r":
err = b.moveRook(position[1:3], false)
err = b.moveRook(targetPosition, false)
case "b":
err = b.moveBishop(position[1:3], false)
err = b.moveBishop(targetPosition, false)
case "n":
err = b.moveKnight(position[1:3])
err = b.moveKnight(targetPosition)
case "q":
err = b.moveQueen(position[1:3])
err = b.moveQueen(targetPosition)
case "k":
err = b.moveKing(position[1:3])
err = b.moveKing(targetPosition)
default:
err = fmt.Errorf("invalid move: %s", position)
err = fmt.Errorf("invalid move %s: %v", move, err)
}
} else {
return fmt.Errorf("invalid move: %s", position)
return fmt.Errorf("invalid move %s: %v", move, err)
}
if err != nil {
@ -341,7 +355,7 @@ func (b *Board) Move(position string) error {
b.turn = Light
}
b.moves = append(b.moves, position)
b.moves = append(b.moves, move)
return nil
}
@ -752,6 +766,30 @@ func (b *Board) getPiece(x int, y int) *Piece {
return b.tiles[x][y]
}
func (b *Board) getCollision(position string) (*Piece, error) {
var (
x, y int
p *Piece
collision bool
err error
)
if x, y, err = getXY(position); err != nil {
return nil, err
}
p = b.getPiece(x, y)
// check if position is occupied by own piece
collision = p != nil && p.Color == b.turn
if collision {
return p, nil
}
// TODO: check if path is blocked by some piece
return nil, nil
}
func getTileColor(x, y int) Color {
if x%2 == y%2 {
return Light

View File

@ -120,6 +120,26 @@ func TestBoardMoveKnight(t *testing.T) {
assertNoPiece(t, b, "g8")
}
func TestBoardMoveKnightInvalid(t *testing.T) {
b := chess.NewBoard()
// out of reach
assertMoveError(t, b, "Ng3", "no knight found that can move to g3")
assertMoveError(t, b, "Nb3", "no knight found that can move to b3")
// blocked by own piece
assertMoveError(t, b, "Nd2", "d2 blocked by white pawn")
assertMoveError(t, b, "Ne2", "e2 blocked by white pawn")
b.Move("Nf3")
assertMoveError(t, b, "Ng6", "no knight found that can move to g6")
assertMoveError(t, b, "Nb6", "no knight found that can move to b6")
assertMoveError(t, b, "Ne7", "e7 blocked by black pawn")
assertMoveError(t, b, "Nd7", "d7 blocked by black pawn")
}
func TestBoardMoveBishop(t *testing.T) {
b := chess.NewBoard()

View File

@ -16,6 +16,34 @@ type Piece struct {
Image image.Image
}
func (p *Piece) String() string {
n := ""
switch p.Name {
case Pawn:
n = "pawn"
case Knight:
n = "knight"
case Bishop:
n = "bishop"
case Rook:
n = "rook"
case Queen:
n = "queen"
case King:
n = "king"
}
c := ""
switch p.Color {
case Light:
c = "white"
case Dark:
c = "black"
}
return fmt.Sprintf("%s %s", c, n)
}
type PieceName string
const (