use crate::geom::{PointType, new_point};
use crate::traffic_lights::groups::TrafficLightGroup;
use std::fmt;
pub type TrafficLightID = i64;
#[derive(Debug)]
pub enum TrafficLightError {
NotFound,
AlreadyExists,
}
impl fmt::Display for TrafficLightError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TrafficLightError::NotFound => write!(f, "No traffic light was found"),
TrafficLightError::AlreadyExists => write!(f, "Traffic light already exists"),
}
}
}
impl std::error::Error for TrafficLightError {}
#[derive(Debug, Clone)]
pub struct TrafficLight {
groups: Vec<TrafficLightGroup>,
times: Vec<i32>,
coordinates: PointType,
id: TrafficLightID,
timer: i32,
active_phase_idx: usize,
}
impl TrafficLight {
pub fn new(id: TrafficLightID) -> TrafficLightBuilder {
TrafficLightBuilder {
traffic_light: TrafficLight {
groups: Vec::new(),
times: Vec::new(),
coordinates: new_point(-1.0, -1.0, None),
id,
timer: 0,
active_phase_idx: 0,
},
}
}
pub fn get_id(&self) -> TrafficLightID {
self.id
}
pub fn step(&mut self) {
self.timer += 1;
let current_phase = self.active_phase_idx;
if self.timer >= self.times[current_phase] {
self.active_phase_idx = (current_phase + 1) % self.times.len();
self.timer = 0;
}
}
pub fn reset(&mut self) {
self.timer = 0;
self.active_phase_idx = 0;
}
pub fn get_active_phase(&self) -> usize {
self.active_phase_idx
}
pub fn get_current_time(&self) -> i32 {
self.timer
}
pub fn get_groups_num(&self) -> usize {
self.groups.len()
}
pub fn get_groups(&self) -> &Vec<TrafficLightGroup> {
&self.groups
}
pub fn get_coordinates(&self) -> PointType {
self.coordinates
}
}
pub struct TrafficLightBuilder {
traffic_light: TrafficLight,
}
impl TrafficLightBuilder {
pub fn with_coordinates(mut self, point: PointType) -> Self {
self.traffic_light.coordinates = point;
self
}
pub fn with_groups(mut self, groups: Vec<TrafficLightGroup>) -> Self {
self.traffic_light.groups = groups;
self
}
pub fn with_groups_append(mut self, groups: Vec<TrafficLightGroup>) -> Self {
self.traffic_light.groups.extend(groups);
self
}
pub fn with_phases_times(mut self, phases_time: Vec<i32>) -> Self {
self.traffic_light.times = phases_time;
self
}
pub fn with_phases_times_append(mut self, phases_time: Vec<i32>) -> Self {
self.traffic_light.times.extend(phases_time);
self
}
pub fn with_active_phase(mut self, phase_idx: usize) -> Self {
self.traffic_light.active_phase_idx = phase_idx;
self
}
pub fn build(self) -> TrafficLight {
self.traffic_light
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::traffic_lights::signals::SignalType;
#[test]
fn test_traffic_light() {
let groups = vec![
TrafficLightGroup::new(1)
.with_label("Group 1".to_string())
.with_cells_ids(vec![20])
.with_signal(vec![SignalType::Red, SignalType::Yellow, SignalType::Green])
.build(),
TrafficLightGroup::new(2)
.with_label("Group 2".to_string())
.with_cells_ids(vec![16])
.with_signal(vec![SignalType::Green, SignalType::Green, SignalType::Green])
.build(),
TrafficLightGroup::new(3)
.with_label("Group 3".to_string())
.with_cells_ids(vec![11])
.with_signal(vec![SignalType::Red, SignalType::Red, SignalType::Red])
.build(),
TrafficLightGroup::new(4)
.with_label("Group 4".to_string())
.with_cells_ids(vec![18, 20])
.with_signal(vec![SignalType::Red, SignalType::Red, SignalType::Red])
.build(),
];
let mut traffic_light = TrafficLight::new(1)
.with_groups(groups)
.with_phases_times(vec![2, 3, 10])
.with_active_phase(0)
.build();
assert_eq!(traffic_light.get_current_time(), 0);
assert_eq!(traffic_light.get_active_phase(), 0);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 1);
assert_eq!(traffic_light.get_active_phase(), 0);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 0);
assert_eq!(traffic_light.get_active_phase(), 1);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 1);
assert_eq!(traffic_light.get_active_phase(), 1);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 2);
assert_eq!(traffic_light.get_active_phase(), 1);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 0);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 1);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 2);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 3);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 4);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 5);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 6);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 7);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 8);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 9);
assert_eq!(traffic_light.get_active_phase(), 2);
traffic_light.step();
assert_eq!(traffic_light.get_current_time(), 0);
assert_eq!(traffic_light.get_active_phase(), 0);
}
}