-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmove.go
133 lines (108 loc) · 2.47 KB
/
move.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
package gotak
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// Move is a single move in Tak.
type Move struct {
// Both Drop and Move
Stone string
Square string
// Move only
MoveCount int64
MoveDirection string
MoveDropCounts []int64
Text string
}
// (stone)(square)
var placeRegex = regexp.MustCompile(`^(C|S|F)?([a-z][0-9]+)$`)
// (count)(square)(direction)(drop counts)(stone)
var moveRegex = regexp.MustCompile(`^([1-9]*)([a-z][0-9]+)([<>+\-])([0-9]*)(C|S|F)?$`)
// Directions
const (
MoveUp = "+"
MoveDown = "-"
MoveLeft = "<"
MoveRight = ">"
)
// NewMove takes in a move string and returns a move object that has been
// parsed.
func NewMove(mv string) (*Move, error) {
m := &Move{Text: mv}
err := m.Parse()
return m, err
}
// Parse takes the Text of a move and fills the rest of the attributes of the
// Move object. It will overright past parses or data stored in the move.
func (m *Move) Parse() error {
if m.isPlace() {
return m.parsePlace()
}
if m.isMove() {
return m.parseMove()
}
return nil
}
func (m *Move) isPlace() bool {
return placeRegex.MatchString(m.Text)
}
func (m *Move) isMove() bool {
return moveRegex.MatchString(m.Text)
}
func (m *Move) parsePlace() error {
parts := placeRegex.FindStringSubmatch(m.Text)
location := ""
if len(parts) == 2 {
location = parts[1]
}
if len(parts) == 3 {
location = parts[2]
m.Stone = parts[1]
}
if m.Stone == "" {
m.Stone = StoneFlat
}
m.Square = location
return nil
}
func (m *Move) parseMove() error {
parts := moveRegex.FindStringSubmatch(m.Text)
countStr := parts[1]
if countStr == "" {
countStr = "1"
}
totalPieces, err := strconv.ParseInt(countStr, 10, 64)
if err != nil {
return err
}
m.MoveCount = totalPieces
m.Square = parts[2]
m.MoveDirection = parts[3]
m.MoveDropCounts = []int64{}
drpCountStr := parts[4]
if drpCountStr == "" {
drpCountStr = countStr
}
var totalDropped int64
for _, str := range strings.Split(drpCountStr, "") {
drpCount, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return err
}
totalDropped += drpCount
if totalDropped > m.MoveCount {
return fmt.Errorf("tried to drop more pieces than available: %d > %d", totalDropped, totalPieces)
}
m.MoveDropCounts = append(m.MoveDropCounts, drpCount)
}
if totalDropped != m.MoveCount {
return fmt.Errorf("did not drop same pieces picked up: %d != %d", totalDropped, m.MoveCount)
}
m.Stone = parts[5]
if m.Stone == "" {
m.Stone = StoneFlat
}
return nil
}