1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! N-Queens Problem Solver (New API)
//!
//! This example demonstrates solving the classic N-Queens problem using the new unified API.
//! The N-Queens problem involves placing N queens on an NรN chessboard such that no two queens
//! attack each other (same row, column, or diagonal).
//!
//! This example demonstrates:
//! - m.ints() for creating multiple variables
//! - m.alldiff() for all-different constraints
//! - add() for expression building
//! - m.solve() for finding solutions
use selen::prelude::*;
use std::time::Instant;
fn main() {
println!("๐ N-Queens Problem Solver (New API)");
println!("====================================\n");
// Test 8-Queens problem
let n = 8;
println!("๐ Solving {}-Queens problem", n);
let start = Instant::now();
match solve_n_queens(n) {
Some(solution) => {
let duration = start.elapsed();
println!("โ
Solution found in {:.3}ms!", duration.as_secs_f64() * 1000.0);
print_board(&solution, n);
}
None => {
println!("โ No solution found");
}
}
}
fn solve_n_queens(n: usize) -> Option<Vec<i32>> {
let mut m = Model::default();
// Variables: queen_rows[i] = row position of queen in column i (1-based)
let queen_rows = m.ints(n, 1, n as i32);
// Constraint 1: All queens must be in different rows
m.alldiff(&queen_rows);
// Constraint 2: No two queens on the same ascending diagonal
// Ascending diagonal: queen_row[i] + i must be different for all i
let mut ascending_diagonals = Vec::new();
for (i, &queen_row) in queen_rows.iter().enumerate() {
// queen_row + i (using explicit int constant)
let diagonal = add(queen_row, int(i as i32));
ascending_diagonals.push(diagonal);
}
// We need to materialize these expressions into variables for alldiff
let ascending_vars: Vec<_> = ascending_diagonals.iter()
.map(|expr| {
let var = m.int(1 - n as i32, 2 * n as i32);
m.new(expr.clone().eq(var));
var
})
.collect();
m.alldiff(&ascending_vars);
// Constraint 3: No two queens on the same descending diagonal
// Descending diagonal: queen_row[i] - i must be different for all i
let mut descending_diagonals = Vec::new();
for (i, &queen_row) in queen_rows.iter().enumerate() {
// queen_row - i (using explicit int constant)
let diagonal = sub(queen_row, int(i as i32));
descending_diagonals.push(diagonal);
}
// Materialize descending diagonal expressions
let descending_vars: Vec<_> = descending_diagonals.iter()
.map(|expr| {
let var = m.int(1 - n as i32, n as i32);
m.new(expr.clone().eq(var));
var
})
.collect();
m.alldiff(&descending_vars);
// Solve the model
match m.solve() {
Ok(sol) => {
let positions: Vec<i32> = queen_rows.iter()
.map(|&var| sol.get_int(var))
.collect();
Some(positions)
}
Err(_) => None,
}
}
fn print_board(solution: &[i32], n: usize) {
println!("\n๐ Solution:");
// Print column numbers
print!(" ");
for col in 1..=n {
print!("{:2} ", col);
}
println!();
// Print board with queens
for row in 1..=(n as i32) {
print!("{:2} ", row);
for col in 0..n {
if solution[col] == row {
print!(" โ ");
} else {
print!(" ยท ");
}
}
println!();
}
println!();
}