diff --git a/planner/src/bin/weekly.rs b/planner/src/bin/weekly.rs index b5b6e92..fc5d033 100644 --- a/planner/src/bin/weekly.rs +++ b/planner/src/bin/weekly.rs @@ -5,28 +5,61 @@ extern crate planner; use self::cookbook::*; use self::cookbook::models::Recipe; -use self::planner::solver::{Domain, Problem, Constraint, Variables}; +use self::planner::solver::{Variables, Domain, Problem, Constraint}; /// We want a mapping of the week meals (matin, midi, soir) +/// Breakfast => RecipeCategory::Breakfast +/// Lunch => RecipeCategory::MainCourse +/// Dinner => RecipeCategory::MainCourse +type Day = String; + +enum Meals { + Breakfast(Day), + Lunch(Day), + Dinner(Day) +} + +impl Into for Meals { + fn into(self) -> String { + match self { + Meals::Breakfast(d) => format!("{}_Breakfast", d), + Meals::Lunch(d) => format!("{}_Lunch", d), + Meals::Dinner(d) => format!("{}_Dinner", d), + } + } +} /// associated with filters for Domain, depending on recipes RecipeCategory +enum RecipeCategory { + Breakfast, + MainCourse +} /// It may also contains an initial value for each variable +fn generate_variables(domain: &Domain) -> Vec<(String, &Domain, Option<&V>)> { + let mut vars = Vec::new(); + for day in &["Lundi", "Mardi", "Mercredi"] { + vars.push((Meals::Lunch(String::from(day)).into(), domain, None)); + vars.push((Meals::Dinner(String::from(day)).into(), domain, None)); + } + vars +} fn ingredients_contains<'a>(assign: &Variables<'a,Recipe>) -> bool { - assign.get("Lundi_midi").unwrap().unwrap().ingredients.contains("Patates") - && assign.get("Mardi_midi").unwrap().unwrap().ingredients.contains("Patates") + assign.get("Lundi_Lunch").unwrap().unwrap().ingredients.contains("Patates") + && !assign.get("Mardi_Lunch").unwrap().unwrap().ingredients.contains("Patates") } fn get_planning_all_results() -> String { let conn = establish_connection(); let possible_values = recipes::load_all(&conn); let domain = Domain::new(possible_values); - let mut problem = Problem::build() - .add_variable("Lundi_midi".to_string(), &domain, None) - .add_variable("Mardi_midi".to_string(), &domain, None) - .add_constraint(ingredients_contains) - .finish(); + let mut problem = Problem::build(); + for (var, dom, ini) in generate_variables(&domain) { + problem = problem.add_variable(var, dom, ini); + } + let mut problem = problem.add_constraint(ingredients_contains) + .finish(); let results = problem.solve_all(); - format!("{:#?}\nTotal = {}", &results, results.len()) + format!("{:#?}\nTotal = {}", &results.first(), results.len()) } fn main() { diff --git a/planner/src/solver.rs b/planner/src/solver.rs index d70206e..6dc0b9a 100644 --- a/planner/src/solver.rs +++ b/planner/src/solver.rs @@ -13,7 +13,7 @@ enum Assignment<'a, V> { Clear(String) } - +type Domains<'a, V> = HashMap>; /// The domain of values that can be assigned to variables #[derive(Clone)] pub struct Domain { @@ -51,13 +51,14 @@ impl fmt::Debug for Domain { } } + pub type Constraint<'a,V> = fn(&Variables<'a,V>) -> bool; pub struct Problem<'a, V> { /// The initial assignements map variables: Variables<'a, V>, /// Each variable has its associated domain - domains: HashMap>, + domains: Domains<'a,V>, /// Set of constraints to validate constraints: Vec>, } @@ -141,11 +142,10 @@ impl<'a, V> ProblemBuilder<'a, V> { }) } - pub fn add_variable(mut self, - name: String, - domain: &'a Domain, - value: Option<&'a V>, - ) -> Self { + pub fn add_variable(mut self, name: S, domain: &'a Domain, value: Option<&'a V>) -> Self + where S: Into + { + let name = name.into(); self.0.variables.insert(name.clone(), value); self.0.domains.insert(name, domain); self