#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FreeSpaceScore {
pub score: f64,
pub lvn_width_atr: f64,
pub distance_to_hvn_atr: f64,
pub volume_density: f64,
}
pub fn build_free_space_score(
lvn_width_atr: f64,
distance_to_hvn_atr: f64,
volume_density: f64,
) -> FreeSpaceScore {
let density_component = (1.0 - volume_density.clamp(0.0, 1.0)) * 40.0;
let width_component = lvn_width_atr.clamp(0.0, 3.0) / 3.0 * 30.0;
let distance_component = distance_to_hvn_atr.clamp(0.0, 3.0) / 3.0 * 30.0;
let score = (density_component + width_component + distance_component).clamp(0.0, 100.0);
FreeSpaceScore {
score,
lvn_width_atr,
distance_to_hvn_atr,
volume_density,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn thin_wide_far_book_scores_high() {
let out = build_free_space_score(3.0, 3.0, 0.0);
assert!((out.score - 100.0).abs() < 1e-9);
}
#[test]
fn dense_narrow_close_book_scores_low() {
let out = build_free_space_score(0.0, 0.0, 1.0);
assert!(out.score.abs() < 1e-9);
}
}