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:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user