Skip to content

Commit 6fc0e40

Browse files
authored
fix: Correct pawn promotion logic and update Go module dependencies (#85)
* fix: Correct pawn promotion logic and update Go module dependencies * fix: Remove obsolete entries from go.sum
1 parent 15cc544 commit 6fc0e40

File tree

4 files changed

+100
-6
lines changed

4 files changed

+100
-6
lines changed

board.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,11 @@ func (b *Board) update(m *Move) {
366366
}
367367
}
368368
// check promotion
369-
if m.promo != NoPieceType {
369+
if m.promo != NoPieceType && p1 != NoPiece {
370370
newPiece := NewPiece(m.promo, p1.Color())
371371
// remove pawn
372372
bbPawn := b.bbForPiece(p1)
373-
b.setBBForPiece(p1, bbPawn & ^s2BB)
373+
b.setBBForPiece(p1, bbPawn & ^s1BB & ^s2BB)
374374
// add promo piece
375375
bbPromo := b.bbForPiece(newPiece)
376376
b.setBBForPiece(newPiece, bbPromo|s2BB)

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
module github.com/corentings/chess/v2
22

3-
go 1.22.0
3+
go 1.25.0
44

55
require (
66
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b
7-
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
7+
golang.org/x/exp v0.0.0-20260209203927-2842357ff358
88
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
88
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
99
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
1010
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
11-
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
12-
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
11+
golang.org/x/exp v0.0.0-20260209203927-2842357ff358 h1:kpfSV7uLwKJbFSEgNhWzGSL47NDSF/5pYYQw1V0ub6c=
12+
golang.org/x/exp v0.0.0-20260209203927-2842357ff358/go.mod h1:R3t0oliuryB5eenPWl3rrQxwnNM3WTwnsRZZiXLAAW8=
1313
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
1414
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
1515
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

notation_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package chess
22

33
import (
4+
"fmt"
5+
"strings"
46
"testing"
57
)
68

@@ -382,6 +384,98 @@ func BenchmarkAlgebraicDecodeComplex(b *testing.B) {
382384
}
383385
}
384386

387+
func TestPromotionWithCheck(t *testing.T) {
388+
promoPos := unsafeFEN("8/1P2k3/8/8/8/8/8/8 w - - 0 1")
389+
promoMove := &Move{s1: B7, s2: B8, promo: Queen, tags: Check}
390+
391+
algebraicNotation := AlgebraicNotation{}
392+
result := algebraicNotation.Encode(promoPos, promoMove)
393+
if result != "b8=Q+" {
394+
t.Fatalf("Expected 'b8=Q+', got '%s'", result)
395+
}
396+
397+
longAlgebraicNotation := LongAlgebraicNotation{}
398+
result = longAlgebraicNotation.Encode(promoPos, promoMove)
399+
if result != "b7b8=Q+" {
400+
t.Fatalf("Expected 'b7b8=Q+', got '%s'", result)
401+
}
402+
}
403+
404+
func TestPromotionWithCheckFromIssue84(t *testing.T) {
405+
promoPos := unsafeFEN("8/1P2k3/8/8/8/8/8/8 w - - 0 1")
406+
promoMove := &Move{s1: B7, s2: B8, promo: Queen}
407+
promoMove.AddTag(Check)
408+
409+
algebraicNotation := AlgebraicNotation{}
410+
result := algebraicNotation.Encode(promoPos, promoMove)
411+
if result != "b8=Q+" {
412+
t.Fatalf("Algebraic Notation: Expected 'b8=Q+', got '%s'", result)
413+
}
414+
415+
longAlgebraicNotation := LongAlgebraicNotation{}
416+
result = longAlgebraicNotation.Encode(promoPos, promoMove)
417+
if result != "b7b8=Q+" {
418+
t.Fatalf("Long Algebraic Notation: Expected 'b7b8=Q+', got '%s'", result)
419+
}
420+
}
421+
422+
func TestIssue84FullGame(t *testing.T) {
423+
const pgn = `[Event "?"]
424+
[Site "?"]
425+
[Date "????.??.??"]
426+
[Round "?"]
427+
[White "?"]
428+
[Black "?"]
429+
[Result "*"]
430+
1. e4 c5 2. Nf3 Nc6 3. Bb5 g6 4. Bxc6 dxc6 5. d3 Bg7 6. h3 e5 7. a3 Nf6
431+
8. Nc3 Nd7 9. Be3 Qe7 10. Qd2 O-O 11. O-O f5 12. exf5 gxf5 13. Bh6 Qf6
432+
14. Bxg7 Qxg7 15. Qg5 Qxg5 16. Nxg5 Re8 17. Rae1 h6 18. Nf3 c4 19. dxc4 Kf7
433+
20. Rd1 Nf6 21. Rd6 e4 22. Nh4 Be6 23. b3 Rg8 24. Ne2 Rad8 25. Rfd1 Rxd6
434+
26. Rxd6 Ke7 27. c5 Ne8 28. Rd1 Nf6 29. Nd4 f4 30. Nhf5+ Bxf5 31. Nxf5+ Ke6
435+
32. Nxh6 Rg5 33. b4 Rd5 34. Rxd5 cxd5 35. c3 Nd7 36. Ng4 Kf5 37. Kf1 Nf8
436+
38. Ke2 Ne6 39. Kd2 Ng5 40. Nh6+ Kg6 41. Ng4 Kf5 42. Nh2 Ke5 43. a4 Ne6
437+
44. Nf1 a5 45. g3 axb4 46. cxb4 d4 47. gxf4+ Nxf4 48. a5 Nxh3 49. c6 Kd6
438+
50. cxb7 Kc7 51. f3 exf3 52. b8=Q+ Kxb8 53. Kd3 Kb7 54. Kxd4 Ka6 55. Kc5 Nf4
439+
56. Kc6 Nd3 57. b5+ Kxa5 58. b6 Nb4+ 59. Kc5 *`
440+
441+
reader := strings.NewReader(pgn)
442+
pgnObj, err := PGN(reader)
443+
if err != nil {
444+
t.Fatalf("Failed to parse PGN: %v", err)
445+
}
446+
game := NewGame(pgnObj)
447+
moves := game.Moves()
448+
449+
for i, mv := range moves {
450+
moveNum := (i / 2) + 1
451+
color := "W"
452+
if i%2 == 1 {
453+
color = "B"
454+
}
455+
456+
_, err := safeEncode(LongAlgebraicNotation{}, mv.Position(), mv)
457+
if err != nil {
458+
t.Fatalf("Error: LongAlgebraicNotation.Encode panic at half-move %d (%d. %s): %v",
459+
i, moveNum, color, err)
460+
}
461+
462+
_, err = safeEncode(AlgebraicNotation{}, mv.Position(), mv)
463+
if err != nil {
464+
t.Fatalf("Error: AlgebraicNotation.Encode panic at half-move %d (%d. %s): %v",
465+
i, moveNum, color, err)
466+
}
467+
}
468+
}
469+
470+
func safeEncode(notation Encoder, pos *Position, mv *Move) (s string, err error) {
471+
defer func() {
472+
if r := recover(); r != nil {
473+
err = fmt.Errorf("%v", r)
474+
}
475+
}()
476+
return notation.Encode(pos, mv), nil
477+
}
478+
385479
// Benchmark promotion scenarios
386480
func BenchmarkPromotionEncoding(b *testing.B) {
387481
promoPos := unsafeFEN("rnbqkbnr/pPpppppp/8/8/8/8/P1PPPPPP/RNBQKBNR w KQkq - 0 1")

0 commit comments

Comments
 (0)