Documentation
¶
Index ¶
- Constants
- Variables
- func ColumnName(col int) string
- func LinksCross(a, b Link) bool
- func LoadRecord(s string) (*Game, Record, error)
- func ParseColumn(s string) (int, error)
- func PositionDigest(g *Game) string
- func PresetNames() []string
- func PresetSummary(name string) string
- type Dir
- type Game
- func (g *Game) AbortTurn()
- func (g *Game) AcceptDraw(pl Player) error
- func (g *Game) AddLink(a, b Point) error
- func (g *Game) At(p Point) Player
- func (g *Game) CanPlace(pl Player, p Point) error
- func (g *Game) CanSwap() bool
- func (g *Game) Clone() *Game
- func (g *Game) CommitTurn() (Result, error)
- func (g *Game) Connected(pl Player) bool
- func (g *Game) DrawOfferedBy() Player
- func (g *Game) EachLegalPlacement(pl Player, fn func(Point) bool)
- func (g *Game) Entries() int
- func (g *Game) Exists(p Point) bool
- func (g *Game) HasLegalPlacement(pl Player) bool
- func (g *Game) HasLink(l Link) bool
- func (g *Game) History() []Move
- func (g *Game) InBounds(p Point) bool
- func (g *Game) IsBorderRow(pl Player, p Point) bool
- func (g *Game) IsCorner(p Point) bool
- func (g *Game) LegalPlacement(p Point) bool
- func (g *Game) LegalPlacements(pl Player) []Point
- func (g *Game) LinkBlockedBy(l Link, owner Player) (Link, bool)
- func (g *Game) LinkMask(p Point) uint8
- func (g *Game) LinkOwner(l Link) Player
- func (g *Game) MoveNotation(i int) (string, error)
- func (g *Game) OfferDraw(pl Player) error
- func (g *Game) PegCount(pl Player) int
- func (g *Game) PlacePeg(p Point) error
- func (g *Game) PlayNotation(s string) error
- func (g *Game) PlayPeg(p Point) (Result, error)
- func (g *Game) Ply() int
- func (g *Game) Record() (Record, error)
- func (g *Game) RemoveLink(a, b Point) error
- func (g *Game) RemovePeg(p Point) error
- func (g *Game) Resign(pl Player) error
- func (g *Game) Result() Result
- func (g *Game) Rules() Ruleset
- func (g *Game) Size() int
- func (g *Game) Staged() StagedTurn
- func (g *Game) String() string
- func (g *Game) Swap() error
- func (g *Game) Swapped() bool
- func (g *Game) Transcript() (string, error)
- func (g *Game) Turn() Player
- func (g *Game) UndoLastMove() error
- type Link
- type Move
- type MoveKind
- type Outcome
- type Player
- type Point
- type Reason
- type Record
- type Result
- type Ruleset
- type StagedTurn
Constants ¶
const ( MinSize = 6 MaxSize = 48 )
MinSize and MaxSize bound the playable board. The lower bound keeps the board wide enough for a knight's move between opposite border rows; the upper bound matches the largest size offered by any known venue.
const NumDirs = 8
NumDirs is the number of link directions.
const RecordVersion = 1
RecordVersion is the format version written by Encode.
Variables ¶
var ( ErrGameOver = errors.New("the game is over") ErrNotYourTurn = errors.New("not this player's turn") ErrOffBoard = errors.New("hole is off the board") ErrCornerHole = errors.New("corner holes do not exist") ErrOccupied = errors.New("hole already holds a peg") ErrOpponentBorder = errors.New("you may not place a peg in your opponent's border row") ErrPegAlreadySet = errors.New("you have already placed a peg this turn") ErrNoPegPlaced = errors.New("a turn must place exactly one peg") ErrNotKnightMove = errors.New("pegs are not a knight's move apart") ErrNotOwnPeg = errors.New("both pegs must be yours") ErrLinkExists = errors.New("that link already exists") ErrNoSuchLink = errors.New("there is no such link") ErrLinkCrosses = errors.New("that link would cross an existing link") ErrLinkingLocked = errors.New("this ruleset links automatically and does not allow link edits") ErrRemovalLocked = errors.New("this ruleset does not allow removing links placed on an earlier turn") ErrPegRemovalOff = errors.New("this ruleset does not allow removing pegs") ErrRemoveAfterPeg = errors.New("removals come before the peg is placed, not after") ErrNoDrawOffer = errors.New("there is no draw offer to accept") )
Errors reported by the engine. They are sentinel values so a caller can react to a specific rule violation instead of matching on message text.
var ( // Std is the default: the printed box rules, with deliberate linking, own // links blocking, removable links and the swap option. Std = Ruleset{ Size: 24, DeliberateLinking: true, LinkRemoval: true, PegRemoval: false, OwnLinksMayCross: false, Swap: true, } // PP is the paper-and-pencil ruleset used by online venues: links are // created automatically and are permanent, and a player's own links may // cross each other. PP = Ruleset{ Size: 24, DeliberateLinking: false, LinkRemoval: false, PegRemoval: false, OwnLinksMayCross: true, Swap: true, } // Classic3M is the original 1962 3M edition: box rules without the swap // option, which Randolph added for a later edition. Classic3M = Ruleset{ Size: 24, DeliberateLinking: true, LinkRemoval: true, PegRemoval: false, OwnLinksMayCross: false, Swap: false, } )
Named rulesets.
Functions ¶
func ColumnName ¶
ColumnName returns the letter name of a zero-based column index.
func LinksCross ¶
LinksCross reports whether two links geometrically cross, and is the single authority for the crossing rule. It is exact and colour-blind; whether a crossing is actually forbidden depends on the ruleset (see Ruleset.blocks).
func LoadRecord ¶
LoadRecord decodes and replays in one step, which is what a caller reading a saved game wants.
func ParseColumn ¶
ParseColumn returns the zero-based index of a column letter name.
func PositionDigest ¶
PositionDigest hashes the position itself: the pegs, the links, the side to move and the result. It is derived from the board rather than from the move text, so it catches a record whose moves do not lead where it says they do. Iteration is in a fixed order, so the digest depends only on the position.
func PresetNames ¶
func PresetNames() []string
PresetNames returns the available ruleset names in a stable order.
func PresetSummary ¶
PresetSummary returns the one-line description of a named preset.
Types ¶
type Dir ¶
type Dir uint8
Dir is one of the eight knight-move link directions.
const ( NNE Dir = 0 ENE Dir = 1 ESE Dir = 2 SSE Dir = 3 SSW Dir = 4 WSW Dir = 5 WNW Dir = 6 NNW Dir = 7 )
The eight link directions, clockwise from north-north-east. North is towards row 0, i.e. up on screen.
func (Dir) IsCanonical ¶
IsCanonical reports whether d is one of the four directions used to name a link uniquely. Every link has exactly one endpoint from which it points in a canonical direction, because no link direction has a zero column offset.
type Game ¶
type Game struct {
// contains filtered or unexported fields
}
Game is a TwixT position together with its rules and history.
func ReplayTranscript ¶
ReplayTranscript builds a game from a ruleset and a transcript.
func (*Game) AbortTurn ¶
func (g *Game) AbortTurn()
AbortTurn discards every uncommitted edit, restoring the position to the start of the turn.
func (*Game) AcceptDraw ¶
AcceptDraw accepts the opponent's standing draw offer.
func (*Game) AddLink ¶
AddLink links two of the current player's pegs. Under a ruleset that links automatically there is nothing to add by hand and this is refused.
func (*Game) CanPlace ¶
CanPlace reports why a player may not place a peg in a hole, or nil if they may. A player may use their own border rows but never their opponent's.
func (*Game) CanSwap ¶
CanSwap reports whether the side to move may take the swap option, which exists only in answer to the very first peg.
func (*Game) CommitTurn ¶
CommitTurn ends the turn, evaluates the position and passes the move to the opponent. A turn must place exactly one peg.
func (*Game) DrawOfferedBy ¶
DrawOfferedBy returns the player with a standing draw offer, if any.
func (*Game) EachLegalPlacement ¶
EachLegalPlacement calls fn for every hole the player may use, stopping early if fn returns false. It allocates nothing, which matters inside search.
func (*Game) Entries ¶
Entries returns the number of entries in the game record, including those that are not turns.
func (*Game) HasLegalPlacement ¶
HasLegalPlacement reports whether the player has anywhere left to play.
func (*Game) IsBorderRow ¶
IsBorderRow reports whether the point lies on one of the player's own two border lines.
func (*Game) IsCorner ¶
IsCorner reports whether the point is one of the four corner holes, which do not exist on a TwixT board.
func (*Game) LegalPlacement ¶
LegalPlacement reports whether the side to move may place a peg in a hole.
func (*Game) LegalPlacements ¶
LegalPlacements returns every hole the given player may place a peg in.
func (*Game) LinkBlockedBy ¶
LinkBlockedBy returns the link that prevents l from being created, if any. The link is canonicalised first, so a caller that built one by hand with a non-canonical direction still gets the right answer.
func (*Game) LinkOwner ¶
LinkOwner returns the side owning a link, or NoPlayer if it is not present.
func (*Game) MoveNotation ¶
MoveNotation renders the move at the given index of the game's history, working out which offered links the player declined by replaying the position.
func (*Game) PlacePeg ¶
PlacePeg places the peg for the turn in progress and takes every link the ruleset offers. It does not end the turn: call CommitTurn.
func (*Game) PlayNotation ¶
PlayNotation parses and plays one move written in player notation.
func (*Game) PlayPeg ¶
PlayPeg places a peg and commits the turn, taking the links the ruleset offers. It is the whole of an ordinary move and the only entry point search and replay need.
func (*Game) Ply ¶
Ply returns the number of turns played. Resignations and draw offers are in the record but are not turns, so they do not count.
func (*Game) RemoveLink ¶
RemoveLink takes one of the current player's links off the board.
Withdrawing a link that came into being this turn is always allowed when linking is deliberate, because choosing not to have a link is a choice the printed rules grant. Removing a link placed on an earlier turn is a different act: it needs Ruleset.LinkRemoval, and the printed rules put it before the peg is placed, so it is refused afterwards.
func (*Game) RemovePeg ¶
RemovePeg lifts one of the current player's pegs, and every link attached to it, off the board. The printed rules place removals before the peg is placed, so this is refused once the turn's peg is down.
func (*Game) Resign ¶
Resign concedes the game. A player may resign at any time, including while the opponent is thinking, so this does not depend on whose turn it is.
func (*Game) Staged ¶
func (g *Game) Staged() StagedTurn
Staged returns the turn in progress. The slices are copies, so a caller may hold the value across further staging calls without watching it change underneath; a board view asks for this every frame and the lists are almost always empty.
func (*Game) Swap ¶
Swap exercises the swap option: the opening peg changes hands and reflects across the board's main diagonal, so it now stands on a hole that is legal for its new owner. The reflection is the convention used by the SGF game-record format and by online venues.
func (*Game) Transcript ¶
Transcript renders the whole game as a semicolon-separated move list.
func (*Game) UndoLastMove ¶
UndoLastMove reverses the most recent record entry, discarding any turn in progress.
type Link ¶
Link is an edge between two pegs a knight's move apart, named by its endpoint with the smaller column together with the canonical direction towards the other endpoint. Canonicalise with NewLink.
func NewLink ¶
NewLink returns the canonical Link connecting a and b, and whether a and b are actually a knight's move apart.
func (Link) Canonical ¶
Canonical returns the link named from its endpoint with the smaller column. A Link built by hand may point in any of the eight directions; anything that indexes a per-direction table needs the canonical form of the same edge.
type Move ¶
type Move struct {
Kind MoveKind
Player Player
// Peg is the hole a peg was placed in, for PlaceMove and SwapMove.
Peg Point
// AutoLinks is the set of directions from Peg that were linked when the peg
// was placed and still stood at the end of the turn, as a bitmask over Dir.
AutoLinks uint8
// Added lists links the player added by hand, beyond AutoLinks.
Added []Link
// Removed lists links the player deliberately took off the board before
// placing their peg. These appear in the move's notation.
Removed []Link
// RemovedPegs lists the player's own pegs lifted off the board.
RemovedPegs []Point
// PegLinks lists the links that came away with those pegs. They are implied
// by the removal rather than chosen, so they are not part of the notation,
// but they are needed to reverse the move exactly.
PegLinks []Link
}
Move is one entry in the game record, holding enough to replay and to reverse it exactly.
type MoveKind ¶
type MoveKind uint8
MoveKind distinguishes the kinds of entry in a game record.
const ( // PlaceMove is an ordinary turn: optional removals, one peg, optional link edits. PlaceMove MoveKind = iota // SwapMove is the second player exercising the swap option. SwapMove // ResignMove ends the game in favour of the opponent. ResignMove // DrawOfferMove offers a draw. DrawOfferMove // DrawAcceptMove accepts a standing draw offer. DrawAcceptMove )
Move kinds.
func (MoveKind) ConsumesTurn ¶
ConsumesTurn reports whether an entry of this kind is a turn. A resignation or a draw offer is made whenever a player likes, including while the opponent is thinking, so it does not advance the move order and does not count as a ply.
type Player ¶
type Player uint8
Player identifies a side. The engine names sides by the axis they connect rather than by colour, because which colour plays which axis is a display choice that differs between editions and is picked by the player at setup.
func ParsePlayer ¶
ParsePlayer reads a side name, accepting the full axis name or its initial.
type Point ¶
Point is a hole on the board.
func ParsePoint ¶
ParsePoint reads a hole name such as "B4" or "aa12".
type Reason ¶
type Reason uint8
Reason explains how a game ended.
const ( NotOver Reason = iota // Connection means a border-to-border chain was completed. Connection // NoMovesLeft means the player to move had no legal placement. NoMovesLeft // Resignation means a player resigned. Resignation // Agreement means both players agreed to a draw. Agreement )
Possible end reasons.
type Record ¶
type Record struct {
Version int
Ruleset Ruleset
// Moves is the transcript: record entries separated by semicolons.
Moves string
// Outcome and Reason are the result the record claims to reach.
Outcome Outcome
Reason Reason
// Position is a digest of the final position, independent of the move text.
Position string
// Entries is the number of record entries, which pins padding that changes
// nothing on the board, such as a repeated draw offer.
Entries int
// Digest covers the whole record and catches an edit to any other field.
Digest string
}
Record is a game together with everything needed to check it replays to the game it claims to be.
func DecodeRecord ¶
DecodeRecord parses a record and checks its digest. It does not replay the game; call Replay for that.
type Ruleset ¶
type Ruleset struct {
// Size is the side length of the square grid of holes. The standard
// commercial board is 24.
Size int
// DeliberateLinking gives the player control over which links exist. The
// printed box rules describe linking as a choice and state that a link a
// player could have made but did not is no barrier, so omitting a link is a
// legal and sometimes useful decision. Online venues instead link
// automatically and offer no choice at all; set this false to reproduce
// that. When true the engine still proposes every legal link on placement,
// but the player may withdraw any of them before committing the turn.
DeliberateLinking bool
// LinkRemoval allows a player to take their own links, placed on earlier
// turns, off the board as part of their turn. The box rules permit this;
// the paper-and-pencil ruleset does not. Withdrawing a link proposed during
// the current, uncommitted turn is governed by DeliberateLinking, not by
// this option.
LinkRemoval bool
// PegRemoval additionally allows a player to lift their own previously
// placed pegs, together with the links attached to them. Only one
// transcription of the printed rules describes this, and no other
// implementation or venue offers it, so it is off in every preset and must
// be opted into.
PegRemoval bool
// OwnLinksMayCross relaxes the crossing rule so that only an opponent's
// links block. Crossed links of the same colour are still not connected to
// one another. The box rules forbid this; the paper-and-pencil ruleset
// allows it.
OwnLinksMayCross bool
// Swap offers the second player a one-time option, immediately after the
// first peg is placed, to take over that peg and side. Absent from the
// original 1962 edition, present in every later edition and online venue.
Swap bool
}
Ruleset holds the rule choices that historical editions and online venues of TwixT genuinely disagree about. Every divergence found while surveying the sources is an explicit option here rather than being silently baked into the engine; docs/rules.md records which source supports which setting.
func ParseCanonicalRuleset ¶
ParseCanonicalRuleset reads the encoding produced by Ruleset.Canonical.
func (Ruleset) Canonical ¶
Canonical returns a stable, parseable encoding of the ruleset. Two engines that agree on this string agree on every rule, which is what makes it usable as a compatibility check between networked opponents.
func (Ruleset) Fingerprint ¶
Fingerprint returns a short hash of the canonical encoding. The network handshake compares fingerprints so a mismatched opponent is rejected before the first move rather than desyncing mid-game.
func (Ruleset) PresetName ¶
PresetName returns the name of the preset matching rs ignoring board size, or the empty string if rs is not a preset.