func (c *comparer) ApplyNextMove() (bool, error) {
	applied, err := c.ApplyNextSpecialAdminMove()
	if err != nil {
		return false, errors.New("Couldn't apply next special admin move: " + err.Error())
	}
	if applied {
		return true, nil
	}
	applied, err = c.ApplyNextPlayerMove()
	if err != nil {
		return false, errors.New("Couldn't apply next player move: " + err.Error())
	}
	return applied, nil
}
ApplyNextMove will apply the next move, whether it's a player move or a
special admin move.
package golden
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"time"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/interfaces"
	"github.com/jkomoros/boardgame/storage/filesystem/record"
)
type comparer struct {
	manager             *boardgame.GameManager
	golden              *record.Record
	storage             *storageManager
	game                *boardgame.Game
	buf                 *bytes.Buffer
	lastBuf             *bytes.Buffer
	lastVerifiedVersion int
}
func newComparer(manager *boardgame.GameManager, rec *record.Record, storage *storageManager) (*comparer, error) {
	if existingGameRec, _ := storage.Game(rec.Game().ID); existingGameRec != nil {
		return nil, errors.New("The storage layer already has a game with that ID. Use a fresh storage manager")
	}
	storage.gameRecords[rec.Game().ID] = rec
	game, err := manager.Internals().RecreateGame(rec.Game())
	if err != nil {
		return nil, errors.New("Couldn't create game: " + err.Error())
	}
	result := &comparer{
		manager,
		rec,
		storage,
		game,
		nil,
		nil,
		0,
	}
	return result, nil
}
func (c *comparer) PrintDebug() {
	if c.lastBuf == nil {
		return
	}
	if c.lastBuf.Len() == 0 {
		return
	}
	fmt.Println(c.lastBuf)
	fmt.Println("Last state: ")
	state := c.game.State(c.lastVerifiedVersion)
	jsonBuf, _ := json.MarshalIndent(state, "", "\t")
	fmt.Println(string(jsonBuf))
}
func (c *comparer) ResetDebugLog() {
	c.lastBuf = c.buf
	logger, buf := newLogger()
	c.manager.SetLogger(logger)
	c.buf = buf
}
func (c *comparer) GoldenHasRemainingMoves() bool {
	return c.golden.Game().Version > c.lastVerifiedVersion
}
func (c *comparer) LastVerifiedVersion() int {
	return c.lastVerifiedVersion
}
func (c *comparer) AdvanceToNextInitiatorMove() {
	if c.game.Version() > 0 {
		c.lastVerifiedVersion++
	}
	for c.lastVerifiedVersion <= len(c.golden.RawMoves())+2 {
		nextMoveRec, err := c.golden.Move(c.lastVerifiedVersion + 1)
		if err != nil {
			return
		}
		if nextMoveRec.Initiator == nextMoveRec.Version {
			return
		}
		c.lastVerifiedVersion++
	}
}
func (c *comparer) VerifyUnverifiedMoves() error {
	verifiedAtLeastOne := false
	for c.lastVerifiedVersion < c.game.Version() {
		stateToCompare, err := c.golden.State(c.lastVerifiedVersion)
		if err != nil {
			return errors.New("Couldn't get " + strconv.Itoa(c.lastVerifiedVersion) + " state: " + err.Error())
		}
		storageRec, err := c.manager.Storage().State(c.game.ID(), c.lastVerifiedVersion)
		if err != nil {
			return errors.New("Couldn't get state storage rec from game: " + err.Error())
		}
		if c.lastVerifiedVersion > 0 {
			recMove, err := c.golden.Move(c.lastVerifiedVersion)
			if err != nil {
				return errors.New("Couldn't get move " + strconv.Itoa(c.lastVerifiedVersion) + " from record")
			}
			moves := c.game.MoveRecords(c.lastVerifiedVersion)
			if len(moves) < 1 {
				return errors.New("Didn't fetch historical move records for " + strconv.Itoa(c.lastVerifiedVersion))
			}
			if err := compareMoveStorageRecords(*moves[len(moves)-1], *recMove, false); err != nil {
				return errors.New("Move " + strconv.Itoa(c.lastVerifiedVersion) + " compared differently: " + err.Error())
			}
		}
		if err := compareJSONBlobs(storageRec, stateToCompare); err != nil {
			return errors.New("State " + strconv.Itoa(c.lastVerifiedVersion) + " compared differently: " + err.Error())
		}
		c.lastVerifiedVersion++
		verifiedAtLeastOne = true
	}
	if !verifiedAtLeastOne && c.game.Version() > 0 {
		return errors.New("VerifyUnverifiedMoves didn't verify any new moves; this implies that ApplyNextMove isn't actually applying the next move")
	}
	return nil
}