use crate::algo::EdgesVec; use std::collections::HashSet; use std::ops::Mul; #[derive(Clone, Copy)] pub enum AntDirection { ToSecond, ToFirst, } pub struct Ant { allowed_vertices: HashSet, location: AntLocation, } pub enum AntLocation { OnEdge { edge_index: usize, offset: u16, direction: AntDirection, }, OnVertex { vertex_index: usize, }, } pub struct AntsSimulationState<'a, Rng: rand::Rng> { rng: Rng, vertices: &'a Vec>, edges: &'a mut EdgesVec, ants: &'a mut [Ant], } pub fn updateState( state: &mut AntsSimulationState, ferment_weight: f64, heuristic_coefficient: f64, q: f64, r: f64, speed: u16, ) -> bool { let mut finished_ants_count = 0usize; for ant in state.ants.iter_mut() { match &mut ant.location { AntLocation::OnEdge { edge_index, offset, direction, } => match offset.checked_add(speed) { Some(newOffset) => *offset = newOffset, None => { let edge = &mut state.edges[*edge_index]; edge.ferment_intensity += (q / edge.length) * r; let vertex_index; match direction { AntDirection::ToSecond => vertex_index = edge.vertex2_index, AntDirection::ToFirst => vertex_index = edge.vertex1_index, } ant.location = AntLocation::OnVertex { vertex_index } } }, AntLocation::OnVertex { vertex_index } => { let allowed_outbounds = state.vertices[*vertex_index] .iter() .map(|ei| (*ei, &state.edges[*ei])) .map(|(ei, e)| { if *vertex_index == e.vertex1_index { return (ei, e, e.vertex2_index, AntDirection::ToSecond); } else { return (ei, e, e.vertex1_index, AntDirection::ToFirst); } }) .filter(|e| ant.allowed_vertices.contains(&e.2)) .map(|e| { return ( e.0, (e.2, e.3), e.1.ferment_intensity.powf(ferment_weight) * (1.0 / e.1.length).powf(heuristic_coefficient), ); }) .collect::>(); let mut accumulator: f64 = allowed_outbounds .iter() .fold(0.0, |a, e| a + e.2) .mul(state.rng.random::()); let target_vertex_index = allowed_outbounds.iter().find(|e| { accumulator -= e.2; return accumulator <= 0.0; }); match target_vertex_index { None => finished_ants_count += 1, Some((ei, (vi, dir), _)) => { ant.allowed_vertices.remove(vi); ant.location = AntLocation::OnEdge { edge_index: *ei, offset: 0, direction: *dir } } }; } } } return finished_ants_count == state.ants.len() }