diff --git a/board.go b/board.go index a61718d..d99e4c8 100644 --- a/board.go +++ b/board.go @@ -4,10 +4,19 @@ import ( "bytes" "encoding/binary" "errors" - "strconv" "strings" ) +var fenReplacer = strings.NewReplacer( + "11111111", "8", + "1111111", "7", + "111111", "6", + "11111", "5", + "1111", "4", + "111", "3", + "11", "2", +) + // A Board represents a chess board and its relationship between squares and pieces. type Board struct { bbWhiteKing bitboard @@ -128,27 +137,23 @@ func (b *Board) Draw() string { // String implements the fmt.Stringer interface and returns // a string in the FEN board format: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR func (b *Board) String() string { - fen := "" + var fenBuilder strings.Builder for r := 7; r >= 0; r-- { for f := 0; f < numOfSquaresInRow; f++ { sq := NewSquare(File(f), Rank(r)) p := b.Piece(sq) if p != NoPiece { - fen += p.getFENChar() + fenBuilder.WriteString(p.getFENChar()) } else { - fen += "1" + fenBuilder.WriteString("1") } } if r != 0 { - fen += "/" + fenBuilder.WriteString("/") } } - for i := 8; i > 1; i-- { - repeatStr := strings.Repeat("1", i) - countStr := strconv.Itoa(i) - fen = strings.Replace(fen, repeatStr, countStr, -1) - } - return fen + + return fenReplacer.Replace(fenBuilder.String()) } // Piece returns the piece for the given square. diff --git a/board_test.go b/board_test.go index 275988e..74848fe 100644 --- a/board_test.go +++ b/board_test.go @@ -5,17 +5,37 @@ import ( ) func TestBoardTextSerialization(t *testing.T) { - fen := "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR" - b := &Board{} - if err := b.UnmarshalText([]byte(fen)); err != nil { - t.Fatal("recieved unexpected error", err) + for _, fen := range []string{ + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR", + "rnbqkb1r/pp1p1np1/4pp2/2pP3p/8/2N2NP1/PPP1PP1P/R1BQKBR1", + } { + t.Run(fen, func(t *testing.T) { + b := &Board{} + if err := b.UnmarshalText([]byte(fen)); err != nil { + t.Fatal("recieved unexpected error", err) + } + txt, err := b.MarshalText() + if err != nil { + t.Fatal("recieved unexpected error", err) + } + if fen != string(txt) { + t.Fatalf("fen expected board string %s but got %s", fen, string(txt)) + } + }) } - txt, err := b.MarshalText() - if err != nil { - t.Fatal("recieved unexpected error", err) + +} + +func BenchmarkBoardTextSerialization(b *testing.B) { + fen := "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR" + board := &Board{} + if err := board.UnmarshalText([]byte(fen)); err != nil { + b.Fatal("recieved unexpected error", err) } - if fen != string(txt) { - t.Fatalf("fen expected board string %s but got %s", fen, string(txt)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + board.String() } } diff --git a/fen.go b/fen.go index 62ae0cc..115deff 100644 --- a/fen.go +++ b/fen.go @@ -137,9 +137,18 @@ var ( "n": BlackKnight, "p": BlackPawn, } + pieceFenMap = reversePieceMap() fenTurnMap = map[string]Color{ "w": White, "b": Black, } ) + +func reversePieceMap() map[Piece]string { + res := make(map[Piece]string) + for k, v := range fenPieceMap { + res[v] = k + } + return res +} diff --git a/piece.go b/piece.go index 1063ba1..e0e20a8 100644 --- a/piece.go +++ b/piece.go @@ -179,10 +179,9 @@ var ( ) func (p Piece) getFENChar() string { - for key, piece := range fenPieceMap { - if piece == p { - return key - } + res, ok := pieceFenMap[p] + if !ok { + return "" } - return "" + return res }