github.com/gorgonia/agogo@v0.1.1/game/wq/game.go (about) 1 package 围碁 2 3 import "github.com/gorgonia/agogo/game" 4 5 var _ game.State = &Game{} 6 7 type historicalBoard struct { 8 board []game.Colour 9 hash game.Zobrist 10 } 11 12 // Game implements game.State and mcts.GameState 13 type Game struct { 14 board *Board 15 history []game.PlayerMove 16 historical []historicalBoard 17 nextToMove game.Player 18 19 komi float32 // komidashi 20 moveCount int // move number, 1 indexed 21 passes int // count of passes 22 histPtr int // pointer at the history (for easy forwarding) 23 handicap int // duh 24 captures [2]byte // number of captures 25 ends bool // game ended due to all possible moves being played 26 } 27 28 func New(boardSize, handicap int, komi float64) *Game { 29 b := newBoard(boardSize) 30 return &Game{ 31 board: b, 32 nextToMove: game.Player(game.Black), 33 komi: float32(komi), 34 handicap: handicap, 35 historical: make([]historicalBoard, 0, int(b.size)), 36 history: make([]game.PlayerMove, 0, int(b.size)), 37 } 38 } 39 40 func (g *Game) BoardSize() (int, int) { return int(g.board.size), int(g.board.size) } 41 42 func (g *Game) Board() []game.Colour { return g.board.data } 43 44 func (g *Game) Historical(i int) []game.Colour { return g.historical[i].board } 45 46 func (g *Game) Hash() game.Zobrist { return game.Zobrist(g.board.hash) } 47 48 func (g *Game) ActionSpace() int { return len(g.board.data) } 49 50 func (g *Game) SetToMove(p game.Player) { g.nextToMove = p } 51 52 func (g *Game) ToMove() game.Player { return g.nextToMove } 53 54 func (g *Game) LastMove() game.PlayerMove { 55 if len(g.history) > 0 { 56 return g.history[g.histPtr-1] 57 } 58 return game.PlayerMove{Player: game.Player(game.None), Single: -1} 59 } 60 61 func (g *Game) Passes() int { return g.passes } 62 63 func (g *Game) MoveNumber() int { return len(g.history) } 64 65 func (g *Game) Check(m game.PlayerMove) bool { 66 if m.Single.IsResignation() { 67 return true 68 } 69 if m.Single.IsPass() { 70 return true 71 } 72 if int(m.Single) >= len(g.board.data) { 73 return false 74 } 75 _, err := g.board.check(m) 76 77 // TODO: SuperKo checks 78 return err == nil 79 } 80 81 func (g *Game) Apply(m game.PlayerMove) game.State { 82 newState := g.Clone().(*Game) 83 // TODO : check for passes etc 84 captures, _ := newState.board.Apply(m) 85 86 newState.captures[m.Player-1] += captures 87 newState.nextToMove = Opponent(m.Player) 88 newState.history = append(newState.history, m) 89 newState.histPtr++ 90 newState.moveCount++ 91 return newState 92 } 93 94 func (g *Game) Ended() (ended bool, winner game.Player) { 95 if g.passes >= 2 { 96 ended = true 97 } 98 if g.ends { 99 ended = true 100 } 101 if !ended { 102 return false, game.Player(game.None) 103 } 104 105 whiteScore := g.Score(WhiteP) 106 blackScore := g.Score(BlackP) 107 switch { 108 case whiteScore == blackScore: 109 return true, game.Player(game.None) 110 case whiteScore > blackScore: 111 return true, WhiteP 112 default: 113 return true, BlackP 114 } 115 } 116 117 func (g *Game) Reset() { panic("not implemented") } 118 119 func (g *Game) UndoLastMove() { panic("not implemented") } 120 121 func (g *Game) Fwd() { panic("not implemented") } 122 123 func (g *Game) Eq(other game.State) bool { 124 ot, ok := other.(*Game) 125 if !ok { 126 return false 127 } 128 129 // easy to check stuff first 130 if g.nextToMove != ot.nextToMove || 131 g.komi != ot.komi || 132 g.moveCount != ot.moveCount || 133 g.passes != ot.passes || 134 g.handicap != ot.handicap || 135 len(g.history) != len(ot.history) && 136 (len(g.history) > 0 && len(ot.history) > 0 && len(g.history[:g.histPtr-1]) != len(ot.history[:ot.histPtr-1])) { 137 return false 138 } 139 140 // specifically unchecked: histPtr 141 142 for i, c := range g.captures { 143 if ot.captures[i] != c { 144 return false 145 } 146 } 147 148 // heavier checks 149 150 if !g.board.Eq(ot.board) { 151 return false 152 } 153 for i, j := 0, 0; i < g.histPtr && j < ot.histPtr; i, j = i+1, j+1 { 154 pm := g.history[i] 155 if !pm.Eq(ot.history[j]) { 156 return false 157 } 158 } 159 160 return true 161 } 162 163 func (g *Game) Clone() game.State { 164 newState := &Game{} 165 newState.board = g.board.Clone() 166 newState.history = make([]game.PlayerMove, len(g.history), len(g.history)+1) 167 copy(newState.history, g.history) 168 newState.nextToMove = g.nextToMove 169 newState.komi = g.komi 170 newState.moveCount = g.moveCount 171 newState.passes = g.passes 172 newState.histPtr = g.histPtr 173 newState.captures = g.captures 174 return newState 175 } 176 177 func (g *Game) Handicap() int { return g.handicap } 178 func (g *Game) Score(p game.Player) float32 { panic("not implemented") } 179 func (g *Game) AdditionalScore() float32 { return g.komi } 180 func (g *Game) SuperKo() bool { panic("not implemented") } 181 182 func (g *Game) IsEye(m game.PlayerMove) bool { 183 panic("not implemented") 184 }