Check for collisions with own pieces on target
This commit is contained in:
parent
4e12b40478
commit
d3966685db
|
@ -269,19 +269,22 @@ func (b *Board) Parse(pgn string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Board) Move(position string) error {
|
func (b *Board) Move(move string) error {
|
||||||
var (
|
var (
|
||||||
err error
|
piece string
|
||||||
|
targetPosition string
|
||||||
// the column from which the piece is captured.
|
// the column from which the piece is captured.
|
||||||
// for example, this would be 'e' for exd4 and 'e' for Nexd4.
|
// 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
|
// capture move
|
||||||
parts := strings.Split(position, "x")
|
parts := strings.Split(move, "x")
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return fmt.Errorf("invalid move: %s", position)
|
return fmt.Errorf("invalid move: %s", move)
|
||||||
}
|
}
|
||||||
if len(parts[0]) == 2 {
|
if len(parts[0]) == 2 {
|
||||||
// example: Nexd4
|
// example: Nexd4
|
||||||
|
@ -295,10 +298,10 @@ func (b *Board) Move(position string) error {
|
||||||
captureFrom = ""
|
captureFrom = ""
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// 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
|
// 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 )
|
// ( this avoids moving into check and moving a piece that exposes the king to check e.g. pinned pieces )
|
||||||
|
|
||||||
if len(position) == 2 {
|
if len(move) == 2 {
|
||||||
err = b.movePawn(position, captureFrom)
|
err = b.movePawn(move, captureFrom)
|
||||||
} else if len(position) == 3 {
|
} else if len(move) == 3 {
|
||||||
switch strings.ToLower(position[0:1]) {
|
|
||||||
|
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":
|
case "r":
|
||||||
err = b.moveRook(position[1:3], false)
|
err = b.moveRook(targetPosition, false)
|
||||||
case "b":
|
case "b":
|
||||||
err = b.moveBishop(position[1:3], false)
|
err = b.moveBishop(targetPosition, false)
|
||||||
case "n":
|
case "n":
|
||||||
err = b.moveKnight(position[1:3])
|
err = b.moveKnight(targetPosition)
|
||||||
case "q":
|
case "q":
|
||||||
err = b.moveQueen(position[1:3])
|
err = b.moveQueen(targetPosition)
|
||||||
case "k":
|
case "k":
|
||||||
err = b.moveKing(position[1:3])
|
err = b.moveKing(targetPosition)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("invalid move: %s", position)
|
err = fmt.Errorf("invalid move %s: %v", move, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("invalid move: %s", position)
|
return fmt.Errorf("invalid move %s: %v", move, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -341,7 +355,7 @@ func (b *Board) Move(position string) error {
|
||||||
b.turn = Light
|
b.turn = Light
|
||||||
}
|
}
|
||||||
|
|
||||||
b.moves = append(b.moves, position)
|
b.moves = append(b.moves, move)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -752,6 +766,30 @@ func (b *Board) getPiece(x int, y int) *Piece {
|
||||||
return b.tiles[x][y]
|
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 {
|
func getTileColor(x, y int) Color {
|
||||||
if x%2 == y%2 {
|
if x%2 == y%2 {
|
||||||
return Light
|
return Light
|
||||||
|
|
|
@ -120,6 +120,26 @@ func TestBoardMoveKnight(t *testing.T) {
|
||||||
assertNoPiece(t, b, "g8")
|
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) {
|
func TestBoardMoveBishop(t *testing.T) {
|
||||||
b := chess.NewBoard()
|
b := chess.NewBoard()
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,34 @@ type Piece struct {
|
||||||
Image image.Image
|
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
|
type PieceName string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
Loading…
Reference in New Issue