Files
Programming-Game-AI-by-Exam…/chapter-2-state-driven-agent-design/westworldwithmessaging/state_wifes_global_state.go
T
2026-09-03 23:39:25 +02:00

69 lines
2.3 KiB
Go

package westworldwithmessaging
import (
"fmt"
"math/rand"
"sync"
)
// wifesGlobalState is Elsa's global state - its Execute runs on
// every single tick of her state machine, in addition to whatever
// her current state is doing (see StateMachine.Update). That's what
// makes it the right place for "does nature call right now" logic:
// the book says that can happen "during any state and at any time,"
// which is exactly what a global state is for.
type wifesGlobalState struct{}
var (
wifesGlobalStateInstance *wifesGlobalState
wifesGlobalStateOnce sync.Once
)
// WifesGlobalState is the Go stand-in for
// "WifesGlobalState::Instance()".
func WifesGlobalState() *wifesGlobalState {
wifesGlobalStateOnce.Do(func() {
wifesGlobalStateInstance = &wifesGlobalState{}
})
return wifesGlobalStateInstance
}
var _ State[Elsa] = (*wifesGlobalState)(nil)
// Enter and Exit do nothing - a global state is set once, in
// NewElsa, and never changed, so these never actually get called.
// They only exist to satisfy the State[Elsa] interface.
func (s *wifesGlobalState) Enter(e *Elsa) {}
func (s *wifesGlobalState) Exit(e *Elsa) {}
// bathroomCallChance is a 1-in-N chance, per the chapter's "1 in 10
// chance to change to VisitBathroom state."
const bathroomCallChance = 10
// Execute rolls the dice every tick. If it comes up, and Elsa isn't
// already in the bathroom (checked with IsInState, so this can't
// interrupt a bathroom trip that's already happening), she breaks
// off into VisitBathroom.
func (s *wifesGlobalState) Execute(e *Elsa) {
if !e.FSM().IsInState(VisitBathroom()) && rand.Intn(bathroomCallChance) == 0 {
e.ChangeState(VisitBathroom())
}
}
// OnMessage handles messages that should get through no matter what
// Elsa is currently doing - the book puts Msg_HiHoneyImHome here
// specifically because she should react to it "when in any state,"
// same reasoning as why the bathroom-call check above lives in the
// global state rather than in DoHousework.
func (s *wifesGlobalState) OnMessage(e *Elsa, msg Telegram) bool {
switch MessageType(msg.Msg) {
case MsgHiHoneyImHome:
fmt.Printf("\nMessage handled by %s at time: %.5f", GetNameOfEntity(e.ID()), Clock.GetCurrentTime())
fmt.Printf("\n%s: Hi honey. Let me make you some of mah fine country stew", GetNameOfEntity(e.ID()))
e.FSM().ChangeState(CookStew())
return true
}
return false
}