Skip to content

Commit 339d216

Browse files
authored
(feature) Support tagless PGN inputs (#59)
The original PGN parser from notnil/chess.git supported tagless PGN games. e.g. just a bare "1. e4 e5 *". This commit restores this support to avoid breaking existing notnil/chess.git consumers migrating to corentings/chess.git.
1 parent 5ad7e6e commit 339d216

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

game_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,13 +1002,20 @@ func TestPGNWithValidData(t *testing.T) {
10021002
}
10031003
}
10041004

1005-
func TestPGNWithInvalidData(t *testing.T) {
1005+
func TestTaglessPGN(t *testing.T) {
10061006
pgnData := "1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Nb8 10. d4 Nbd7 11. c4 c6 12. cxb5 axb5 13. Nc3 Bb7 14. Bg5 h6 15. Bh4 Re8 16. a3 Bf8 17. Rc1 Qb6 18. dxe5 dxe5 19. Qe2 Nh5 20. Qd2 Nc5 21. Bc2 Nf4 22. Bg3 Rad8 23. Qe3 Qc7 24. Rcd1 Rxd1 25. Rxd1 Nce6 26. Bb3 Bc5 27. Qe1 Nd4 28. Nxd4 Bxd4 29. Bxf4 exf4 30. Rxd4 c5 31. Rd1 c4 32. Bc2 Qe5 33. f3 Qc5+ 34. Qf2 Qe5 35. Qd4 Qg5 36. Qd7 Re7 37. Qd8+ Kh7 38. e5+ g6 39. Qd6 Bxf3 40. Rd2 Rxe5 41. Qd4 Re1+ 42. Kf2 Qg3# 0-1"
1007-
r := strings.NewReader(pgnData)
1007+
1008+
r := strings.NewReader("#!)(*#@$" + pgnData)
10081009
_, err := PGN(r)
10091010
if err == nil {
10101011
t.Fatal("expected error for invalid PGN data")
10111012
}
1013+
1014+
r = strings.NewReader(pgnData)
1015+
_, err = PGN(r)
1016+
if err != nil {
1017+
t.Fatal("expected non-nil error for tagless PGN data")
1018+
}
10121019
}
10131020

10141021
func TestPGNWithEmptyData(t *testing.T) {

scanner.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,19 +246,34 @@ func handleEOF(data []byte, atEOF bool) (int, []byte, error) {
246246
return 0, nil, nil
247247
}
248248

249-
// Helper to find the start of a game (first '[' character).
249+
// Helper to find the start of a game (normally first '[' character).
250250
func findGameStart(data []byte, start int, atEOF bool) int {
251251
// If the first character is not '[', find the next '[' character
252252
if start < len(data) && data[start] != '[' {
253253
idx := bytes.IndexByte(data[start:], '[')
254254
if idx == -1 {
255+
return findTaglessGameStart(data, start, atEOF)
256+
}
257+
start += idx
258+
}
259+
return start
260+
}
261+
262+
// Helper to find the start of a game without tags
263+
func findTaglessGameStart(data []byte, start int, atEOF bool) int {
264+
// If the first character is not '[', find the next '[' character
265+
if start < len(data) && data[start] != '1' {
266+
idx := bytes.IndexByte(data[start:], '1')
267+
if idx == -1 || data[start+idx+1] != '.' ||
268+
(idx != 0 && data[start+idx-1] != '\n') {
255269
if atEOF {
256270
return -1 // this could be removed as we return -1 in the next line anyway (just to be explicit and debuggable)
257271
}
258272
return -1
259273
}
260274
start += idx
261275
}
276+
262277
return start
263278
}
264279

0 commit comments

Comments
 (0)