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) }