first step towards weekly planning

This commit is contained in:
artus
2018-12-24 15:44:19 +01:00
parent f0bc06d9ed
commit 8236b8ac9f
7 changed files with 99 additions and 17 deletions

View File

@@ -1,3 +1,7 @@
mod meal;
pub use self::meal::Meal;
#[cfg(test)]
mod tests {
#[test]

19
cookbook/src/meal.rs Normal file
View File

@@ -0,0 +1,19 @@
#[derive(Debug,Clone)]
pub struct Meal {
name: String,
nutritional_value: i32,
}
impl Meal {
pub fn new(name: String, nutritional_value: i32) -> Meal {
Meal { name, nutritional_value }
}
pub fn nutritional_value(&self) -> i32 {
self.nutritional_value
}
}

View File

@@ -1,11 +0,0 @@
enum Meal {
FullMeal,
Composed,
}
fn retrieve_all() -> Vec<Meal> {
vec!()
}

47
planner/src/bin/weekly.rs Normal file
View File

@@ -0,0 +1,47 @@
//! The weekly menu planner
//!
use cookbook::Meal;
use planner::solver::{Variables, Domain, solve_all};
fn generate_weekly_menu() -> String {
let assignments: Variables<Meal> = [
("LundiMidi".to_string(), None), ("LundiSoir".to_string(), None),
("MardiMidi".to_string(), None), ("MardiSoir".to_string(), None),
("MercrediMidi".to_string(), None), ("MercrediSoir".to_string(), None),
].iter().cloned().collect();
let meals: Domain<Meal> = Domain::new(vec![
Meal::new("Raclette".to_string(), 800),
Meal::new("Soupe".to_string(), 400),
]);
let validator = |vars: &Variables<Meal>| {
let mut result = true;
for day in ["Lundi", "Mardi", "Mercredi"].into_iter() {
let all_day = vars.keys().filter(|k| k.starts_with(day));
let mut nutri_value = 0;
for key in all_day {
nutri_value += vars.get(key)
.expect("no value here !")
.expect("no meal there !")
.nutritional_value()
}
println!("{} -> {}", day, nutri_value);
if nutri_value != 1200 { result = false; };
}
println!("Validator returns {}", result);
result
};
let solutions = solve_all(assignments, &meals, validator);
format!("{:#?}", solutions)
}
fn main() {
println!("{}", generate_weekly_menu());
}
#[cfg(test)]
mod tests {
}

View File

@@ -1,4 +1,6 @@
mod solver;
extern crate cookbook;
pub mod solver;
#[cfg(test)]
mod tests {

16
planner/src/rules.rs Normal file
View File

@@ -0,0 +1,16 @@
//! Rules used by the `planner`
//! A rule is a constraint on valid solutions, but also provides insights
//! and eventually inferences to optimize the solving process.
// Nutritional values
// - Per day : according to user profile (man: 2000kcal, woman: 1800kcal)
// - Per meal : some meals should have higher nutrional values than others
// Ingredients
// - Per week : should use most of a limited set of ingredients (excluding
// condiments, ...)
// - To consume : must use a small set of ingredients (leftovers)
//
// Price
// - Per week : should restrict ingredients cost to a given amount

View File

@@ -2,7 +2,7 @@ use std::fmt;
use std::clone::Clone;
use std::collections::HashMap;
type Variables<'a, V> = HashMap<String, Option<&'a V>>;
pub type Variables<'a, V> = HashMap<String, Option<&'a V>>;
enum Assignment<'a, V> {
Update(String, &'a V),
@@ -11,12 +11,12 @@ enum Assignment<'a, V> {
#[derive(Clone)]
struct Domain<V> {
pub struct Domain<V> {
values: Vec<V>
}
impl<V> Domain<V> {
fn new(values: Vec<V>) -> Domain<V> {
pub fn new(values: Vec<V>) -> Domain<V> {
Domain { values }
}
}
@@ -35,6 +35,7 @@ fn assign_next<'a,'b, V>(assign: &'b Variables<'a, V>, domain: &'a Domain<V>)
where V: fmt::Debug
{
// Panics on empty domain
// If domain values are filtered, then the branch is a dead end
if domain.values.is_empty() { panic!("No values in domain : {:?}", domain); };
// TODO: should be able to inject a choosing strategy
@@ -51,8 +52,12 @@ fn assign_next<'a,'b, V>(assign: &'b Variables<'a, V>, domain: &'a Domain<V>)
}
/// Visit all possible solutions, using a stack.
fn solve_all<'a, V: Clone + fmt::Debug>(mut assign: Variables<'a, V>, domain: &'a Domain<V>, is_valid: fn(&Variables<'a,V>) -> bool)
-> Vec<Variables<'a, V>>
pub fn solve_all<'a, V>(
mut assign: Variables<'a, V>,
domain: &'a Domain<V>,
is_valid: fn(&Variables<'a,V>) -> bool
) -> Vec<Variables<'a, V>>
where V: Clone + fmt::Debug
{
let mut solutions: Vec<Variables<V>> = vec![];
let mut stack: Vec<Assignment<'a, V>> = vec![];