This repository has been archived by the owner on Jun 9, 2021. It is now read-only.
/
gamemanager.go
156 lines (130 loc) · 3.9 KB
/
gamemanager.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package lib
import (
"log"
"strings"
)
type gameManager struct {
maxTurns int
// Use a map to imitate a Python-style set of game states
states map[string]gameState
success bool
turn int
}
func NewGame(libraryRaw []string, handRaw []string, otp bool, verbose bool, maxTurns int) (gameManager, error) {
allCardNames := []string{}
handCards := []card{}
for _, cardName := range handRaw {
handCards = append(handCards, Card(cardName))
allCardNames = append(allCardNames, cardName)
}
libraryCards := []card{}
for _, cardName := range libraryRaw {
libraryCards = append(libraryCards, Card(cardName))
allCardNames = append(allCardNames, cardName)
}
err := EnsureCardData(allCardNames)
if err != nil {
return gameManager{}, err
}
state := NewGameState(libraryCards, handCards, otp, verbose, maxTurns)
return GameManager(state), nil
}
func GameManager(states ...gameState) gameManager {
manager := gameManager{
states: make(map[string]gameState),
}
for _, state := range states {
manager.Add(state)
}
return manager
}
func (self *gameManager) NextTurn() gameManager {
if self.Size() == 0 {
log.Fatal("called NextTurn on empty gameManager")
}
// Once we find a line, we're done iterating
if self.success {
return *self
}
if self.turn > 0 {
log.Println("starting turn", self.turn, "with", self.Size(), "states")
}
ret := GameManager()
for self.Size() > 0 {
stateOld := self.Pop()
for _, stateNew := range stateOld.NextStates() {
// If we find a state that gets there, we're done
if stateNew.success {
return GameManager(stateNew)
}
if stateNew.turn == self.turn {
self.Add(stateNew)
} else {
ret.Add(stateNew)
}
}
}
// After turn four or so, further work is expensive but not interesting.
// Pop off the longest log we can find to show we tried.
if ret.turn > self.maxTurns {
log.Println("giving up on turn", ret.turn, "with", ret.Size(), "states")
bestState := ret.Pop()
for ret.Size() > 0 {
state := ret.Pop()
if state.LogSize() > bestState.LogSize() {
bestState = state
}
}
bestState.MarkDeadEnd()
return GameManager(bestState)
}
return ret
}
func (self *gameManager) Pretty() string {
lines := []string{}
for _, state := range self.states {
lines = append(lines, state.Pretty())
}
return strings.Join(lines, "\n~~~\n")
}
func (self *gameManager) ToJSON() string {
lines := []string{}
for _, state := range self.states {
lines = append(lines, state.ToJSON())
}
return strings.Join(lines, "\n~~~\n")
}
func (self *gameManager) ToMiniJSON() string {
lines := []string{}
for _, state := range self.states {
lines = append(lines, state.ToMiniJSON())
}
return strings.Join(lines, "\n~~~\n")
}
func (self *gameManager) Add(state gameState) {
self.states[state.Hash()] = state
self.maxTurns = state.maxTurns
// By construction, in-progress states and completed states never mix
self.success = state.success
// Turn is uniform for all states within a gameManager
self.turn = state.turn
}
func (self *gameManager) Pop() gameState {
for hash, state := range self.states {
delete(self.states, hash)
return state
}
log.Fatal("pop from empty gameManager")
return gameState{}
}
func (self *gameManager) Size() int {
return len(self.states)
}
func (self *gameManager) IsDone() bool {
return self.turn > self.maxTurns || self.success
}
func (self *gameManager) Update(other gameManager) {
for hash, state := range other.states {
self.states[hash] = state
}
}