Add simple pawn move + tests

This commit is contained in:
ekzyis 2024-09-18 04:33:58 +02:00
parent f1ab0c2af4
commit b29034bab0
4 changed files with 204 additions and 2 deletions

View File

@ -7,14 +7,16 @@ import (
"image/png" "image/png"
"log" "log"
"os" "os"
"strings"
) )
type Board struct { type Board struct {
tiles [8][8]*Piece tiles [8][8]*Piece
turn Color
} }
func NewBoard() *Board { func NewBoard() *Board {
board := &Board{} board := &Board{turn: Light}
board.mustSetPiece(Rook, Light, "a1") board.mustSetPiece(Rook, Light, "a1")
board.mustSetPiece(Knight, Light, "b1") board.mustSetPiece(Knight, Light, "b1")
@ -112,12 +114,100 @@ func (b *Board) SetPiece(name PieceName, color Color, position string) error {
return nil return nil
} }
func (b *Board) Parse(pgn string) error {
var (
moves = strings.Split(pgn, " ")
err error
)
for _, move := range moves {
if err = b.Move(move); err != nil {
return err
}
}
return nil
}
func (b *Board) Move(position string) error {
var (
name PieceName
err error
)
// TODO: implement remaining moveset of pieces
if len(position) == 2 {
name = Pawn
}
switch name {
case Pawn:
err = b.movePawn(position)
default:
err = fmt.Errorf("invalid move: %s", position)
}
if err != nil {
return err
}
if b.turn == Light {
b.turn = Dark
} else {
b.turn = Light
}
return nil
}
func (b *Board) movePawn(position string) error {
var (
x int
y int
piece *Piece
err error
)
if x, y, err = getXY(position); err != nil {
return err
}
// TODO: implement diagonal pawn attacks
for yi := 0; yi < 8; yi++ {
piece = b.tiles[x][yi]
if piece != nil && piece.Name == Pawn && piece.Color == b.turn {
// TODO: assert move is valid:
// * 2 moves from start position
// * 1 move otherwise
// * diagonal if attacking
b.tiles[x][y] = piece
b.tiles[x][yi] = nil
return nil
}
}
return nil
}
func (b *Board) mustSetPiece(name PieceName, color Color, position string) { func (b *Board) mustSetPiece(name PieceName, color Color, position string) {
if err := b.SetPiece(name, color, position); err != nil { if err := b.SetPiece(name, color, position); err != nil {
log.Fatalf("cannot set piece %s: %v", name, err) log.Fatalf("cannot set piece %s: %v", name, err)
} }
} }
func (b *Board) At(position string) *Piece {
var (
x int
y int
err error
)
if x, y, err = getXY(position); err != nil {
return nil
}
return b.tiles[x][y]
}
func getXY(position string) (int, int, error) { func getXY(position string) (int, int, error) {
var ( var (
posX rune posX rune

93
chess/board_test.go Normal file
View File

@ -0,0 +1,93 @@
package chess_test
import (
"fmt"
"os"
"path"
"testing"
"github.com/ekzyis/sn-chess/chess"
"github.com/stretchr/testify/assert"
)
func init() {
// change working directory to the root of the project
// so assets/ can be found
wd, _ := os.Getwd()
os.Chdir(path.Dir(wd))
}
func TestBoardInitial(t *testing.T) {
b := chess.NewBoard()
assertPiece(t, b, "a1", chess.Rook, chess.Light)
assertPiece(t, b, "b1", chess.Knight, chess.Light)
assertPiece(t, b, "c1", chess.Bishop, chess.Light)
assertPiece(t, b, "d1", chess.Queen, chess.Light)
assertPiece(t, b, "e1", chess.King, chess.Light)
assertPiece(t, b, "f1", chess.Bishop, chess.Light)
assertPiece(t, b, "g1", chess.Knight, chess.Light)
assertPiece(t, b, "h1", chess.Rook, chess.Light)
assertPiece(t, b, "a2", chess.Pawn, chess.Light)
assertPiece(t, b, "b2", chess.Pawn, chess.Light)
assertPiece(t, b, "c2", chess.Pawn, chess.Light)
assertPiece(t, b, "d2", chess.Pawn, chess.Light)
assertPiece(t, b, "e2", chess.Pawn, chess.Light)
assertPiece(t, b, "f2", chess.Pawn, chess.Light)
assertPiece(t, b, "g2", chess.Pawn, chess.Light)
assertPiece(t, b, "h2", chess.Pawn, chess.Light)
assertPiece(t, b, "a8", chess.Rook, chess.Dark)
assertPiece(t, b, "b8", chess.Knight, chess.Dark)
assertPiece(t, b, "c8", chess.Bishop, chess.Dark)
assertPiece(t, b, "d8", chess.Queen, chess.Dark)
assertPiece(t, b, "e8", chess.King, chess.Dark)
assertPiece(t, b, "f8", chess.Bishop, chess.Dark)
assertPiece(t, b, "g8", chess.Knight, chess.Dark)
assertPiece(t, b, "h8", chess.Rook, chess.Dark)
assertPiece(t, b, "a7", chess.Pawn, chess.Dark)
assertPiece(t, b, "b7", chess.Pawn, chess.Dark)
assertPiece(t, b, "c7", chess.Pawn, chess.Dark)
assertPiece(t, b, "d7", chess.Pawn, chess.Dark)
assertPiece(t, b, "e7", chess.Pawn, chess.Dark)
assertPiece(t, b, "f7", chess.Pawn, chess.Dark)
assertPiece(t, b, "g7", chess.Pawn, chess.Dark)
assertPiece(t, b, "h7", chess.Pawn, chess.Dark)
}
func TestBoardMovePawn(t *testing.T) {
b := chess.NewBoard()
b.Move("e4")
assertNoPiece(t, b, "e2")
assertPiece(t, b, "e4", chess.Pawn, chess.Light)
b.Move("e5")
assertNoPiece(t, b, "e7")
assertPiece(t, b, "e5", chess.Pawn, chess.Dark)
}
func assertPiece(t *testing.T, b *chess.Board, position string, name chess.PieceName, color chess.Color) {
p := b.At(position)
c := "white"
if color == chess.Dark {
c = "black"
}
msg := fmt.Sprintf("expected %s %s at %s", c, name, position)
assert.NotNil(t, p, msg)
assert.Equal(t, name, p.Name, msg)
assert.Equal(t, color, p.Color, msg)
}
func assertNoPiece(t *testing.T, b *chess.Board, position string) {
p := b.At(position)
assert.Nil(t, p, "expected no piece at %s", position)
}

11
go.mod
View File

@ -2,4 +2,13 @@ module github.com/ekzyis/sn-chess
go 1.23.0 go 1.23.0
require golang.org/x/image v0.20.0 require (
github.com/stretchr/testify v1.9.0
golang.org/x/image v0.20.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

10
go.sum
View File

@ -1,2 +1,12 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=