proto

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package proto is the protocol between the host (internal/ui and internal/proto/host) and every "program" it runs: the persona, each game, the ending and the movie director.

A program never touches the terminal. It receives Events, returns Outputs, and draws into a Canvas of semantic styles. It must not block: anything slow (an AI search, a brain reply) is returned as a Think output and runs off the UI goroutine.

The package depends on the standard library only.

Index

Constants

View Source
const (
	DomainBrain uint64 = 1 << 56 // id: brain turn
	DomainGame  uint64 = 2 << 56 // id: hash32(slug)<<16 | play index
	DomainAI    uint64 = 3 << 56 // id: think sequence number
	DomainMovie uint64 = 4 << 56 // id: scene number
	DomainUI    uint64 = 5 << 56 // id: 0
)

Stream domains keep every consumer's random sequence separate. A StreamID is Domain<<56 | id.

Variables

View Source
var ErrCanceled = errors.New("cancelled by the user")

ErrCanceled is ThinkDone.Err when the user cancelled the request (Esc while a brain reply was pending).

Functions

func GameStream

func GameStream(slug string, playIndex uint16) uint64

GameStream returns the stream id for the playIndex-th game of slug in a session.

func NewRand

func NewRand(seed, stream uint64) *rand.Rand

NewRand is the only sanctioned way to make a random source (forbidigo bans the top-level math/rand/v2 functions). The same seed and stream always produce the same sequence, across Go releases.

Types

type Animate

type Animate struct{ Every time.Duration }

Animate asks for TickEvents every Every; 0 stops them.

type Attr

type Attr uint8

Attr is a set of text attributes.

const (
	AttrBlink Attr = 1 << iota
	AttrReverse
	AttrUnderline
	AttrBold
)

Attributes. Blink is rendered by the ui's clock (at most 3 Hz), not by SGR 5.

type AwaitKeys

type AwaitKeys struct {
	Hint    string
	Capture bool
}

AwaitKeys switches to key mode; KeyEvents follow until the next Prompt.

Capture is for a root program other than the persona (the movie director): it then receives every key, Esc included (KeyEsc), with none of the host's side effects: no key skips the typewriter and Esc is not the host's. While a program it launched runs, keys other than Ctrl+C do nothing. The host ignores Capture from a launched program.

type Canvas

type Canvas struct {
	W, H int
	// contains filtered or unexported fields
}

Canvas is a fixed-size grid of cells that programs draw into. Every rune occupies one cell; art is ASCII by design.

func NewCanvas

func NewCanvas(w, h int) *Canvas

NewCanvas returns a blank w×h canvas.

func (*Canvas) At

func (c *Canvas) At(x, y int) Cell

At returns the cell at x, y, or a blank cell outside the canvas.

func (*Canvas) Put

func (c *Canvas) Put(x, y int, s string, st Style, a Attr) int

Put writes s starting at x, y in one style, clipping at the edges. It returns the x after the last rune written.

func (*Canvas) Reset

func (c *Canvas) Reset(w, h int)

Reset resizes the canvas and blanks it.

func (*Canvas) Set

func (c *Canvas) Set(x, y int, cell Cell)

Set writes one cell; positions outside the canvas are ignored.

func (*Canvas) String

func (c *Canvas) String() string

String renders the text of the canvas, one line per row, with trailing spaces trimmed. Golden tests use it so they stay independent of the theme.

func (*Canvas) StyleMap

func (c *Canvas) StyleMap() string

StyleMap renders one style letter per non-blank cell ('.' for blanks), so goldens can assert colour meaning without escape codes.

type Cell

type Cell struct {
	R rune
	S Style
	A Attr
}

Cell is one character position.

type Clear

type Clear struct{}

Clear starts a new page. Scrollback keeps what was above it. The host starts one by itself when it launches a program whose layout is not LayoutConsole (see Launch).

type Done

type Done struct{ Result Result }

Done pops this program; the one below receives GameOver.

type Drain added in v0.2.0

type Drain struct{}

Drain asks for a Drained event once everything output before it has been revealed and its pauses waited out, so a program can pace itself one step at a time (movie mode). A newer Drain replaces a pending one, and only the running program hears it.

type Drained added in v0.2.0

type Drained struct{}

Drained answers a Drain: the output before it has been revealed.

type Env

type Env struct {
	Seed          uint64 // derive random streams with NewRand(Seed, StreamID)
	Width, Height int    // the program's layout area, always at least its minimum
	Instant       bool   // no pacing: --instant, tests
	Deterministic bool   // --seed or WOPR_SEED, tests, movie mode: searches obey Limit, not the clock
	ReduceMotion  bool   // --reduce-motion: no acceleration, no blinking
	Mode          string // optional launch mode, e.g. "climax"
}

Env is what a program learns about its surroundings when it starts.

type Event

type Event interface {
	// contains filtered or unexported methods
}

Event is something the host tells a program. The set is closed.

type GameOver

type GameOver struct{ Result Result }

GameOver tells a program that the program it launched has finished.

type Hold added in v0.2.0

type Hold struct{ On bool }

Hold freezes output while On: the typewriter, Wait, Animate and Blink stop where they are, as they do behind the TERMINAL TOO SMALL card, until a Hold with On false (movie mode's pause). Keys still arrive, but none reveals held output, and neither does Env.Instant. Only a root program that captures keys (AwaitKeys.Capture) can hold output, since it alone is sure to get the key that releases it; the host ignores Hold from any other program. A hold ends when its program launches another or ends.

type Key

type Key uint8

Key is a key a program can receive in key mode. Esc belongs to the host: only a root program that captures keys (AwaitKeys.Capture, movie mode) receives KeyEsc.

const (
	KeyRune Key = iota // a printable character; see KeyEvent.Rune (Space arrives as ' ')
	KeyUp
	KeyDown
	KeyLeft
	KeyRight
	KeyEnter
	KeyBackspace
	KeyEsc // only for a capturing root program
)

Keys.

func (Key) String

func (k Key) String() string

type KeyEvent

type KeyEvent struct {
	Key  Key
	Rune rune // set when Key is KeyRune
}

KeyEvent is a key press, delivered only in key mode (after AwaitKeys). KeyEsc arrives only at a root program that captures keys.

type Launch

type Launch struct{ Slug, Mode string }

Launch pushes another program on top of this one. A program with its own screen (any layout but LayoutConsole) starts on a new page, whether it was launched or handed off to, so its console strip shows only its own text. Ending a program does not start one: its last lines stay above the verdict.

type Layout

type Layout uint8

Layout says where a program's View goes.

const (
	LayoutConsole Layout = iota // console text only
	LayoutPanel                 // View on top, console strip and input line below
	LayoutFull                  // View fills the screen above a 3-row strip and the input line
)

Layouts.

type Limit

type Limit struct {
	MaxDepth int
	MaxNodes uint64
}

Limit bounds a search deterministically. Zero fields mean "no limit".

type LineEvent

type LineEvent struct{ Text string }

LineEvent answers the last Prompt. Text is sanitised and trimmed; "" is an empty Enter.

type Outcome

type Outcome uint8

Outcome is how a program ended.

const (
	Win Outcome = iota
	Loss
	Draw
	NoWinner
	Aborted
)

Outcomes.

type Output

type Output interface {
	// contains filtered or unexported methods
}

Output is something a program asks the host to do. The set is closed: every output a program can produce is declared in this file.

func Typed added in v0.2.0

func Typed(prompt, text string, r *rand.Rand) []Output

Typed returns the outputs that show a user typing text after prompt, laid out as the console echoes an answer: the prompt at once, a pause, the text a few keystrokes at a time at PaceTyping on the same row, then a blank line. r jitters the pauses and the bursts (movie mode seeds it); with nil every keystroke is its own burst and the pauses are fixed. Under Env.Instant the host drops the pauses, so the line appears whole.

type Pace

type Pace uint8

Pace is how fast the typewriter reveals text.

const (
	PaceSpeech  Pace = iota // WOPR speaking, about 30 characters per second
	PaceTable               // tables and lists, fast
	PaceInstant             // boards and redraws, no delay
	PaceTyping              // a simulated user typing (movie mode), about 8 characters per second
)

Paces.

func (Pace) CharsPerSecond

func (p Pace) CharsPerSecond() float64

CharsPerSecond returns the typewriter speed for p; 0 means instant.

type Program

type Program interface {
	// Start is called once, after the first valid terminal size is known.
	Start(Env) []Output
	// Handle reacts to one event. It must return quickly.
	Handle(Event) []Output
	// View draws the program's layout area. It is never called for LayoutConsole.
	View(c *Canvas)
}

Program is implemented by the persona, every game, the ending and the movie director.

type Prompt

type Prompt struct{ Text string }

Prompt switches to line mode; the next LineEvent answers it.

type Quit

type Quit struct{}

Quit ends the session normally (exit code 0).

type Redraw

type Redraw struct{}

Redraw asks the host to call View again.

type ResizeEvent

type ResizeEvent struct{ Width, Height int }

ResizeEvent reports a change of the program's layout area.

type Result

type Result struct {
	Outcome   Outcome
	Lines     []string // kill ratios and other detail for the persona's verdict
	Next      *Launch  // hand-off without a verdict, e.g. gtw → tictactoe(climax) → ending
	NoVerdict bool     // the persona adds nothing after this program's last line
}

Result is reported by Done.

type Say

type Say struct {
	Lines []string
	Pace  Pace
	Open  bool
}

Say prints lines through the typewriter. With Open, the last line stays open: the next Say continues it on the same row, as a typist's keystrokes do (movie mode, Typed).

type SetLayout

type SetLayout struct {
	Layout    Layout
	PanelRows int // rows for LayoutPanel; ignored otherwise
}

SetLayout changes where the program's View goes.

type Skip added in v0.2.0

type Skip struct{}

Skip reveals at once everything output before it, as a key press skips the typewriter (movie mode's next and previous scene). It reveals held output too.

type Style

type Style uint8

Style is the meaning of a cell, not its colour. The ui maps each Style to the active theme, with explicit 16-colour and no-colour fallbacks.

const (
	StyleText Style = iota
	StyleBright
	StyleDim
	StyleAccent
	StyleLand
	StyleLabel
	StyleIncoming
	StyleOutgoing
	StyleTarget
	StyleDefcon1
	StyleDefcon2
	StyleDefcon3
	StyleDefcon4
	StyleDefcon5
	StyleAlert
	StyleSuitRed
	StyleSuitBlack
	StyleSelected
)

Styles.

func Styles added in v0.3.0

func Styles() []Style

Styles lists every Style in order. Tests that must hold for each style (every theme defines it, its contrast) range over it, so a new Style is covered once it is declared.

func (Style) Letter

func (s Style) Letter() byte

Letter returns the one-character code StyleMap uses for s.

type Think

type Think struct {
	Fn     func(ctx context.Context) (any, error)
	Limit  Limit
	Budget time.Duration
}

Think runs Fn off the UI goroutine and delivers its result as a ThinkDone event.

Fn must use only values it captured (copy positions, e.g. as a FEN string): the program keeps running while Fn does. With Env.Deterministic, Fn must stop at Limit; Budget is a safety cap. Otherwise Budget is the main bound: when the context's deadline passes, Fn returns the best result it has, without an error.

type ThinkDone

type ThinkDone struct {
	Value any
	Err   error
}

ThinkDone carries the result of the program's Think. A program has at most one Think in flight: a new Think replaces the previous one, whose result is dropped. Err is ErrCanceled when the user cancelled the Think with Esc and the program keeps running (a brain reply at the root); a confirmed abort pops the program, so its result is never delivered. For a search, a deadline is not an error (Fn returns its best result); slow I/O such as a brain reply returns an error instead.

type TickEvent

type TickEvent struct{ Dt time.Duration }

TickEvent arrives at the cadence a program asked for with Animate.

type Wait

type Wait struct{ D time.Duration }

Wait pauses output for D. Any key skips it; it is zero under Env.Instant.

Directories

Path Synopsis
Package host runs proto programs.
Package host runs proto programs.

Jump to

Keyboard shortcuts

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