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 }