diff --git a/fixtures/pgns/0014.pgn b/fixtures/pgns/0014.pgn new file mode 100644 index 0000000..8b76d3c --- /dev/null +++ b/fixtures/pgns/0014.pgn @@ -0,0 +1,55 @@ +[Event "Fantasy Caro-Kann: Starting Position"] +[Result "*"] +[UTCDate "2023.05.29"] +[UTCTime "16:05:07"] +[Variant "Standard"] +[ECO "B12"] +[Opening "Caro-Kann Defense: Maróczy Variation"] + +1. e4 c6 2. d4 d5 3. f3 * + + +[Event "Fantasy Caro-Kann: 3. ... dxe4"] +[Result "*"] +[UTCDate "2023.05.29"] +[UTCTime "16:05:48"] +[Variant "Standard"] +[FEN "rnbqkbnr/pp2pppp/2p5/3p4/3PP3/5P2/PPP3PP/RNBQKBNR b KQkq - 0 3"] +[SetUp "1"] + +3... dxe4 4. fxe4 e5 5. Nf3 Bg4 (5... exd4 6. Bc4) 6. Bc4 Nd7 7. O-O Ngf6 8. c3 * + + +[Event "Fantasy Caro-Kann: 3. ... e6"] +[Result "*"] +[UTCDate "2023.05.29"] +[UTCTime "16:06:13"] +[Variant "Standard"] +[FEN "rnbqkbnr/pp2pppp/2p5/3p4/3PP3/5P2/PPP3PP/RNBQKBNR b KQkq - 0 3"] +[SetUp "1"] + +3... e6 4. Nc3 Bb4 (4... Nf6 5. e5) 5. Bd2 Ne7 6. Bd3 * + + +[Event "Fantasy Caro-Kann: 3. ... g6"] +[Result "*"] +[UTCDate "2023.05.29"] +[UTCTime "16:06:42"] +[Variant "Standard"] +[FEN "rnbqkbnr/pp2pppp/2p5/3p4/3PP3/5P2/PPP3PP/RNBQKBNR b KQkq - 0 3"] +[SetUp "1"] + +3... g6 4. Nc3 Bg7 5. Be3 * + + +[Event "Fantasy Caro-Kann: 3. ... Qb6"] +[Result "*"] +[UTCDate "2023.05.29"] +[UTCTime "16:07:08"] +[Variant "Standard"] +[FEN "rnbqkbnr/pp2pppp/2p5/3p4/3PP3/5P2/PPP3PP/RNBQKBNR b KQkq - 0 3"] +[SetUp "1"] + +3... Qb6 4. Nc3 dxe4 5. fxe4 e5 6. Nf3 exd4 7. Nxd4 * + + diff --git a/pgn.go b/pgn.go index 37b76af..e22c689 100644 --- a/pgn.go +++ b/pgn.go @@ -37,6 +37,8 @@ const ( // a game or EOF was reached. Running scan populates // data for Next() and Err(). func (s *Scanner) Scan() bool { + moveListRe := regexp.MustCompile(`^\d+\.`) + if s.err == io.EOF { return false } @@ -64,7 +66,7 @@ func (s *Scanner) Scan() bool { } line := strings.TrimSpace(s.scanr.Text()) isTagPair := strings.HasPrefix(line, "[") - isMoveSeq := strings.HasPrefix(line, "1. ") + isMoveSeq := moveListRe.MatchString(line) switch state { case notInPGN: if !isTagPair { diff --git a/pgn_test.go b/pgn_test.go index 913796d..beec82d 100644 --- a/pgn_test.go +++ b/pgn_test.go @@ -154,6 +154,41 @@ func TestScanner(t *testing.T) { } } +func TestScannerWithFromPosFENs(t *testing.T) { + finalPositions := []string{ + "rnbqkbnr/pp2pppp/2p5/3p4/3PP3/5P2/PPP3PP/RNBQKBNR b KQkq - 0 3", + "r2qkb1r/pp1n1ppp/2p2n2/4p3/2BPP1b1/2P2N2/PP4PP/RNBQ1RK1 b kq - 0 8", + "rnbqk2r/pp2nppp/2p1p3/3p4/1b1PP3/2NB1P2/PPPB2PP/R2QK1NR b KQkq - 5 6", + "rnbqk1nr/pp2ppbp/2p3p1/3p4/3PP3/2N1BP2/PPP3PP/R2QKBNR b KQkq - 3 5", + "rnb1kbnr/pp3ppp/1qp5/8/3NP3/2N5/PPP3PP/R1BQKB1R b KQkq - 0 7", + } + fname := "fixtures/pgns/0014.pgn" + f, err := os.Open(fname) + if err != nil { + panic(err) + } + defer f.Close() + scanner := NewScanner(f) + games := []*Game{} + for idx := 0; scanner.Scan(); { + game := scanner.Next() + if len(game.moves) == 0 { + continue + } + finalPos := game.Position().String() + if finalPos != finalPositions[idx] { + t.Fatalf(fname+" game %v expected final pos %v but got %v", idx, + finalPositions[idx], finalPos) + } + games = append(games, game) + idx++ + } + if len(games) != len(finalPositions) { + t.Fatalf(fname+" expected %v games but got %v", len(finalPositions), + len(games)) + } +} + func BenchmarkPGN(b *testing.B) { pgn := mustParsePGN("fixtures/pgns/0001.pgn") b.ResetTimer()