package westworldwithmessaging import ( "fmt" "sync" ) // cookStew is the Go version of the (not yet pasted) singleton class // CookStew from the book. Same pattern as every other state: // unexported type, one shared instance, reached only through the // function below. type cookStew struct{} var ( cookStewInstance *cookStew cookStewOnce sync.Once ) // CookStew is the Go stand-in for "CookStew::Instance()". func CookStew() *cookStew { cookStewOnce.Do(func() { cookStewInstance = &cookStew{} }) return cookStewInstance } var _ State[Elsa] = (*cookStew)(nil) // Execute and Exit weren't pasted to us directly either, but a // sample run of the book's program makes their behavior clear // enough to fill in: Execute prints "Fussin' over food" once per // tick while the stew is in the oven (waiting for the delayed // Msg_StewReady reminder to arrive), and Exit announces taking the // stew out and putting it on the table, right before switching back // to DoHousework. // Enter puts the stew in the oven (if one isn't already cooking) and // sends a delayed message to herself, reminding her to take it out // once it's ready. func (s *cookStew) Enter(e *Elsa) { if !e.Cooking() { fmt.Printf("\n%s: Puttin' the stew in the oven", GetNameOfEntity(e.ID())) // send a delayed message to myself so that I know when to take // the stew out of the oven Dispatch.DispatchMessage( 1.5, // time delay e.ID(), // sender ID e.ID(), // receiver ID int(MsgStewReady), // the message NoAdditionalInfo, // no extra info attached ) e.SetCooking(true) } } func (s *cookStew) Execute(e *Elsa) { fmt.Printf("\n%s: Fussin' over food", GetNameOfEntity(e.ID())) } func (s *cookStew) Exit(e *Elsa) { fmt.Printf("\n%s: Puttin' the stew on the table", GetNameOfEntity(e.ID())) } // OnMessage handles the delayed reminder Enter sent to herself: once // the stew's ready, take it out, let Bob know dinner's on the table, // and go back to the ordinary housework state. func (s *cookStew) OnMessage(e *Elsa, msg Telegram) bool { switch MessageType(msg.Msg) { case MsgStewReady: fmt.Printf("\nMessage received by %s at time: %.5f", GetNameOfEntity(e.ID()), Clock.GetCurrentTime()) fmt.Printf("\n%s: Stew ready! Let's eat", GetNameOfEntity(e.ID())) // let hubby know the stew is ready Dispatch.DispatchMessage( SendMsgImmediately, e.ID(), entMinerBob, int(MsgStewReady), NoAdditionalInfo, ) e.SetCooking(false) e.FSM().ChangeState(DoHousework()) return true } return false }