-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathalgebraic_notation.go
134 lines (104 loc) · 3.19 KB
/
algebraic_notation.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
package pawn
import (
"fmt"
"regexp"
"strings"
)
type AlgebraicNotation string
func (an AlgebraicNotation) Material() Material {
firstCharacter := string(an[0])
for material, name := range materialNames {
if firstCharacter == name {
return material
}
}
return Pawn
}
func (an AlgebraicNotation) Takes() bool {
return strings.Contains(string(an), "x")
}
func (an AlgebraicNotation) DestinationPosition() Position {
destinationPositionStr := an.destinationPosition()
return Position{
File: File(string(destinationPositionStr[0])),
Rank: Rank(rankFromByte(destinationPositionStr[1])),
}
}
func (an AlgebraicNotation) destinationPosition() string {
destinationPositionPattern := regexp.MustCompile("[a-h][1-8]")
if matches := destinationPositionPattern.FindAllString(string(an), -1); len(matches) > 0 {
return matches[len(matches)-1]
}
return ""
}
func (an AlgebraicNotation) OriginDisambiguated() bool {
return an.OriginFile() != NilFile || an.OriginRank() != NilRank
}
func (an AlgebraicNotation) OriginRank() Rank {
var rank Rank
rankPattern := regexp.MustCompile("[1-8]")
if matches := rankPattern.FindAllString(string(an), -1); len(matches) > 1 {
rank = rankFromByte(matches[0][0])
}
return rank
}
func (an AlgebraicNotation) OriginFile() File {
var file File
filePattern := regexp.MustCompile("[a-h]")
if matches := filePattern.FindAllString(string(an), -1); len(matches) > 1 {
file = File(matches[0])
}
return file
}
// TODO
/*
For example, with knights on g1 and d2, either of which might move to f3, the move is specified as Ngf3 or Ndf3, as appropriate. With knights on g5 and g1, the moves are N5f3 or N1f3. As above, an "x" can be inserted to indicate a capture, for example: N5xf3. Another example: two rooks on d3 and h5, either one of which may move to d5. If the rook on d3 moves to d5, it is possible to disambiguate with either Rdd5 or R3d5, but the file takes precedence over the rank, so Rdd5 is correct. (And likewise if the move is a capture, Rdxd5 is correct.)
*/
func (an AlgebraicNotation) IsPromotion() bool {
return an.PromotedTo() != Pawn
}
func (an AlgebraicNotation) PromotedTo() Material {
if index := strings.Index(string(an), "="); index != -1 {
materialCharacter := string(an[index+1])
return AlgebraicNotation(materialCharacter).Material()
}
return Pawn
}
func (an AlgebraicNotation) IsCheck() bool {
return strings.HasSuffix(string(an), "+")
}
func (an AlgebraicNotation) IsCheckMate() bool {
return strings.HasSuffix(string(an), "#")
}
func (an AlgebraicNotation) IsCastle() bool {
return an.IsCastleKingSide() || an.IsCastleQueenSide()
}
func (an AlgebraicNotation) IsCastleKingSide() bool {
return an == "O-O"
}
func (an AlgebraicNotation) IsCastleQueenSide() bool {
return an == "O-O-O"
}
type AlgebraiclyNotated interface {
AN() string
FAN() string
}
func (m Material) AN() string {
return materialNames[m]
}
func (p Piece) AN() string {
return p.Material.AN()
}
func (p Piece) FAN() string {
if p == NoPiece {
return " "
} else {
return materialFigurines[p.Color][p.Material]
}
}
func (p Position) AN() string {
return fmt.Sprintf("%s%d", p.File, p.Rank)
}
func (s Square) AN() string {
return s.Piece.AN() + s.Position.AN()
}