Traffic

The following example integrates three simulation entities

  • A gas station with a limited number of pumps
  • A traffic light that prevents cars from driving
  • Multiple cars that need to pass the cross with the traffic light to reach a gas station. There each car needs to refill before it is reaching its end of live within the simulation context.

The example illustrates how to establish a simple interplay of states and resources. It is realized elegantly with dependency injection.

////Traffic.kts
import org.kalasim.*
import org.koin.core.component.inject

enum class TrafficLightState { RED, GREEN }

/** A traffic light with 2 states. */
class TrafficLight : State<TrafficLightState>(TrafficLightState.RED) {

    fun toggleState() {
        when(value) {
            TrafficLightState.RED -> TrafficLightState.GREEN
            TrafficLightState.GREEN -> TrafficLightState.RED
        }
    }
}


/** A simple controller that will toggle the state of the traffic-light */
class TrafficLightController(val trafficLight: TrafficLight) : Component() {

    override fun repeatedProcess() = sequence {
        hold(6)
        trafficLight.toggleState()
    }
}

/** A gas station, where cars will stop for refill. */
class GasStation(numPumps: Int = 6) : Resource(capacity = numPumps)

/** A car with a process definition detailing out its way to the gas-station via a crossing. */
class Car(val trafficLight: TrafficLight) : Component() {

    val gasStation by inject<GasStation>()

    override fun process() = sequence {
        // Wait until the traffic light is green
        wait(trafficLight, TrafficLightState.GREEN)

        // Request a slot in the gas-station
        request(gasStation) {
            hold(5, description = "refilling")
        }
    }
}

createSimulation(true) {
    // Add a traffic light so that we can refer to it via koin get<T>()
    dependency { TrafficLight() }

    // Also add a resource with a limited capacity
    dependency { GasStation(2) }

    // Setup a traffic light controller to toggle the light
    TrafficLightController(get())

    // Setup a car generator with an exponentially distributed arrival time
    ComponentGenerator(exponential(7)){ Car(get())}

    // enable component tracking for later analytics
    val cg = componentCollector()

    // Run for 30 ticks
    run(10)

    // Toggle the traffic light manually
    get<TrafficLight>().value = TrafficLightState.GREEN

    // Run for another 10 ticks
    run(10)

    // Assess the state of the simulation entities
    cg.filterIsInstance<Car>().first().statusTimeline.printHistogram()
    get<GasStation>().printStatistics()
}

Here, we use both lazy injection with inject<T>() and instance retrieval with get<T>(). For details see koin reference