forked from freeeve/pgn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fen.go
139 lines (130 loc) · 2.88 KB
/
fen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package pgn
import (
"errors"
"fmt"
"strings"
)
type FEN struct {
FOR string
ToMove Color
WhiteCastleStatus CastleStatus
BlackCastleStatus CastleStatus
EnPassantVulnerable Position
HalfmoveClock int
Fullmove int
}
func ParseFEN(fenstr string) (*FEN, error) {
fen := FEN{}
colorStr := ""
castleStr := ""
enPassant := ""
_, err := fmt.Sscanf(fenstr, "%s %s %s %s %d %d",
&fen.FOR,
&colorStr,
&castleStr,
&enPassant,
&fen.HalfmoveClock,
&fen.Fullmove,
)
if err != nil {
return nil, err
}
switch colorStr {
case "w":
fen.ToMove = White
case "b":
fen.ToMove = Black
default:
return nil, errors.New("pgn: invalid color")
}
if strings.Contains(castleStr, "k") {
fen.BlackCastleStatus = Kingside
}
if strings.Contains(castleStr, "q") {
if fen.BlackCastleStatus == Kingside {
fen.BlackCastleStatus = Both
} else {
fen.BlackCastleStatus = Queenside
}
}
if strings.Contains(castleStr, "K") {
fen.WhiteCastleStatus = Kingside
}
if strings.Contains(castleStr, "Q") {
if fen.WhiteCastleStatus == Kingside {
fen.WhiteCastleStatus = Both
} else {
fen.WhiteCastleStatus = Queenside
}
}
if enPassant == "-" {
fen.EnPassantVulnerable = NoPosition
} else {
fen.EnPassantVulnerable, err = ParsePosition(enPassant)
if err != nil {
return nil, err
}
}
return &fen, nil
}
func FORFromBoard(b *Board) string {
f := ""
for y := '8'; y > '0'; y-- {
count := 0
for x := 'a'; x <= 'h'; x++ {
pos, _ := ParsePosition(fmt.Sprintf("%c%c", x, y))
p := b.GetPiece(pos)
if p == NoPiece {
count++
} else {
if count > 0 {
f += fmt.Sprintf("%d", count)
count = 0
}
f += string(p)
}
}
if count > 0 {
f += fmt.Sprintf("%d", count)
}
if y != '1' {
f += "/"
}
}
return f
}
func FENFromBoard(b *Board) FEN {
f := FEN{}
f.FOR = FORFromBoard(b)
f.ToMove = b.toMove
f.WhiteCastleStatus = b.wCastle
f.BlackCastleStatus = b.bCastle
f.HalfmoveClock = b.halfmoveClock
f.Fullmove = b.fullmove
if b.GetPiece(b.lastMove.To) == WhitePawn &&
b.lastMove.To.GetRank()-2 == b.lastMove.From.GetRank() {
f.EnPassantVulnerable = PositionFromFileRank(b.lastMove.To.GetFile(), b.lastMove.To.GetRank()-1)
}
if b.GetPiece(b.lastMove.To) == BlackPawn &&
b.lastMove.To.GetRank()+2 == b.lastMove.From.GetRank() {
f.EnPassantVulnerable = PositionFromFileRank(b.lastMove.To.GetFile(), b.lastMove.To.GetRank()+1)
}
return f
}
func (fen FEN) String() string {
castleStatus := fen.WhiteCastleStatus.String(White) + fen.BlackCastleStatus.String(Black)
if castleStatus == "--" {
castleStatus = "-"
}
if castleStatus != "-" && strings.Contains(castleStatus, "-") {
castleStatus = strings.Trim(castleStatus, "-")
}
return fmt.Sprintf("%s %v %s %s %d %d",
fen.FOR,
fen.ToMove,
castleStatus,
fen.EnPassantVulnerable.String(),
fen.HalfmoveClock,
fen.Fullmove,
)
}