Use maps to track workload progress instead of recalculating them at every step of the search, calculate total days/slots once, add integration tests, add log folder

This commit is contained in:
2026-01-17 18:41:43 +02:00
parent 908f114e54
commit 5bad63e8a7
10 changed files with 819 additions and 574 deletions

View File

@@ -8,7 +8,7 @@ use crate::{
const YEAR: i32 = 2026;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ToxicPair((ResidentId, ResidentId));
impl ToxicPair {
@@ -42,28 +42,47 @@ pub struct UserConfigDTO {
toxic_pairs: Vec<(String, String)>,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct UserConfig {
pub month: Month,
pub year: i32,
pub holidays: Vec<usize>,
pub residents: Vec<Resident>,
pub toxic_pairs: Vec<ToxicPair>,
pub total_days: u8,
pub total_slots: u8,
pub total_holiday_slots: u8,
}
impl UserConfig {
pub fn new(month: usize) -> Self {
pub fn new(month: u8) -> Self {
let month = Month::try_from(month).unwrap();
let total_days = month.num_days(YEAR).unwrap();
let total_slots = (1..=total_days)
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
let total_holiday_slots = (1..=total_days)
.filter(|&d| Day(d).is_weekend(month.number_from_month(), YEAR))
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
Self {
month: Month::try_from(month as u8).unwrap(),
month,
year: YEAR,
holidays: vec![],
residents: vec![],
toxic_pairs: vec![],
total_days,
total_slots,
total_holiday_slots,
}
}
pub fn with_holidays(mut self, holidays: Vec<usize>) -> Self {
self.holidays = holidays;
self.total_holiday_slots = self.total_holiday_slots();
self
}
@@ -81,18 +100,8 @@ impl UserConfig {
self
}
pub fn total_days(&self) -> u8 {
self.month.num_days(self.year).unwrap()
}
pub fn total_slots(&self) -> u8 {
(1..=self.total_days())
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum()
}
pub fn total_holiday_slots(&self) -> u8 {
(1..=self.total_days())
fn total_holiday_slots(&self) -> u8 {
(1..=self.total_days)
.filter(|&d| self.is_holiday_or_weekend_slot(d))
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum()
@@ -107,20 +116,52 @@ impl UserConfig {
impl Default for UserConfig {
fn default() -> Self {
let month = Month::try_from(2).unwrap();
let total_days = month.num_days(YEAR).unwrap();
let total_slots = (1..=total_days)
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
let total_holiday_slots = (1..=total_days)
.filter(|&d| Day(d).is_weekend(month.number_from_month(), YEAR))
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
Self {
month: Month::try_from(2).unwrap(),
month,
year: YEAR,
holidays: vec![],
residents: vec![],
toxic_pairs: vec![],
total_days,
total_slots,
total_holiday_slots,
}
}
}
impl From<UserConfigDTO> for UserConfig {
fn from(value: UserConfigDTO) -> Self {
let month = Month::try_from(value.month as u8).unwrap();
let total_days = month.num_days(YEAR).unwrap();
let total_slots = (1..=total_days)
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
let total_holiday_slots = (1..=total_days)
.filter(|&d| {
Day(d).is_weekend(month.number_from_month(), value.year)
|| value.holidays.contains(&(d as usize))
})
.map(|d| if Day(d).is_open_shift() { 2 } else { 1 })
.sum();
Self {
month: Month::try_from(value.month as u8).unwrap(),
month,
year: value.year,
holidays: value.holidays,
residents: value.residents.into_iter().map(Resident::from).collect(),
@@ -129,32 +170,9 @@ impl From<UserConfigDTO> for UserConfig {
.into_iter()
.map(|p| ToxicPair::new(&p.0, &p.1))
.collect(),
total_days,
total_slots,
total_holiday_slots,
}
}
}
#[cfg(test)]
mod tests {
use rstest::{fixture, rstest};
use crate::{config::UserConfig, resident::Resident, schedule::MonthlySchedule};
#[fixture]
fn setup() -> (UserConfig, MonthlySchedule) {
let mut config = UserConfig::default();
let res_a = Resident::new("1", "Stefanos");
let res_b = Resident::new("2", "Iordanis");
config.add(res_a);
config.add(res_b);
let schedule = MonthlySchedule::new();
(config, schedule)
}
#[rstest]
fn test_total_holiday_slots() {
let config = UserConfig::default().with_holidays(vec![2, 3, 4]);
assert_eq!(16, config.total_holiday_slots());
}
}