1use crate::{LinkId, TrafficControl};
2use serde::{Deserialize, Serialize};
3use std::cell::Cell;
4
5#[derive(Serialize, Deserialize, Clone, Default)]
7pub struct TrafficLight {
8 movements: Vec<Movement>,
10 links: Vec<(u8, LinkId)>,
12 conflicts: Vec<Conflict>,
14 phases: Vec<Phase>,
16 phase: usize,
18}
19
20#[derive(Serialize, Deserialize, Clone, Debug)]
22struct Movement {
23 state: LightState,
25 next_state: Cell<LightState>,
27 active: bool,
29 since: f64,
31 amber_time: f64,
33}
34
35#[derive(Serialize, Deserialize, Clone, Copy)]
37struct Conflict {
38 subject: usize,
40 other: usize,
42 wait: f64,
45}
46
47#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Debug)]
49pub enum LightState {
50 Red,
51 Amber,
52 Green,
53}
54
55#[derive(Serialize, Deserialize, Clone, Copy)]
57pub struct Phase {
58 mask: u64,
60 duration: f64,
62}
63
64impl TrafficLight {
65 pub fn new() -> Self {
67 Default::default()
68 }
69
70 pub fn add_movement(&mut self, amber_time: f64, links: impl Iterator<Item = LinkId>) {
77 let idx = self.movements.len() as u8;
78 self.movements.push(Movement {
79 state: LightState::Red,
80 next_state: Cell::new(LightState::Red),
81 active: false,
82 since: 0.0,
83 amber_time,
84 });
85 self.links.extend(links.map(|link| (idx, link)));
86 }
87
88 pub fn add_conflict(&mut self, subject: usize, other: usize, wait: f64) {
90 self.conflicts.push(Conflict {
91 subject,
92 other,
93 wait,
94 });
95 }
96
97 pub fn add_phase(&mut self, mask: u64, duration: f64) {
99 self.phases.push(Phase { mask, duration });
100 }
101
102 pub fn step(&mut self, dt: f64) {
104 self.update_phase();
105 self.apply_phase();
106
107 for (idx, movement) in self.movements.iter().enumerate() {
109 use LightState::*;
110 let next = match (movement.active, movement.state) {
111 (false, Green) => Amber,
112 (false, Amber) if movement.since >= movement.amber_time => Red,
113 (true, Amber) => Green,
114 (true, Red) if self.can_turn_green(idx) => Green,
115 (_, state) => state,
116 };
117 movement.next_state.set(next);
118 }
119
120 for movement in &mut self.movements {
122 movement.step(dt);
123 }
124 }
125
126 fn update_phase(&mut self) {
128 if self.phases.is_empty() {
129 return;
130 }
131
132 let Phase { duration, mask } = self.phases[self.phase];
133 let phase_complete = self
134 .movements
135 .iter()
136 .enumerate()
137 .filter(|(index, _)| mask & (1 << index) != 0)
138 .all(|(_, m)| m.state == LightState::Green && m.since >= duration);
139
140 if phase_complete {
141 self.phase = (self.phase + 1) % self.phases.len();
142 }
143 }
144
145 fn apply_phase(&mut self) {
147 let Phase { mask, .. } = self.phases[self.phase];
148 for (idx, movement) in self.movements.iter_mut().enumerate() {
149 movement.active = (mask >> idx) & 1 != 0;
150 }
151 }
152
153 pub fn get_states(&self) -> impl Iterator<Item = (LinkId, TrafficControl)> + '_ {
155 self.links.iter().map(|(idx, link)| {
156 let control = match self.movements[*idx as usize].state {
157 LightState::Red => TrafficControl::Closed,
158 LightState::Amber => TrafficControl::Closed,
159 LightState::Green => TrafficControl::Open,
160 };
161 (*link, control)
162 })
163 }
164
165 fn can_turn_green(&self, movement: usize) -> bool {
167 self.conflicts
168 .iter()
169 .filter(|conflict| conflict.subject == movement)
170 .all(|conflict| {
171 let movement = &self.movements[conflict.other];
172 movement.state == LightState::Red && movement.since >= conflict.wait
173 })
174 }
175}
176
177impl Movement {
178 fn step(&mut self, dt: f64) {
179 if self.next_state.get() != self.state {
180 self.state = self.next_state.get();
181 self.since = dt;
182 } else {
183 self.since += dt;
184 }
185 }
186}