Skip to content

Commit 8e857e8

Browse files
add implementation of Nagel and Schrekenberg algo (TheAlgorithms#5584)
* add implementation of Nagel and Schrekenberg algo * Update cellular_automata/nasch.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update nasch.py * Update and rename nasch.py to nagel_schrekenberg.py * Update cellular_automata/nagel_schrekenberg.py Co-authored-by: Christian Clauss <cclauss@me.com> * Update nagel_schrekenberg.py * Update nagel_schrekenberg.py * Update nagel_schrekenberg.py * update nagel_schrekenberg.py * Update nagel_schrekenberg.py Co-authored-by: Christian Clauss <cclauss@me.com>
1 parent 716beb3 commit 8e857e8

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
"""
2+
Simulate the evolution of a highway with only one road that is a loop.
3+
The highway is divided in cells, each cell can have at most one car in it.
4+
The highway is a loop so when a car comes to one end, it will come out on the other.
5+
Each car is represented by its speed (from 0 to 5).
6+
7+
Some information about speed:
8+
-1 means that the cell on the highway is empty
9+
0 to 5 are the speed of the cars with 0 being the lowest and 5 the highest
10+
11+
highway: list[int] Where every position and speed of every car will be stored
12+
probability The probability that a driver will slow down
13+
initial_speed The speed of the cars a the start
14+
frequency How many cells there are between two cars at the start
15+
max_speed The maximum speed a car can go to
16+
number_of_cells How many cell are there in the highway
17+
number_of_update How many times will the position be updated
18+
19+
More information here: https://en.wikipedia.org/wiki/Nagel%E2%80%93Schreckenberg_model
20+
21+
Examples for doctest:
22+
>>> simulate(construct_highway(6, 3, 0), 2, 0, 2)
23+
[[0, -1, -1, 0, -1, -1], [-1, 1, -1, -1, 1, -1], [-1, -1, 1, -1, -1, 1]]
24+
>>> simulate(construct_highway(5, 2, -2), 3, 0, 2)
25+
[[0, -1, 0, -1, 0], [0, -1, 0, -1, -1], [0, -1, -1, 1, -1], [-1, 1, -1, 0, -1]]
26+
"""
27+
from random import randint, random
28+
29+
30+
def construct_highway(
31+
number_of_cells: int,
32+
frequency: int,
33+
initial_speed: int,
34+
random_frequency: bool = False,
35+
random_speed: bool = False,
36+
max_speed: int = 5,
37+
) -> list:
38+
"""
39+
Build the highway following the parameters given
40+
>>> construct_highway(10, 2, 6)
41+
[[6, -1, 6, -1, 6, -1, 6, -1, 6, -1]]
42+
>>> construct_highway(10, 10, 2)
43+
[[2, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
44+
"""
45+
46+
highway = [[-1] * number_of_cells] # Create a highway without any car
47+
i = 0
48+
if initial_speed < 0:
49+
initial_speed = 0
50+
while i < number_of_cells:
51+
highway[0][i] = (
52+
randint(0, max_speed) if random_speed else initial_speed
53+
) # Place the cars
54+
i += (
55+
randint(1, max_speed * 2) if random_frequency else frequency
56+
) # Arbitrary number, may need tuning
57+
return highway
58+
59+
60+
def get_distance(highway_now: list, car_index: int) -> int:
61+
"""
62+
Get the distance between a car (at index car_index) and the next car
63+
>>> get_distance([6, -1, 6, -1, 6], 2)
64+
1
65+
>>> get_distance([2, -1, -1, -1, 3, 1, 0, 1, 3, 2], 0)
66+
3
67+
>>> get_distance([-1, -1, -1, -1, 2, -1, -1, -1, 3], -1)
68+
4
69+
"""
70+
71+
distance = 0
72+
cells = highway_now[car_index + 1 :]
73+
for cell in range(len(cells)): # May need a better name for this
74+
if cells[cell] != -1: # If the cell is not empty then
75+
return distance # we have the distance we wanted
76+
distance += 1
77+
# Here if the car is near the end of the highway
78+
return distance + get_distance(highway_now, -1)
79+
80+
81+
def update(highway_now: list, probability: float, max_speed: int) -> list:
82+
"""
83+
Update the speed of the cars
84+
>>> update([-1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3], 0.0, 5)
85+
[-1, -1, -1, -1, -1, 3, -1, -1, -1, -1, 4]
86+
>>> update([-1, -1, 2, -1, -1, -1, -1, 3], 0.0, 5)
87+
[-1, -1, 3, -1, -1, -1, -1, 1]
88+
"""
89+
90+
number_of_cells = len(highway_now)
91+
# Beforce calculations, the highway is empty
92+
next_highway = [-1] * number_of_cells
93+
94+
for car_index in range(number_of_cells):
95+
if highway_now[car_index] != -1:
96+
# Add 1 to the current speed of the car and cap the speed
97+
next_highway[car_index] = min(highway_now[car_index] + 1, max_speed)
98+
# Number of empty cell before the next car
99+
dn = get_distance(highway_now, car_index) - 1
100+
# We can't have the car causing an accident
101+
next_highway[car_index] = min(next_highway[car_index], dn)
102+
if random() < probability:
103+
# Randomly, a driver will slow down
104+
next_highway[car_index] = max(next_highway[car_index] - 1, 0)
105+
return next_highway
106+
107+
108+
def simulate(
109+
highway: list, number_of_update: int, probability: float, max_speed: int
110+
) -> list:
111+
"""
112+
The main function, it will simulate the evolution of the highway
113+
>>> simulate([[-1, 2, -1, -1, -1, 3]], 2, 0.0, 3)
114+
[[-1, 2, -1, -1, -1, 3], [-1, -1, -1, 2, -1, 0], [1, -1, -1, 0, -1, -1]]
115+
>>> simulate([[-1, 2, -1, 3]], 4, 0.0, 3)
116+
[[-1, 2, -1, 3], [-1, 0, -1, 0], [-1, 0, -1, 0], [-1, 0, -1, 0], [-1, 0, -1, 0]]
117+
"""
118+
119+
number_of_cells = len(highway[0])
120+
121+
for i in range(number_of_update):
122+
next_speeds_calculated = update(highway[i], probability, max_speed)
123+
real_next_speeds = [-1] * number_of_cells
124+
125+
for car_index in range(number_of_cells):
126+
speed = next_speeds_calculated[car_index]
127+
if speed != -1:
128+
# Change the position based on the speed (with % to create the loop)
129+
index = (car_index + speed) % number_of_cells
130+
# Commit the change of position
131+
real_next_speeds[index] = speed
132+
highway.append(real_next_speeds)
133+
134+
return highway
135+
136+
137+
if __name__ == "__main__":
138+
import doctest
139+
140+
doctest.testmod()

0 commit comments

Comments
 (0)