"""
Simulate the evolution of a highway with only one road that is a loop.
The highway is divided in cells, each cell can have at most one car in it.
The highway is a loop so when a car comes to one end, it will come out on the other.
Each car is represented by its speed (from 0 to 5).
Some information about speed:
-1 means that the cell on the highway is empty
0 to 5 are the speed of the cars with 0 being the lowest and 5 the highest
highway: list[int] Where every position and speed of every car will be stored
probability The probability that a driver will slow down
initial_speed The speed of the cars a the start
frequency How many cells there are between two cars at the start
max_speed The maximum speed a car can go to
number_of_cells How many cell are there in the highway
number_of_update How many times will the position be updated
More information here: https://en.wikipedia.org/wiki/Nagel%E2%80%93Schreckenberg_model
Examples for doctest:
>>> simulate(construct_highway(6, 3, 0), 2, 0, 2)
[[0, -1, -1, 0, -1, -1], [-1, 1, -1, -1, 1, -1], [-1, -1, 1, -1, -1, 1]]
>>> simulate(construct_highway(5, 2, -2), 3, 0, 2)
[[0, -1, 0, -1, 0], [0, -1, 0, -1, -1], [0, -1, -1, 1, -1], [-1, 1, -1, 0, -1]]
"""
from random import randint, random
def construct_highway(
number_of_cells: int,
frequency: int,
initial_speed: int,
random_frequency: bool = False,
random_speed: bool = False,
max_speed: int = 5,
) -> list:
"""
Build the highway following the parameters given
>>> construct_highway(10, 2, 6)
[[6, -1, 6, -1, 6, -1, 6, -1, 6, -1]]
>>> construct_highway(10, 10, 2)
[[2, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
"""
highway = [[-1] * number_of_cells]
i = 0
if initial_speed < 0:
initial_speed = 0
while i < number_of_cells:
highway[0][i] = (
randint(0, max_speed) if random_speed else initial_speed
)
i += (
randint(1, max_speed * 2) if random_frequency else frequency
)
return highway
def get_distance(highway_now: list, car_index: int) -> int:
"""
Get the distance between a car (at index car_index) and the next car
>>> get_distance([6, -1, 6, -1, 6], 2)
1
>>> get_distance([2, -1, -1, -1, 3, 1, 0, 1, 3, 2], 0)
3
>>> get_distance([-1, -1, -1, -1, 2, -1, -1, -1, 3], -1)
4
"""
distance = 0
cells = highway_now[car_index + 1 :]
for cell in range(len(cells)):
if cells[cell] != -1:
return distance
distance += 1
return distance + get_distance(highway_now, -1)
def update(highway_now: list, probability: float, max_speed: int) -> list:
"""
Update the speed of the cars
>>> update([-1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3], 0.0, 5)
[-1, -1, -1, -1, -1, 3, -1, -1, -1, -1, 4]
>>> update([-1, -1, 2, -1, -1, -1, -1, 3], 0.0, 5)
[-1, -1, 3, -1, -1, -1, -1, 1]
"""
number_of_cells = len(highway_now)
next_highway = [-1] * number_of_cells
for car_index in range(number_of_cells):
if highway_now[car_index] != -1:
next_highway[car_index] = min(highway_now[car_index] + 1, max_speed)
dn = get_distance(highway_now, car_index) - 1
next_highway[car_index] = min(next_highway[car_index], dn)
if random() < probability:
next_highway[car_index] = max(next_highway[car_index] - 1, 0)
return next_highway
def simulate(
highway: list, number_of_update: int, probability: float, max_speed: int
) -> list:
"""
The main function, it will simulate the evolution of the highway
>>> simulate([[-1, 2, -1, -1, -1, 3]], 2, 0.0, 3)
[[-1, 2, -1, -1, -1, 3], [-1, -1, -1, 2, -1, 0], [1, -1, -1, 0, -1, -1]]
>>> simulate([[-1, 2, -1, 3]], 4, 0.0, 3)
[[-1, 2, -1, 3], [-1, 0, -1, 0], [-1, 0, -1, 0], [-1, 0, -1, 0], [-1, 0, -1, 0]]
"""
number_of_cells = len(highway[0])
for i in range(number_of_update):
next_speeds_calculated = update(highway[i], probability, max_speed)
real_next_speeds = [-1] * number_of_cells
for car_index in range(number_of_cells):
speed = next_speeds_calculated[car_index]
if speed != -1:
index = (car_index + speed) % number_of_cells
real_next_speeds[index] = speed
highway.append(real_next_speeds)
return highway
if __name__ == "__main__":
import doctest
doctest.testmod()