use clingo::{Control, ShowType, Symbol, Part, SolveMode};
use crate::{SolveRequest, SolveResponse, SolveError};
// Potassco solution for n-queens.
const BASE_PROGRAM: &str = r#"
{ queen (I, 0..n-1) } = 1 :- I = 0..n-1.
{ queen (0..n-1, J) } = 1 :- J = 0..n-1.
:- { queen (D - J, J) } > 1, D = 2..2 * (n-1).
:- { queen (D + J, J) } > 1, D = n..n - 2.
"#;
pub fn solve(req: SolveRequest) -> Result<SolveResponse, SolveError> {
// Setup
let mut ctl = Control::new(vec![])?;
ctl.add("base", &["n"], BASE_PROGRAM)?;
let base_parameter = [Symbol::create_number(req.size)];
let base = Part::new("base", &base_parameter)?;
// TODO (malte): Add fixed queen constraints
// Ground
ctl.ground(&[base])?;
// Solve
let mut handle = ctl.solve(SolveMode::YIELD, &[])?;
handle.resume()?;
// TODO (malte): Implement timeout
let model = handle.model()?.ok_or(SolveError::NoSolution)?;
// Parse model
let mut response = SolveResponse { id: req.id, queens: vec![] };
for atom in model.symbols(ShowType::SHOWN)? {
match atom.name()? {
"queen" => {
let params = atom.arguments()?;
debug_assert!(params.len() == 2);
let x_param = params[0].number()?;
let y_param = params[1].number()?;
response.queens.push((x_param as u32, y_param as u32));
},
_ => unreachable!()
}
}
Ok(response)
}