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  }