use crate::distance::*;
use crate::gradient::*;
use crate::mesh::*;
pub fn best_for_indexes(mesh: &impl Mesh, indexes: &[usize]) -> Option<usize> {
if mesh.is_empty() || indexes.is_empty() {
return None;
}
let len = mesh.len();
let mut gradients: Vec<Gradient> = Vec::with_capacity(indexes.len());
for &idx in indexes {
let mut gradient = Gradient::from_mesh(mesh);
gradient.set_distance(idx, 0.0);
gradient.spread(mesh);
gradients.push(gradient);
}
let mut best_index: Option<usize> = None;
let mut best_sum = f32::MAX;
for cell in 0..len {
let mut sum_squared: f32 = 0.0;
let mut all_reachable = true;
for gradient in &gradients {
let dist = gradient.get_distance(cell);
if dist >= DISTANCE_MAX {
all_reachable = false;
break;
}
sum_squared += dist * dist;
}
if all_reachable && sum_squared < best_sum {
best_sum = sum_squared;
best_index = Some(cell);
}
}
best_index
}
pub fn worst_for_indexes(mesh: &impl Mesh, indexes: &[usize]) -> Option<usize> {
if mesh.is_empty() || indexes.is_empty() {
return None;
}
let len = mesh.len();
let mut gradients: Vec<Gradient> = Vec::with_capacity(indexes.len());
for &idx in indexes {
let mut gradient = Gradient::from_mesh(mesh);
gradient.set_distance(idx, 0.0);
gradient.spread(mesh);
gradients.push(gradient);
}
let mut worst_index: Option<usize> = None;
let mut worst_sum = f32::MIN;
for cell in 0..len {
let mut sum_squared: f32 = 0.0;
let mut all_reachable = true;
for gradient in &gradients {
let dist = gradient.get_distance(cell);
if dist >= DISTANCE_MAX {
all_reachable = false;
break;
}
sum_squared += dist * dist;
}
if all_reachable && sum_squared > worst_sum {
worst_sum = sum_squared;
worst_index = Some(cell);
}
}
worst_index
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mesh_2d::*;
#[test]
fn test_best_for_indexes_center() {
let rect = Full2D::new(5, 5);
let corners = vec![0, 4, 20, 24];
let best = best_for_indexes(&rect, &corners);
assert_eq!(best, Some(12), "Center should minimize distance to corners");
}
#[test]
fn test_best_for_indexes_single() {
let rect = Full2D::new(5, 5);
let single = vec![7];
let best = best_for_indexes(&rect, &single);
assert_eq!(best, Some(7), "Best should be the target itself");
}
#[test]
fn test_best_for_indexes_empty() {
let rect = Full2D::new(5, 5);
let empty_mesh = Full2D::new(0, 0);
assert_eq!(best_for_indexes(&empty_mesh, &[0]), None);
assert_eq!(best_for_indexes(&rect, &[]), None);
}
#[test]
fn test_worst_for_indexes_from_center() {
let rect = Full2D::new(5, 5);
let center = vec![12];
let worst = worst_for_indexes(&rect, ¢er);
assert!(
worst == Some(0) || worst == Some(4) || worst == Some(20) || worst == Some(24),
"Worst should be a corner, got {:?}",
worst
);
}
#[test]
fn test_worst_for_indexes_from_corners() {
let rect = Full2D::new(5, 5);
let corners = vec![0, 4, 20, 24];
let worst = worst_for_indexes(&rect, &corners);
assert!(worst.is_some(), "Should find a worst index");
assert_ne!(worst, Some(12), "Center should not be the worst");
}
#[test]
fn test_worst_for_indexes_single() {
let rect = Full2D::new(5, 5);
let corner = vec![0];
let worst = worst_for_indexes(&rect, &corner);
assert_eq!(worst, Some(24), "Opposite corner should be furthest");
}
#[test]
fn test_worst_for_indexes_empty() {
let rect = Full2D::new(5, 5);
let empty_mesh = Full2D::new(0, 0);
assert_eq!(worst_for_indexes(&empty_mesh, &[0]), None);
assert_eq!(worst_for_indexes(&rect, &[]), None);
}
#[test]
fn test_best_worst_with_walls() {
let map = "\
.....
.###.
.....";
let mesh = Compact2D::from_text(map).unwrap();
let corners: Vec<usize> = vec![
mesh.xy_to_index(0, 0).unwrap(),
mesh.xy_to_index(4, 0).unwrap(),
mesh.xy_to_index(0, 2).unwrap(),
mesh.xy_to_index(4, 2).unwrap(),
];
let best = best_for_indexes(&mesh, &corners);
assert!(best.is_some(), "Should find a best index even with walls");
let worst = worst_for_indexes(&mesh, &corners);
assert!(worst.is_some(), "Should find a worst index even with walls");
}
}