game

package
v0.13.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: GPL-3.0 Imports: 36 Imported by: 10

Documentation

Overview

Package game encapsulates the main mechanics for a Crossword Game. It interacts heavily with the protobuf data structures.

a fast unique time-based ID algorithm from the mongo mgo driver

Index

Constants

View Source
const (
	//IdentificationAuthority is the authority that gives out game IDs
	IdentificationAuthority = "org.macondo"

	MacondoCreation = "Created with Macondo"

	RackTileLimit = 7

	DefaultMaxScorelessTurns  = 6
	CurrentGameHistoryVersion = 2
)
View Source
const (
	NN_C        = 85
	NN_H, NN_W  = 15, 15
	NN_N_PLANES = NN_C * NN_H * NN_W
	NN_N_SCAL   = 72
	NN_RowLen   = NN_N_PLANES + NN_N_SCAL
)
View Source
const (
	HistoryStartIdx      = NN_N_PLANES + 54
	HistoryEndIdx        = HistoryStartIdx + 3
	PowerTilesStartIdx   = HistoryEndIdx
	PowerTilesEndIdx     = PowerTilesStartIdx + 6
	VCRatioBagStartIdx   = PowerTilesEndIdx
	VCRatioBagEndIdx     = VCRatioBagStartIdx + 2
	VCRatioRackStartIdx  = VCRatioBagEndIdx
	VCRatioRackEndIdx    = VCRatioRackStartIdx + 2
	AddlFeaturesStartIdx = VCRatioRackEndIdx
	AddlFeaturesEndIdx   = AddlFeaturesStartIdx + 5
)
View Source
const (
	VarClassic  Variant = "classic"
	VarWordSmog         = "wordsmog"
	// Redundant information, but we are deciding to treat different board
	// layouts as different variants.
	VarClassicSuper  = "classic_super"
	VarWordSmogSuper = "wordsmog_super"
)
View Source
const (
	CrossScoreOnly   = "cs"
	CrossScoreAndSet = "css"
)
View Source
const DefaultExchangeLimit = 7

Variables

View Source
var MLVectorPool = sync.Pool{
	New: func() interface{} {

		v := make([]float32, NN_RowLen)
		return &v
	},
}

Functions

func CalculateCoordsFromStringPosition

func CalculateCoordsFromStringPosition(evt *pb.GameEvent)

CalculateCoordsFromStringPosition turns a "position" on the board such as H7 and turns it into a numeric row, col, and direction.

func ExtractLastOppLeave added in v0.13.0

func ExtractLastOppLeave(g *Game) ([]tilemapping.MachineLetter, error)

ExtractLastOppLeave finds the opponent's last tile-placement or exchange event in the game history and returns the leave they held after playing.

We do NOT use game.MoveFromEvent here because that function calls modifyForPlaythrough against the current board, which by this point already has those tiles on it — causing every tile to be flagged as a play-through (set to 0) and the computed leave to equal the full rack. Instead we parse the leave directly from the event fields without touching the board: strip '.' play-through markers from PlayedTiles (GCG notation), leaving only the tiles that came from the rack.

func InverseScaleScoreWithTanh added in v0.11.1

func InverseScaleScoreWithTanh(y float32, center float32, scaleFactor float32) float32

func MLLoadFunc added in v0.11.0

func MLLoadFunc(cfg *wglconfig.Config, key string) (interface{}, error)

func MaxCanExchange added in v0.9.9

func MaxCanExchange(inbag, exchLimit int) int

func MoveFromEvent added in v0.4.4

func MoveFromEvent(evt *pb.GameEvent, alph *tilemapping.TileMapping, board *board.GameBoard) (*move.Move, error)

MoveFromEvent generates a move from an event

func NormalizeSpreadForML added in v0.11.0

func NormalizeSpreadForML(spread float32) float32

func ScaleScoreWithTanh added in v0.11.0

func ScaleScoreWithTanh(score float32, center float32, scaleFactor float32) float32

Types

type BackupMode added in v0.4.5

type BackupMode int
const (
	// NoBackup never performs game backups. It can be used for autoplay
	// that has absolutely no input.
	NoBackup BackupMode = iota
	// SimulationMode keeps a stack of game copies, using these for doing
	// endgame and other types of simulations.
	SimulationMode
	// InteractiveGameplayMode keeps just one backup after every turn. This is needed
	// in order to get challenges working, which would roll back the game to
	// an earlier state if a word is challenged off.
	InteractiveGameplayMode
)

type Game

type Game struct {
	// contains filtered or unexported fields
}

Game is the actual internal game structure that controls the entire business logic of the game; drawing, making moves, etc. The two structures above are basically data entities. Note: a Game doesn't care how it is played. It is just rules for gameplay. AI players, human players, etc will play a game outside of the scope of this module.

func NewFromHistory

func NewFromHistory(history *pb.GameHistory, rules *GameRules, turnnum int) (*Game, error)

NewFromHistory instantiates a Game from a history, and sets the current turn to the passed in turnnum. It assumes the rules contains the current lexicon in history, if any! Note: NewFromHistory does not currently parse any CGP included in the starting_cgp. We should fix this.

func NewFromSnapshot added in v0.4.5

func NewFromSnapshot(rules *GameRules, players []*pb.PlayerInfo, lastKnownRacks []string,
	scores []int, boardRows [][]tilemapping.MachineLetter) (*Game, error)

func NewGame

func NewGame(rules *GameRules, playerinfo []*pb.PlayerInfo) (*Game, error)

NewGame is how one instantiates a brand new game. playerinfo must be in the order of who goes first. It is the caller's responsibility to alternate firsts.

func (*Game) AddFinalScoresToHistory added in v0.4.5

func (g *Game) AddFinalScoresToHistory()

AddFinalScoresToHistory adds the final scores and winner to the history.

func (*Game) AddNote added in v0.4.10

func (g *Game) AddNote(note string) error

func (*Game) Alphabet

func (g *Game) Alphabet() *tilemapping.TileMapping

func (*Game) Bag

func (g *Game) Bag() *tilemapping.Bag

Bag returns the current bag

func (*Game) BingosForNick added in v0.4.4

func (g *Game) BingosForNick(nick string) int

func (*Game) Board

func (g *Game) Board() *board.GameBoard

Board returns the current board state.

func (*Game) BuildMLVector added in v0.11.0

func (g *Game) BuildMLVector(m *move.Move, evalMoveLeaveVal float64, lastMoves []*move.Move) (
	*[]float32, error)

BuildMLVector builds the feature vector for the current game state. It should not modify the game state! lastMoves contains the last few moves played, most recent last. (-1 is opponent)

func (*Game) ChallengeEvent added in v0.4.5

func (g *Game) ChallengeEvent(addlBonus int, millis int) (bool, error)

ChallengeEvent should only be called if there is a history of events. It has the logic for appending challenge events and calculating scores properly. Note that this event can change the history of the game, including things like reset gameEnded back to false (for example if someone plays out with a phony). Return playLegal, error

func (*Game) Config added in v0.4.5

func (g *Game) Config() *config.Config

func (*Game) Copy

func (g *Game) Copy() *Game

Copy creates a deep copy of Game for the most part. The lexicon and alphabet are not deep-copied because these are not expected to change. The history is not copied because this only changes with the main Game, and not these copies.

func (*Game) CopyWithHistory added in v0.11.4

func (g *Game) CopyWithHistory() *Game

CopyWithHistory creates a deep copy of Game including a deep copy of the history. This is specifically for the variation system where each variation needs its own independent history. Use Copy() for performance-critical paths like simulations.

func (*Game) CreateAndScorePlacementMove

func (g *Game) CreateAndScorePlacementMove(coords string, tiles string, rack string, transpose bool) (*move.Move, error)

CreateAndScorePlacementMove creates a *move.Move from the coords and given tiles. It scores the move, calculates the leave, etc. This should be used when a person is interacting with the interface.

func (*Game) CrossSetGen added in v0.13.0

func (g *Game) CrossSetGen() cross_set.Generator

func (*Game) CurrentSpread

func (g *Game) CurrentSpread() int

func (*Game) EventFromMove added in v0.4.5

func (g *Game) EventFromMove(m *move.Move) *pb.GameEvent

func (*Game) ExchangeLimit added in v0.9.9

func (g *Game) ExchangeLimit() int

func (*Game) FirstPlayer

func (g *Game) FirstPlayer() *pb.PlayerInfo

func (*Game) FlipPlayers added in v0.4.9

func (g *Game) FlipPlayers()

func (*Game) History

func (g *Game) History() *pb.GameHistory

func (*Game) LastEvent added in v0.4.5

func (g *Game) LastEvent() *pb.GameEvent

func (*Game) LastScorelessTurns added in v0.7.0

func (g *Game) LastScorelessTurns() int

func (*Game) LastWordsFormed added in v0.4.5

func (g *Game) LastWordsFormed() []tilemapping.MachineWord

func (*Game) Lexicon added in v0.4.5

func (g *Game) Lexicon() lexicon.Lexicon

func (*Game) LexiconName added in v0.4.5

func (g *Game) LexiconName() string

func (*Game) MLEvaluateMove added in v0.11.0

func (g *Game) MLEvaluateMove(m *move.Move, leaveCalc *equity.ExhaustiveLeaveCalculator,
	lastMoves []*move.Move) (*triton.ModelOutputs, error)

MLEvaluateMove evaluates a single move using the machine learning model. It's a wrapper around MLEvaluateMoves.

func (*Game) MLEvaluateMoves added in v0.11.0

func (g *Game) MLEvaluateMoves(moves []*move.Move, leaveCalc *equity.ExhaustiveLeaveCalculator,
	lastMoves []*move.Move) (*triton.ModelOutputs, error)

MLEvaluateMoves evaluates a slice of moves in a single batch inference. Their equities must already be set.

func (*Game) NextPlayer added in v0.4.5

func (g *Game) NextPlayer() int

func (*Game) NickOnTurn

func (g *Game) NickOnTurn() string

func (*Game) NumPlayers

func (g *Game) NumPlayers() int

NumPlayers is always 2.

func (*Game) PlayLatestEvent added in v0.4.5

func (g *Game) PlayLatestEvent() error

PlayLatestEvent "plays" the latest event on the board. This is used for replaying a game from a GCG.

func (*Game) PlayMove

func (g *Game) PlayMove(m *move.Move, addToHistory bool, millis int) error

PlayMove plays a move on the board. This function is meant to be used by simulators as it implements a subset of possible moves, and by remote gameplay engines as much as possible. If the millis argument is passed in, it adds this value to the history as the time remaining for the user (when they played the move).

func (*Game) PlayMoveNoCrossSet added in v0.13.0

func (g *Game) PlayMoveNoCrossSet(m *move.Move, addToHistory bool, millis int) error

PlayMoveNoCrossSet is like PlayMove but skips cross-set recalculation. Use this when no move generation will happen from the resulting position (e.g. the last ply of a Monte Carlo simulation), so the cross-set work would be discarded by UnplayLastMove anyway.

func (*Game) PlayScoringMove

func (g *Game) PlayScoringMove(coords, word string, addToHistory bool) (*move.Move, error)

PlayScoringMove plays a move on a board that is described by the coordinates and word only. It returns the move.

func (*Game) PlaySmallMove added in v0.8.7

PlaySmallMove plays a SmallMove in the game. SmallMove can only be a pass or a tile move play right now. It is meant to be used for pre-endgames and endgames. It is meant for "simulation" mode as opposed to real play mode. A lot of this function is copied from PlayMove. We should try to unite those somehow.

func (*Game) PlaySmallMoveNoCrossSet added in v0.13.0

func (g *Game) PlaySmallMoveNoCrossSet(m *tinymove.SmallMove) (
	*[board.MaxBoardDim]tilemapping.MachineLetter, error)

PlaySmallMoveNoCrossSet is like PlaySmallMove but skips cross-set recalculation. Use this when the resulting position will be immediately unplayed without generating any moves from it (e.g. at negamax leaf depth), so the cross-set work would be discarded by UnplayLastMove anyway.

func (*Game) PlaySmallMoveWithDraw added in v0.13.0

func (g *Game) PlaySmallMoveWithDraw(m *tinymove.SmallMove) (
	*[board.MaxBoardDim]tilemapping.MachineLetter, error)

PlaySmallMoveWithDraw plays a SmallMove and draws replacement tiles from the bag into the rack. After board.PlaySmallMove the rack already holds the leave (played tiles were removed via rack.Take); we draw up to TilesPlayed() new tiles and add them with rack.Add — zero heap allocations.

func (*Game) PlayToTurn

func (g *Game) PlayToTurn(turnnum int) error

func (*Game) PlayTurn added in v0.8.3

func (g *Game) PlayTurn(t int) error

func (*Game) PlayerIDOnTurn added in v0.4.5

func (g *Game) PlayerIDOnTurn() string

func (*Game) PlayerOnTurn

func (g *Game) PlayerOnTurn() int

func (*Game) Playing

func (g *Game) Playing() pb.PlayState

func (*Game) PointsFor

func (g *Game) PointsFor(playerIdx int) int

PointsFor returns the number of points for the given player

func (*Game) PointsForNick

func (g *Game) PointsForNick(nick string) int

func (*Game) RackFor

func (g *Game) RackFor(playerIdx int) *tilemapping.Rack

RackFor returns the rack for the player with the passed-in index

func (*Game) RackLettersFor

func (g *Game) RackLettersFor(playerIdx int) string

RackLettersFor returns a user-visible representation of the player's rack letters

func (*Game) RecalculateBoard added in v0.4.5

func (g *Game) RecalculateBoard()

func (*Game) RenamePlayer added in v0.4.10

func (g *Game) RenamePlayer(idx int, playerinfo *pb.PlayerInfo) error

func (*Game) ResetToFirstState

func (g *Game) ResetToFirstState()

ResetToFirstState unplays all moves on the stack.

func (*Game) Rules added in v0.4.5

func (g *Game) Rules() *GameRules

func (*Game) ScorelessTurns added in v0.4.5

func (g *Game) ScorelessTurns() int

func (*Game) SeedBag added in v0.11.8

func (g *Game) SeedBag(seed [32]byte)

SeedBag sets up a seeded RNG for deterministic tile draws. This should be called before StartGame() to ensure the bag is seeded when created.

func (*Game) SetBackupMode added in v0.4.5

func (g *Game) SetBackupMode(m BackupMode)

func (*Game) SetBoard added in v0.4.5

func (g *Game) SetBoard(b *board.GameBoard)

func (*Game) SetChallengeRule added in v0.4.5

func (g *Game) SetChallengeRule(rule pb.ChallengeRule)

SetChallengeRule sets the challenge rule for a game. The game must already be started with StartGame above (call immediately afterwards). It would default to the 0 state (VOID) otherwise.

func (*Game) SetCrossSetGen added in v0.4.5

func (g *Game) SetCrossSetGen(gen cross_set.Generator)

func (*Game) SetEndgameMode added in v0.8.7

func (g *Game) SetEndgameMode(m bool)

func (*Game) SetHistory added in v0.4.5

func (g *Game) SetHistory(h *pb.GameHistory)

func (*Game) SetMaxScorelessTurns added in v0.4.5

func (g *Game) SetMaxScorelessTurns(m int)

func (*Game) SetPlayerOnTurn

func (g *Game) SetPlayerOnTurn(onTurn int)

func (*Game) SetPlaying added in v0.4.5

func (g *Game) SetPlaying(s pb.PlayState)

func (*Game) SetPointsFor

func (g *Game) SetPointsFor(player, pts int)

func (*Game) SetRackFor

func (g *Game) SetRackFor(playerIdx int, rack *tilemapping.Rack) error

SetRackFor sets the player's current rack. It throws an error if the rack is impossible to set from the current unseen tiles. It puts tiles back from opponent racks and our own racks, then sets the rack, and finally redraws for opponent.

func (*Game) SetRackForOnly added in v0.5.0

func (g *Game) SetRackForOnly(playerIdx int, rack *tilemapping.Rack) error

SetRackForOnly is like SetRackFor, but it doesn't redraw random racks for opponent, or throw racks in. It assumes these tasks have already been done, or will be done properly.

func (*Game) SetRacksForBoth

func (g *Game) SetRacksForBoth(racks []*tilemapping.Rack) error

SetRacksForBoth sets both racks at the same time.

func (*Game) SetRandomRack

func (g *Game) SetRandomRack(playerIdx int, knownRack []tilemapping.MachineLetter) ([]tilemapping.MachineLetter, error)

SetRandomRack sets the player's rack to a random rack drawn from the bag. It tosses the current rack back in first. This is used for simulations. If a second argument (knownRack) is provided, the randomRack will contain the known rack. Any extra drawn tiles are returned as well, in this case.

func (*Game) SetRules added in v0.10.2

func (g *Game) SetRules(r *GameRules)

func (*Game) SetScorelessTurns added in v0.4.5

func (g *Game) SetScorelessTurns(n int)

func (*Game) SetStateStackLength

func (g *Game) SetStateStackLength(length int)

func (*Game) SetUidFromSeed added in v0.11.8

func (g *Game) SetUidFromSeed(seed [32]byte)

SetUidFromSeed sets the game UID based on the seed for deterministic identification. Format: "seed:<base64_encoded_seed>"

func (*Game) SpreadFor

func (g *Game) SpreadFor(playerIdx int) int

func (*Game) StartGame

func (g *Game) StartGame()

StartGame starts a game anew, dealing out tiles to both players.

func (*Game) ThrowRacksIn

func (g *Game) ThrowRacksIn()

ThrowRacksIn throws both players' racks back in the bag.

func (*Game) ThrowRacksInFor added in v0.8.0

func (g *Game) ThrowRacksInFor(pidx int)

func (*Game) ToCGP added in v0.7.0

func (g *Game) ToCGP(formatForBot bool) string

ToCGP converts the game to a CGP string. See cgp directory.

func (*Game) ToDisplayText

func (g *Game) ToDisplayText() string

ToDisplayText turns the current state of the game into a displayable string.

func (*Game) Turn

func (g *Game) Turn() int

func (*Game) TurnsForNick added in v0.4.5

func (g *Game) TurnsForNick(nick string) int

func (*Game) Uid

func (g *Game) Uid() string

func (*Game) UnplayLastMove

func (g *Game) UnplayLastMove()

UnplayLastMove is a tricky but crucial function for any sort of simming / minimax search / etc. It restores the state after playing a move, without having to store a giant amount of data. The alternative is to store the entire game state with every node which quickly becomes unfeasible.

func (*Game) ValidateMove added in v0.4.4

func (g *Game) ValidateMove(m *move.Move) ([]tilemapping.MachineWord, error)

ValidateMove validates the given move. It is meant to be used to validate user input games (perhaps from live play or GCGs). It does not check the validity of the words formed (unless the challenge rule is VOID), but it validates that the rules of the game are followed. It returns an array of `tilemapping.MachineWord`s formed, or an error if the play is not game legal.

func (*Game) ValidateWords added in v0.4.9

func (g *Game) ValidateWords(lex lexicon.Lexicon, words []tilemapping.MachineWord) error

ValidateWords validates all `words` with the passed-in lexicon, and the game's variant. We don't use the game's lexicon because of Reasons.

type GameRules added in v0.4.5

type GameRules struct {
	// contains filtered or unexported fields
}

GameRules is a simple struct that encapsulates the instantiated objects needed to actually play a game.

func NewBasicGameRules added in v0.4.5

func NewBasicGameRules(cfg *config.Config,
	lexiconName, boardLayoutName, letterDistributionName, csetGenName string,
	variant Variant) (*GameRules, error)

func (GameRules) Board added in v0.4.5

func (g GameRules) Board() *board.GameBoard

func (GameRules) BoardName added in v0.4.5

func (g GameRules) BoardName() string

func (GameRules) Config added in v0.4.5

func (g GameRules) Config() *config.Config

func (GameRules) CrossSetGen added in v0.4.5

func (g GameRules) CrossSetGen() cross_set.Generator

func (GameRules) ExchangeLimit added in v0.9.9

func (g GameRules) ExchangeLimit() int

func (GameRules) LetterDistribution added in v0.4.5

func (g GameRules) LetterDistribution() *tilemapping.LetterDistribution

func (GameRules) LetterDistributionName added in v0.4.5

func (g GameRules) LetterDistributionName() string

func (GameRules) Lexicon added in v0.4.5

func (g GameRules) Lexicon() lexicon.Lexicon

func (GameRules) LexiconName added in v0.4.5

func (g GameRules) LexiconName() string

func (*GameRules) SetExchangeLimit added in v0.9.9

func (g *GameRules) SetExchangeLimit(l int)

func (GameRules) Variant added in v0.4.5

func (g GameRules) Variant() Variant

type MLModel added in v0.11.0

type MLModel struct {
	// contains filtered or unexported fields
}

type MLModelTemplate added in v0.11.0

type MLModelTemplate struct {
	// contains filtered or unexported fields
}

MLModelTemplate holds the raw ONNX model data.

func (*MLModelTemplate) NewInstance added in v0.11.0

func (t *MLModelTemplate) NewInstance() (*MLModel, error)

NewInstance creates a new MLModel from the template.

type RequestId added in v0.4.10

type RequestId string

RequestId is used for tagging each incoming http request for logging purposes. The actual implementation is just the ObjectId implementation found in launchpad.net/mgo/bson. This will most likely change and evolve into its own format.

func (RequestId) String added in v0.4.10

func (id RequestId) String() string

func (RequestId) Time added in v0.4.10

func (id RequestId) Time() time.Time

Time returns the timestamp part of the id. It's a runtime error to call this method with an invalid id.

type Variant added in v0.4.5

type Variant string

func HistoryToVariant added in v0.4.5

func HistoryToVariant(h *pb.GameHistory) (boardLayoutName, letterDistributionName string, variant Variant)

HistoryToVariant takes in a game history and returns the board configuration and letter distribution name.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL