traffic_light.ry

module traffic_light
  purpose: A traffic light as a state machine driven by timer and emergency events.

import std.console

public type Light is one of
  purpose: The colour the light shows.
  Red
  Green
  Yellow
  FlashingRed
  can ToText
end

public type Event is one of
  purpose: Something that can change the light.
  TimerExpired
  EmergencyDeclared
  EmergencyCleared
end

public function next_light(current: Light, event: Event) returns Light
  purpose: The light shown after the event; an emergency overrides the normal cycle.
  tags: state-machine, traffic
  example: next_light(current: Red, event: TimerExpired) is Green
  example: next_light(current: Green, event: TimerExpired) is Yellow
  example: next_light(current: Yellow, event: TimerExpired) is Red
  example: next_light(current: Green, event: EmergencyDeclared) is FlashingRed
  example: next_light(current: FlashingRed, event: TimerExpired) is FlashingRed
  example: next_light(current: FlashingRed, event: EmergencyCleared) is Red

  match event
    when EmergencyDeclared then return FlashingRed
    when EmergencyCleared then return Red
    when TimerExpired then
      match current
        when Red then return Green
        when Green then return Yellow
        when Yellow then return Red
        when FlashingRed then return FlashingRed
      end
  end
end

public function run_sequence(start: Light, events: List of Event) returns List of Light
  purpose: Every light shown while the events are applied in order, one entry per event.
  example: run_sequence(start: Red, events: [TimerExpired, TimerExpired]) is [Green, Yellow]
  example: run_sequence(start: Red, events: []) is []

  let mutable current be start
  let mutable shown: List of Light be []
  for each event in events
    change current to next_light(current: current, event: event)
    change shown to shown.append(current)
  end
  return shown
end

public function main() needs console
  purpose: Print the lights of a short sequence with one emergency in the middle.

  let events be [TimerExpired, TimerExpired, EmergencyDeclared, TimerExpired, EmergencyCleared]
  for each light in run_sequence(start: Red, events: events)
    console.print(light.to_text())
  end
end