1use rand::{thread_rng, Rng};
2use sol::PossibilityMap;
3use Difficulty;
4use Element;
5use Grid;
6use Score;
7use Sudoku;
8
9const MAX_HARDEN_ITERATIONS: u8 = 20;
12
13pub trait Generate: Score + Sized {
18 fn generate(order: u8, difficulty: Difficulty) -> Self;
20}
21
22fn take_random<T>(values: &mut Vec<T>) -> Option<T> {
23 let mut rng = thread_rng();
24 let mut indices = (0..values.len()).collect::<Vec<_>>();
25 rng.shuffle(&mut indices);
26 indices.get(0).map(|index| values.remove(*index))
27}
28
29fn recurse(puzzle: Sudoku) -> Option<Sudoku> {
30 let map: PossibilityMap = puzzle.clone().into();
31 match map.next() {
32 (None, _) => {
33 let puzzle = puzzle.clone();
34 if puzzle.is_complete() {
35 Some(puzzle)
36 } else {
37 None
38 }
39 }
40 (Some(index), Some(set)) => {
41 let mut possibilities = (1..=(puzzle.order as usize).pow(2))
42 .filter(|v| set.contains(*v))
43 .collect::<Vec<_>>();
44 while let Some(candidate) = take_random(&mut possibilities) {
45 let solution = recurse(puzzle.substitute(index, Some(Element(candidate as u8))));
46 if solution.is_some() {
47 return solution;
48 }
49 }
50 None
51 }
52 _ => unreachable!(),
53 }
54}
55
56fn grid(order: u8) -> Option<Sudoku> {
58 let mut rng = thread_rng();
59 let mut puzzle = Sudoku::new(order);
60 {
62 let mut first_box = (1..=order.pow(2))
64 .map(|v| Some(Element(v)))
65 .collect::<Vec<_>>();
66 rng.shuffle(&mut first_box);
67 let order = order as usize;
68 let axis = order.pow(2);
69 {
70 let elements = &mut puzzle.elements;
71 for i in 0..axis {
72 let index = i / order * axis + i;
73 elements[index] = first_box[i];
74 }
75 }
76 recurse(puzzle)
79 }
80}
81
82fn harden(mut sudoku: &mut Sudoku, target: Difficulty) -> Result<(), ()> {
87 let current = sudoku.score().unwrap();
88 let mut points = sudoku.points();
89 for _ in 0..MAX_HARDEN_ITERATIONS {
90 if let (Some(one), Some(two)) = (take_random(&mut points), take_random(&mut points)) {
91 let (one, two) = (one.fold(sudoku.order), two.fold(sudoku.order));
92 let mut puzzle = sudoku.clone();
93 puzzle.elements[one] = None;
95 puzzle.elements[two] = None;
96 match puzzle.score() {
97 Some(score) => {
98 if score > current {
99 let difficulty: Difficulty = score.into();
100 if difficulty > target {
101 continue;
103 }
104 sudoku.elements[one] = None;
105 sudoku.elements[two] = None;
106 return if difficulty == target {
107 Ok(())
108 } else {
109 harden(&mut sudoku, target)
110 };
111 }
112 }
113 _ => {}
114 }
115 }
116 }
117 Err(())
118}
119
120impl Generate for Sudoku {
121 fn generate(order: u8, difficulty: Difficulty) -> Self {
122 let mut puzzle = grid(order).unwrap();
123 let _ = harden(&mut puzzle, difficulty);
124 puzzle
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use gen;
131 use Solve;
132 #[cfg_attr(feature = "2D", test)]
133 fn test_grid() {
134 let grid = gen::grid(3);
135 let grid = grid.unwrap();
136 assert!(grid.is_complete());
137 assert!(grid.is_uniquely_solvable());
138 }
139}