Last updated on

hotpotato Example

This example demonstrates how to use the ClockDrivenStateMachine provided by the library. It enables you to simulate a continuous, time-based game instead of relying solely on discrete player actions.

In the hotpotato game, a player starts holding a potato. The longer they keep it, the more points they earn. However, after a random amount of time, the potato will explode, turning into rösti. The player holding the potato at that moment loses a significant number of points.

ClockDrivenStateMachine

To use the clock, your Logic class needs to extend ClockDrivenStateMachine

class Logic extends ClockDrivenStateMachine[Event, State, View]:

apps/jvm/src/main/scala/apps/hotpotato/Logic.scala

This requires defining two fields:

override val clockPeriodMs: Int = 100 // How frequently we want to receive the clock tick events in ms
override val clockDrivenWire: AppWire[Event, View] = hotpotato.Wire // The wire of our app

apps/jvm/src/main/scala/apps/hotpotato/Logic.scala

Your transition function will now take an event of type Either[Tick, Event], instead of Event. This will allow you to handle the Tick events as well as your regular events.

override def transition(state: State)(
    userId: UserId,
    event: Either[Tick, Event]
): Try[Seq[Action[State]]] =

apps/jvm/src/main/scala/apps/hotpotato/Logic.scala

For example, in our transition function, we separately handle cases where a Tick or an Event is received.

event match
  case Left(Tick(_)) =>
    if timer - clockPeriodMs <= 0 then
      goToNextRound(state, holder)
    else
      Seq(Render(state.copy(
        scores = state.scores.updatedWith(holder)(prevScore => Some(prevScore.get + 1)),
        phase = Phase.Playing(holder, timer - clockPeriodMs)
      )))
  case Right(Event.Pass) =>
    if holder == userId then
      val players = state.scores.keys.toList.sorted
      Seq(Render(state.copy(
        phase = Phase.Playing(holder = pickNextPlayer(players, holder), timer = timer)
      )))
    else Seq()

apps/jvm/src/main/scala/apps/hotpotato/Logic.scala

Pictures

This example also includes a picture. If you want to use any kind of picture file, you can wrap it in a img element. You need to put all your images in the apps/jvm/src/main/resources/www/static directory, similar to thumbnails.

Then the src attribute of the img element needs to be /static/<my_image>

img(
  src := "/static/rosti.png",
  alt := "Rosti!",
  cls := "rosti-image"
)

apps/js/src/main/scala/apps/hotpotato/UI.scala