use bounds::partial_tiles_bound;
use crate::utils::{DominoError, Puzzle};
use super::model::bounds::{
each_position_filled_bound, each_tile_used_once_bound, next_adjacent_bound,
};
use super::model::variables::{variables, Variables};
mod bounds;
mod helpers;
pub mod variables;
fn bounds(puzzle: &Puzzle, vars: &Variables) -> Vec<String> {
let mut prob_bounds = Vec::new();
prob_bounds.extend(vec!["y = 0".to_string()].into_iter());
prob_bounds.extend(each_tile_used_once_bound(vars));
prob_bounds.extend(each_position_filled_bound(vars));
prob_bounds.extend(next_adjacent_bound(puzzle, vars));
prob_bounds.extend(partial_tiles_bound(puzzle, vars));
prob_bounds
}
pub fn compute_model(puzzle: &Puzzle) -> Result<String, DominoError> {
let prob_vars = variables(puzzle)?;
let prob_obj = "y".to_string();
let prob_bounds = bounds(puzzle, &prob_vars);
let mut model = "Minimize\n".to_string();
model.push_str(format!(" obj: {}\n", prob_obj).as_str());
model.push_str("Subject To\n");
for (i, constraint) in prob_bounds.iter().enumerate() {
if !constraint.is_empty() {
model.push_str(format!(" c{}: {}\n", i, constraint).as_str());
}
}
model.push_str("Binary\n");
for variable in prob_vars.vars {
model.push_str(format!(" {}\n", variable.label).as_str());
}
model.push_str("End");
Ok(model)
}