github.com/gorgonia/agogo@v0.1.1/game/c4/game.go (about) 1 package c4 2 3 import ( 4 "fmt" 5 "hash/fnv" 6 7 "github.com/gorgonia/agogo/game" 8 ) 9 10 var ( 11 _ game.State = &Game{} 12 ) 13 14 type Game struct { 15 b *Board 16 history []game.PlayerMove 17 historical [][]game.Colour 18 nextToMove game.Player 19 histPtr int 20 moveCount int 21 passCount int 22 } 23 24 //New creates a new game with a board of (rows,cols) and N to win (connect4 being 4 to win) 25 func New(rows, cols, N int) *Game { 26 b := newBoard(rows, cols, N) 27 history := make([]game.PlayerMove, 0, rows*cols) 28 historical := make([][]game.Colour, 0, rows*cols/2) 29 return &Game{ 30 b: b, 31 history: history, 32 historical: historical, 33 } 34 } 35 36 func (g *Game) BoardSize() (int, int) { return g.b.data.Shape()[0], g.b.data.Shape()[1] } 37 38 func (g *Game) SetToMove(p game.Player) { g.nextToMove = p } 39 40 func (g *Game) ToMove() game.Player { return g.nextToMove } 41 42 func (g *Game) LastMove() game.PlayerMove { 43 if len(g.history) > 0 { 44 return g.history[g.histPtr-1] 45 } 46 return game.PlayerMove{Player: game.Player(game.None), Single: -1} 47 } 48 49 // Passes will always return 0 50 func (g *Game) Passes() int { return 0 } 51 52 func (g *Game) MoveNumber() int { return g.moveCount + 1 } 53 54 func (g *Game) Check(m game.PlayerMove) bool { _, _, err := g.b.check(m); return err == nil } 55 56 func (g *Game) Apply(m game.PlayerMove) game.State { 57 board := g.b.data.Data().([]game.Colour) 58 historicalBoard := make([]game.Colour, len(board)) 59 copy(historicalBoard, board) 60 61 if err := g.b.Apply(m); err == nil { 62 g.history = append(g.history, m) 63 g.historical = append(g.historical, historicalBoard) 64 g.histPtr++ 65 } 66 67 if m.IsPass() { 68 g.passCount++ 69 } else { 70 g.passCount = 0 71 } 72 return g 73 } 74 75 func (g *Game) Score(p game.Player) float32 { 76 winning := g.b.checkWin() 77 if game.Player(winning) == p { 78 return 1 79 } 80 if winning == game.None { 81 return 0 82 } 83 return -1 84 } 85 86 func (g *Game) UndoLastMove() { 87 g.histPtr-- 88 lastMove := g.history[g.histPtr-1] 89 col := int(lastMove.Single) 90 var row int 91 for row = len(g.b.it) - 1; row >= 0; row-- { 92 if g.b.it[row][col] == game.None { 93 row-- 94 break 95 } 96 } 97 g.b.it[row][col] = game.None 98 } 99 100 func (g *Game) Fwd() { 101 if len(g.history) > 0 { 102 g.histPtr++ 103 } 104 } 105 106 func (g *Game) Eq(other game.State) bool { 107 ot, ok := other.(*Game) 108 if !ok { 109 return false 110 } 111 if !ot.b.data.Eq(ot.b.data) { 112 return false 113 } 114 if g.histPtr != ot.histPtr { 115 return false 116 } 117 if g.moveCount != ot.moveCount { 118 return false 119 } 120 if len(g.history) != len(ot.history) { 121 return false 122 } 123 if len(g.historical) != len(ot.historical) { 124 return false 125 } 126 127 for i := range g.history { 128 if ot.history[i] != g.history[i] { 129 return false 130 } 131 } 132 for i := range g.historical { 133 for j := range g.historical[i] { 134 if ot.historical[i][j] != g.historical[i][j] { 135 return false 136 } 137 } 138 } 139 return true 140 } 141 142 func (g *Game) Clone() game.State { 143 b2 := g.b.clone() 144 history2 := make([]game.PlayerMove, len(g.history)+2) 145 copy(history2, g.history) 146 historical2 := make([][]game.Colour, len(g.historical)+2) 147 for i := range g.historical { 148 historical2[i] = make([]game.Colour, len(g.historical[i])) 149 copy(historical2[i], g.historical[i]) 150 } 151 return &Game{ 152 b: b2, 153 history: history2, 154 historical: historical2, 155 nextToMove: g.nextToMove, 156 histPtr: g.histPtr, 157 moveCount: g.moveCount, 158 passCount: g.passCount, 159 } 160 } 161 162 func (g *Game) AdditionalScore() float32 { return 0 } 163 164 func (g *Game) Ended() (bool, game.Player) { 165 winner := g.b.checkWin() 166 if winner != game.None { 167 return true, game.Player(winner) 168 } 169 170 if g.passCount > 2 { 171 return true, game.Player(game.None) 172 } 173 174 // ended due to full board 175 raw := g.b.data.Data().([]game.Colour) 176 for i := range raw { 177 if raw[i] == game.None { 178 return false, game.Player(game.None) 179 } 180 } 181 return true, game.Player(game.None) 182 } 183 184 func (g *Game) Handicap() int { return 0 } 185 186 func (g *Game) Reset() { 187 data := g.b.data.Data().([]game.Colour) 188 for i := range data { 189 data[i] = game.None 190 } 191 g.historical = g.historical[:0] 192 g.history = g.history[:0] 193 g.histPtr = 0 194 g.moveCount = 0 195 g.passCount = 0 196 g.nextToMove = 0 197 } 198 199 func (g *Game) ActionSpace() int { return g.b.data.Shape()[1] } 200 201 func (g *Game) Board() []game.Colour { return g.b.data.Data().([]game.Colour) } 202 203 func (g *Game) Hash() game.Zobrist { 204 h := fnv.New32a() 205 data := g.b.data.Data().([]game.Colour) 206 for i := range data { 207 fmt.Fprintf(h, "%v", data[i]) 208 } 209 return game.Zobrist(h.Sum32()) 210 } 211 212 func (g *Game) Historical(i int) []game.Colour { return g.historical[i] } 213 214 func (g *Game) Format(s fmt.State, c rune) { g.b.Format(s, c) }