Documentation
¶
Overview ¶
Package react makes characters react to what the player says or does, without a language model. See docs/decisions/0015-reaction-and-chat.md.
A Stimulus (typed text, a game event, numbers such as a tip) runs through the built-in analyzers. They attach Tags with a confidence in 0..1: lexicon words, acrostics, repetition and references to what the character remembers. Tags the game already knows come in Stimulus.Tags. The rules of the person in the Book, whose conditions are expressions, then pick a Reaction. When no rule holds, the person dodges in character (teases, asks back, changes the subject) with a line chosen by how sure the analysis was. Judging is deliberately simple; the person's manner is what makes it feel clever.
Load and Parse read a Book (a shared lexicon and the people) and validate every reference. New makes a Mind, the running state of one person: mood, memory, cooldowns and a pending question. A Mind is not safe for concurrent use. Save and Restore keep that state as bytes.
Index ¶
Constants ¶
const ( // TagRepeat is attached when the sender says the same thing again. TagRepeat = "repeat" // TagRecall is attached when the text mentions something the person remembers. TagRecall = "recall" // TagEmpty is attached to a "say" stimulus with no text. TagEmpty = "empty" // AcrosticPrefix prefixes a lexicon tag found in the first characters of the lines // (acrostic_cat for the tag cat). AcrosticPrefix = "acrostic_" )
Built-in tags that the analyzers attach besides the lexicon tags.
const KindSay = "say"
KindSay is the stimulus kind of spoken or typed words.
Variables ¶
This section is empty.
Functions ¶
func Normalize ¶
Normalize folds text so that casual spellings match the lexicon: full-width and half-width forms are unified, katakana becomes hiragana, Latin letters become lower case, and spaces, punctuation and long-vowel marks ("ー", "〜") are dropped. A run of three or more of the same character becomes two, so "かわいいいい" matches "かわいい". The lexicon and the input go through the same folding.
Types ¶
type Book ¶
type Book struct {
// contains filtered or unexported fields
}
Book is a lexicon shared by the people and the people themselves, as Load and Parse read them. A Book is read-only after loading and may be shared by many Minds. Its parts are read with YAML.
type Config ¶
type Config struct {
// Rand chooses lines. Nil uses a fixed seed, so reactions are reproducible.
Rand *rand.Rand
// Clock is the game time, for memories with a Time limit. Nil is allowed only when
// no rule of the person uses Time.
Clock func() time.Duration
// MaxRunes cuts longer text before analysis (0 means 400).
MaxRunes int
// History is how many recent texts per sender are kept to find repeats (0 means 8).
History int
}
Config holds a Mind's collaborators. The zero value works: a fixed random seed, no game clock, 400 runes and 8 remembered texts per sender.
type Mind ¶
type Mind struct {
// contains filtered or unexported fields
}
Mind is the running state of one person. It is not safe for concurrent use.
func New ¶
New makes the running state of the person id in the book. The book must have been validated (Load and Parse do it) and must not change while the Mind is used.
func (*Mind) Ask ¶
Ask has the person put the question id, as a reaction of its own (for example when the game wants the person to start a topic).
func (*Mind) React ¶
React analyzes the stimulus, chooses a rule (or a dodge) and applies it to the mood and memory. An error means a condition failed to evaluate (for example comparing a remembered string with a number). The turn then still advances and memories whose limit has passed are dropped, as on every call; the mood, the remaining memory, the recent texts, the pending question and the cooldowns are unchanged, so retrying the same stimulus is not counted as a repeat.
func (*Mind) Recall ¶
Recall is a remembered value (a string or a float64); ok is false when it is absent or expired.
func (*Mind) Reset ¶
func (m *Mind) Reset()
Reset starts a new conversation with the same person, such as the next stream or a later visit: the recent texts used to find repeats and the pending question are cleared, while the mood, the memory and the cooldowns are kept.
type Reaction ¶
type Reaction struct {
// ruleDef is the rule ID, "dodge.repeat", "dodge.unsure", "dodge.unknown",
// "ask.ID" for Mind.Ask, or empty when the person had nothing to say.
Rule string
// Lines are the line said and, when the rule asks a question, the question.
Lines []string
Face string
// Delta is the mood change applied; Mood is the mood after it.
Delta, Mood float64
// Confidence is the highest tag score (0 when nothing was found).
Confidence float64
// Tags are the findings, the most confident first.
Tags []Tag
// question is the ID of the question now pending, if any.
Ask string
}
Reaction is how the person reacted.
type Stimulus ¶
type Stimulus struct {
// Kind is KindSay for words, or a game-defined kind such as "event.steal".
Kind string
// From names the sender (a player, a viewer); repeats are counted per sender.
From string
// Text is the words; it may be empty for events.
Text string
// Values are numbers the rules read as value.NAME (a tip, an item's price).
Values map[string]float64
// Tags are tags the game already knows (score 1), declared in Book.Tags.
Tags []string
}
Stimulus is what reaches a person: words, an event, numbers.