wits

package module
v0.0.0-...-5b22ee5 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2024 License: Apache-2.0 Imports: 1 Imported by: 0

README

wits-go

Service/frontend in golang of game logic for Wits, an homage to the mobile strategy game Outwitters 2.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ActionPoints

type ActionPoints byte

Non-negative integer, the amount of "wits" (action points) available, or cost.

func CostForUnit

func CostForUnit(class UnitClassEnum) ActionPoints

Each unit class costs a consistent amount regardless of race or team.

type BaseHealth

type BaseHealth byte

type FriendlyEnum

type FriendlyEnum byte

Team alignment.

const (
	FR_UNKNOWN FriendlyEnum = iota
	// two roles relative to the current player.
	FR_SELF
	FR_ENEMY
	// additional roles available in `duos` game replays:
	FR_ALLY
	FR_ENEMY2
)

func (FriendlyEnum) Opponent

func (role FriendlyEnum) Opponent() FriendlyEnum

Often-useful toggle for player role.

type GCID

type GCID string

A globally consistent identifier for players (from OML, via OSN)

type GameInit

type GameInit interface {
	Units() []UnitInit
}

type GameMapID

type GameMapID string

The identifying string, restricted to hyphenated-alphanumeric. Used as a primary key or file name for locating the map definition.

type GameMapName

type GameMapName string

The human-readable (and translatable) name for the map. Shown in UI/views.

type GameReplay

type GameReplay interface {
	GameID() MatchID
	MapID() GameMapID
	MapTheme() string
	Players() []PlayerRole

	InitState() GameInit
	MatchReplay() []PlayerTurn
	MatchResult() TerminalStatus
}

type GameState

type GameState interface {
	BaseHP(player FriendlyEnum) BaseHealth
	BonusWits() []HexCoord
	Units() []UnitPlacement
}

type HexCoord

type HexCoord interface {
	I() int
	J() int
}

A two-dimensional coordinate for map locations. Third coordinate is implicit. There don't need to be format-specific representations for the raw coordinate.

type HexCoordIndex

type HexCoordIndex uint8

This is a reference to a coordinate, the GameMap can convert it into HexCoord, representing in one byte a wide variety of (i, j) coordinate choices. Its primary benefit is an independence from unit index (pawnID in OSN) when storing and analyzing past replays and future play-theories.

It serves its purpose as an identifier and perfect hash lookup, but at the cost of not being able to calculate the neighboring indices. They could be converted (twice, one to lookup the coordinate, then O(n) lookups for reachable tiles). This mapping is static for each GameMap so they can be precomputed or memoized. For move-to lookups, each position can have its "by-1", "by-2", "by-..." tiles accessible by each distance (up to 5, for the runner). Similarly, a set of "all" visible tiles" can be constructed from these index values instead of coordinate pairs, easier to serialize in JSON and easier to compare pairs of coordinates.

type InvalidTileState

type InvalidTileState struct {
	InvalidUnitState
	At HexCoordIndex
}

A variant of InvalidUnitState for when having a known position.

func (InvalidTileState) Error

func (err InvalidTileState) Error() string

func (InvalidTileState) Index

func (err InvalidTileState) Index() HexCoordIndex

func (InvalidTileState) MoveTo

func (err InvalidTileState) MoveTo(index HexCoordIndex) TileState

type InvalidUnitState

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

An invalid state includes a copy of the unit parameters used to create it.

func (InvalidUnitState) Class

func (err InvalidUnitState) Class() UnitClassEnum

Information about the underlying unit can still be extracted.

func (InvalidUnitState) Cost

func (InvalidUnitState) Distance

func (InvalidUnitState) Distance() TileDistance

func (InvalidUnitState) DoAction

func (err InvalidUnitState) DoAction(action PlayerAction) (UnitState, error)

func (InvalidUnitState) Error

func (err InvalidUnitState) Error() string

func (InvalidUnitState) HasActed

func (InvalidUnitState) HasActed() bool

func (InvalidUnitState) HasAlted

func (InvalidUnitState) HasAlted() bool

func (InvalidUnitState) HasMoved

func (InvalidUnitState) HasMoved() bool

func (InvalidUnitState) HasParent

func (err InvalidUnitState) HasParent() bool

Parentage (e.g., bramble thorns when KO'd also KO their children).

func (InvalidUnitState) Health

func (InvalidUnitState) Health() UnitHealth

Zero values for properties of an invalid state.

func (InvalidUnitState) Init

func (err InvalidUnitState) Init() UnitState

func (InvalidUnitState) IsAlternate

func (InvalidUnitState) IsAlternate() bool

Appropriate zero values for these are where the unit is not allowed to do anything.

func (InvalidUnitState) IsSpecial

func (err InvalidUnitState) IsSpecial() bool

func (InvalidUnitState) Parent

func (err InvalidUnitState) Parent() HexCoordIndex

func (InvalidUnitState) Race

func (err InvalidUnitState) Race() UnitRaceEnum

func (InvalidUnitState) ReceiveBoost

func (err InvalidUnitState) ReceiveBoost() UnitState

func (InvalidUnitState) ReceiveCharm

func (err InvalidUnitState) ReceiveCharm(other Unit) UnitState

func (InvalidUnitState) ReceiveDamage

func (err InvalidUnitState) ReceiveDamage(other Unit) UnitState

func (InvalidUnitState) Strength

func (InvalidUnitState) Strength() UnitHealth

func (InvalidUnitState) Team

func (err InvalidUnitState) Team() FriendlyEnum

func (InvalidUnitState) ToTile

func (err InvalidUnitState) ToTile(index HexCoordIndex) TileState

func (InvalidUnitState) Toggle

func (err InvalidUnitState) Toggle() UnitState

The effect-visiting methods of an invalid state are no-ops.

type LeagueRank

type LeagueRank int

This is the rank out of a group of 100 players (an integer between 1..100).

type LeagueTier

type LeagueTier string

Ranked competitions are divided into skill levels, advancing within a local (top-100) ranking leads to advancing to the next higher tier.

const (
	LEAGUE_TIER_UNRANKED     LeagueTier = "Unranked"
	LEAGUE_TIER_NOVICE       LeagueTier = "Novice"
	LEAGUE_TIER_INTERMEDIATE LeagueTier = "Intermediate"
	LEAGUE_TIER_ADVANCED     LeagueTier = "Advanced"
	LEAGUE_TIER_EXPERT       LeagueTier = "Expert"
)

type MapDescription

type MapDescription interface {
	MapName() GameMapName
	MapID() GameMapID
	Terrain() TerrainDefinition
	Units() []UnitInit
	Legacy() bool
}

type MatchID

type MatchID string

String for uniquely identifying the match between two players (seeded by the player IDs and which sequence )

type PassAction

type PassAction struct{}

While not absolutely necessary to have the encoding work out, as the player turns have dedicated lists they are in, this "no-op" action is crucial. It allows for simplifying assumptions later about empty sets/subsets vis-a-vis the recurrence relation of reordering action subgroups (when canonicalizing).

func (PassAction) ActionName

func (PassAction) ActionName() string

func (PassAction) RelVarEncoding

func (PassAction) RelVarEncoding() string

func (PassAction) Visit

func (PassAction) Visit(*GameState) error

type Placement

type Placement interface {
	Index() HexCoordIndex
}

Composable interface for units/tiles associated with a coordinate-index.

type PlayerAction

type PlayerAction interface {
	ActionName() string
	RelVarEncoding() string
	Visit(*GameState) error
}

type PlayerID

type PlayerID interface {
	PlayerKey() GCID
}

For identifying players globally.

type PlayerName

type PlayerName string

The human-readable representation (may contain unicode)

type PlayerRole

type PlayerRole interface {
	PlayerID
	Name() PlayerName

	Race() UnitRaceEnum
	Team() FriendlyEnum

	Result() TerminalStatus
	BaseHP() BaseHealth
	Wits() ActionPoints
}

Player information as it pertains to a single match.

type PlayerStandings

type PlayerStandings interface {
	Tier() LeagueTier
	Rank() LeagueRank
}

The league & rank of each player at the beginning of the match.

type PlayerStandingsUpdate

type PlayerStandingsUpdate interface {
	PlayerStandings
	Delta() int
}

The league & rank of each player as a result of the match outcome.

type PlayerTurn

type PlayerTurn interface {
	TurnCount() uint
	Actions() []PlayerAction

	// Temporarily here so that we can validate the simulation against the intermediate states.
	State() GameState
}

type Positional

type Positional interface {
	Position() HexCoord
}

Composable interface for units/tiles that are associated with a coordinate.

type RectilinearCoord

type RectilinearCoord interface {
	Column() uint
	Row() uint
	ToHexCoord() HexCoord
}

Legacy maps and replays are in a column-major Euclidean coordinates. Due to the staggered vertical offset of neighboring hexagons in this structure, the coordinates of odd columns are (i-1) and (i) from even columns. The unit vector representation of HexCoord is more suitable in general.

type TerminalStatus

type TerminalStatus byte

An enum describing the win or loss result, relative to the current player (relative to player 1 if without context). Values include win (destruction), win (extinction), ...lose, forfeit

const (
	STATUS_UNKNOWN TerminalStatus = iota
	VICTORY_DESTRUCTION
	VICTORY_EXTINCTION
	VICTORY_RESIGNATION
	DELAY_OF_GAME
	LOSS_DESTRUCTION
	LOSS_EXTINCTION
	LOSS_RESIGNATION
)
const WINLOSS_BIT TerminalStatus = 0b0100

Differentiating bit for (win/loss) result, in non-unknown/defaulting game results.

func (TerminalStatus) Opposing

func (status TerminalStatus) Opposing() TerminalStatus

Converts win or loss status to the equivalent state from the opponent's view. An UNKNOWN is understandably still UNKNOWN, and may represent a game not yet completed.

Although a DELAY_OF_GAME is considered equivalent to resignation in actual play, there is a special exception made here to give it a similar unitary representation similar to unknown. This is useful in situations where reward might erroneously be propagated back from a timing issue when it may not have been a skill-related issue.

type TerrainDefinition

type TerrainDefinition interface {
	Floor() []TileDefinition
	Wall() []TileDefinition
	Bonus() []TileDefinition
	Spawn() []TileDefinition
	Base() []TileDefinition
}

type TileDefinition

type TileDefinition interface {
	Positional
	CanWalk() bool

	IsFloor() bool
	IsWall() bool
	IsSpawn() bool
	IsBase() bool
	IsBonus() bool

	Team() FriendlyEnum
	Typename() string
	Equals(other TileDefinition) bool
}

The position (HexCoord) and

type TileDistance

type TileDistance uint8

non-negative integer value for measuring distance between coordinates.

func DistanceForUnit

func DistanceForUnit(class UnitClassEnum) TileDistance

Distance is also straightforward for standard units but the special units vary depending on whether they are toggled into their alt state. At the point where these details matter, the actions will be invoked on a unit status object which can distinguish which kind of special is the active unit.

type TileState

type TileState interface {
	Placement
	UnitStateExtended
}

The hex-index and unit's essential state (all information per a coordinate).

type Unit

type Unit interface {
	Class() UnitClassEnum
	IsSpecial() bool
	Race() UnitRaceEnum
	Team() FriendlyEnum

	Cost() ActionPoints
	Strength() UnitHealth
	Distance() TileDistance
}

Intrinsic (and invariant) properties of the Unit

type UnitClassEnum

type UnitClassEnum byte

The type of unit (determining its movement, health, actions, ...) can actually fit in three bits (including an UNKNOWN enum) and is usually part of the Unit data. In the case of specials, the tribe data also needs to be known.

const (
	CLASS_UNKNOWN UnitClassEnum = iota
	CLASS_RUNNER
	CLASS_SOLDIER
	CLASS_MEDIC
	CLASS_SNIPER
	CLASS_HEAVY
	CLASS_THORN
	CLASS_SPECIAL
)

These values are inherited from OML enumeration.

func (UnitClassEnum) String

func (class UnitClassEnum) String() string

type UnitHealth

type UnitHealth int

Unit health (and strength) does not exceed 5, its max is determined by the unit's constructor; some units have a maix health of 2, all units have a max (and constant) UnitHealth equivalent measuring their strength.

func StrengthForUnit

func StrengthForUnit(class UnitClassEnum) UnitHealth

Calculating unit strength is a little tricky for special units because most specials do not have an attack, except the bombshell which has an added AoE splash-damage to adjacent tiles. We generalize with 3 here.

type UnitInit

type UnitInit interface {
	Positional
	Team() FriendlyEnum
	Class() UnitClassEnum
	Health() UnitHealth // if 0 value, use default
}

type UnitParentage

type UnitParentage interface {
	HasParent() bool
	Parent() HexCoordIndex
}

type UnitPlacement

type UnitPlacement interface {
	UnitState
	Placement
}

type UnitRaceEnum

type UnitRaceEnum byte

UnitRace is an enumeration with both string and integer representations. In contexts where the explicit UNKNOWN value is unnecessary (e.g., in Unit) the other values may be squeezed into two bits without loss of generality.

const (
	RACE_UNKNOWN UnitRaceEnum = iota
	RACE_FEEDBACK
	RACE_ADORABLES
	RACE_SCALLYWAGS
	RACE_VEGGIENAUTS
)

func (UnitRaceEnum) String

func (race UnitRaceEnum) String() string

type UnitState

type UnitState interface {
	Unit
	Health() UnitHealth

	// Two special units (bombshell and bramble) have a "toggle" special action
	// that they need to perform before being able to do a more powerful action.
	IsAlternate() bool
	Toggle() UnitState

	// Health and Team are not directly assigned, they are affected by effects.
	ReceiveBoost() UnitState
	ReceiveDamage(other Unit) UnitState
	ReceiveCharm(other Unit) UnitState
	DoAction(action PlayerAction) (UnitState, error)
}

Common interface for JSON-loaded and binary-deflated representations. This is turn-intransient state (excluding status bits like HasMoved, HasActed). This state and a position are enough to make reasonable strategy decisions. Some information, such as parentage, would need to be derived and is subject to the partial information visibility of each player (the thorn that spawned a thorn may be known only if the parent was visible during spawning). These properties were chosen because they are minimally-satisfying and as much as I could pack within just eight bits.

type UnitStateExtended

type UnitStateExtended interface {
	UnitState
	UnitTurnStatus
	UnitParentage
}

type UnitTurnStatus

type UnitTurnStatus interface {
	HasActed() bool
	HasMoved() bool
	HasAlted() bool
}

type UnknownActionError

type UnknownActionError struct {
	Name string
}

func (UnknownActionError) Error

func (e UnknownActionError) Error() string

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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