protohackers/problem_06/src/ticketing.rs

95 lines
2.3 KiB
Rust

use tracing::debug;
use crate::db::{CameraId, Db, Plate, Road, Ticket};
pub(crate) async fn issue_possible_ticket(db: &mut Db, plate: Plate, camera_id: CameraId) {
debug!("Issue possible ticket");
let camera = db.get_camera(camera_id.clone()).unwrap();
let observed_plates = db.get_plates_by_road(plate.clone(), camera.road.clone());
if observed_plates.is_none() {
debug!("No observed plates");
db.add_plate(camera_id, plate);
return;
}
debug!(?observed_plates, "Observed plates");
let mile = camera.mile;
let limit = camera.limit;
let road = camera.road;
let plate_name = plate.clone().plate;
let timestamp = plate.clone().timestamp;
debug!(
?plate_name,
?timestamp,
?mile,
?limit,
?road,
"Checking plate"
);
for (m, t) in observed_plates.unwrap().iter() {
let distance = if mile > *m {
mile.0 - m.0
} else {
m.0 - mile.0
};
let (time, mile1, timestamp1, mile2, timestamp2) = if timestamp > *t {
(timestamp.0 - t.0, m.0, t.0, mile.0, timestamp.0)
} else {
(t.0 - timestamp.0, mile.0, timestamp.0, m.0, t.0)
};
let speed = (distance as u64 * 3600 * 100 / time as u64) as u16;
debug!(?distance, ?time, ?speed, "Checking speed");
if speed > limit.0 * 100 {
let ticket = Ticket {
plate: plate_name.clone().0,
road: road.0,
mile1,
timestamp1,
mile2,
timestamp2,
speed,
};
let day_start = timestamp1 / 86400;
let day_end = timestamp2 / 86400;
for day in day_start..=day_end {
if db.is_plate_ticketed_for_day(day, plate_name.clone()) {
debug!(?ticket, "Ticket already issued");
continue;
}
let dispatcher = db.get_dispatcher_for_road(road.clone());
if dispatcher.is_none() {
debug!(?ticket, "No dispatcher for road");
db.add_open_ticket(ticket.clone());
continue;
}
debug!(?ticket, "Sending ticket");
let _ = dispatcher.unwrap().send(ticket.clone().into()).await;
db.ticket_plate(day, plate_name.clone());
}
}
}
db.add_plate(camera_id, plate);
}
pub(crate) async fn send_out_waiting_tickets(db: Db) {
let tickets = db.get_open_tickets();
debug!(?tickets, "Sending out waiting tickets");
for ticket in tickets {
if let Some(dispatcher) = db.get_dispatcher_for_road(Road(ticket.road)) {
let _ = dispatcher.send(ticket.clone().into()).await;
db.remove_open_ticket(Road(ticket.road), ticket);
}
}
}