sudoku.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. // pub mod group;
  2. use crate::group::*;
  3. // use std::collections::HashSet;
  4. use std::string::String;
  5. /// Width of the sudoku board.
  6. const WIDTH: u8 = 9;
  7. /// Size (width * height) of the board.
  8. const MAX_SIZE: u8 = 81;
  9. // Use bitfields instead of HashSets.
  10. use bit_field::BitField;
  11. extern crate rand_chacha;
  12. use rand::prelude::*;
  13. use rand::seq::SliceRandom;
  14. use rand_chacha::rand_core::SeedableRng;
  15. use rand_chacha::ChaCha20Rng;
  16. #[derive(Debug, Copy, Clone, PartialEq)]
  17. pub struct Possible(u16);
  18. /// Set bits number of bits to 1 (true)
  19. pub const fn set_bits(bits: u8) -> u16 {
  20. (1 << (bits)) - 1
  21. }
  22. impl Possible {
  23. /// clear all bits
  24. pub fn clear(&mut self) {
  25. self.0 = 0;
  26. }
  27. /// set bit to state of value.
  28. pub fn set(&mut self, bit: u8, value: bool) {
  29. self.0.set_bit(bit as usize, value);
  30. }
  31. /// get state of bit.
  32. pub fn get(&self, bit: u8) -> bool {
  33. self.0.get_bit(bit as usize)
  34. }
  35. /// set bits on, given number of bits initially to set.
  36. pub fn set_bits(&mut self, bits: u8) {
  37. self.0 = set_bits(bits);
  38. }
  39. /// count number of bits set.
  40. pub fn count_set(&self) -> u8 {
  41. let mut count = 0;
  42. for i in 0..u16::BIT_LENGTH {
  43. if self.get(i as u8) {
  44. count += 1;
  45. }
  46. }
  47. count
  48. }
  49. }
  50. struct PossibleIterator<'a> {
  51. possible: &'a Possible,
  52. index: u8,
  53. }
  54. impl Possible {
  55. fn iter(&self) -> PossibleIterator {
  56. PossibleIterator {
  57. possible: self,
  58. index: 1,
  59. }
  60. }
  61. }
  62. impl<'a> Iterator for PossibleIterator<'a> {
  63. type Item = u8;
  64. fn next(&mut self) -> Option<u8> {
  65. while (self.index < u16::BIT_LENGTH as u8) && (!self.possible.get(self.index)) {
  66. self.index += 1;
  67. // println!("index = {}", self.index);
  68. }
  69. if self.index == u16::BIT_LENGTH as u8 {
  70. None
  71. } else {
  72. self.index += 1;
  73. Some(self.index - 1)
  74. }
  75. }
  76. }
  77. #[cfg(test)]
  78. mod tests {
  79. use crate::sudoku::*;
  80. #[test]
  81. fn check_possible_bitset() {
  82. let mut p = Possible(0);
  83. p.clear();
  84. for i in 0..9 {
  85. let mut result = p.get(i);
  86. assert_eq!(result, false);
  87. p.set(i, true);
  88. result = p.get(i);
  89. assert_eq!(result, true);
  90. }
  91. }
  92. #[test]
  93. fn check_possible_iter() {
  94. let mut p = Possible(0);
  95. p.set(3, true);
  96. p.set(5, true);
  97. p.set(6, true);
  98. assert_eq!(3, p.count_set());
  99. let values: Vec<u8> = p.iter().collect();
  100. assert_eq!(values, vec!(3, 5, 6));
  101. assert_eq!(3, p.count_set());
  102. p.set(0, true);
  103. assert_eq!(4, p.count_set());
  104. }
  105. #[test]
  106. fn check_bits() {
  107. // Set bits 0-5 (6 bits total)
  108. let p = Possible(set_bits(6));
  109. for i in 0..6 {
  110. let result = p.get(i);
  111. assert_eq!(result, true);
  112. }
  113. assert_eq!(p.get(6), false);
  114. }
  115. }
  116. pub type SudokuBoard = [u8; MAX_SIZE as usize];
  117. pub type SudokuPossible = [Possible; MAX_SIZE as usize];
  118. #[derive(Debug)]
  119. pub struct Sudoku {
  120. pub board: [u8; MAX_SIZE as usize],
  121. // pub possible: [HashSet<u8>; MAX_SIZE as usize],
  122. pub possible: [Possible; MAX_SIZE as usize],
  123. }
  124. /// Translate x,y to position in board.
  125. pub const fn pos(x: u8, y: u8) -> u8 {
  126. x + (y * WIDTH as u8)
  127. }
  128. /// Translate x,y (with starting index of 1) to position in board.
  129. pub const fn pos1(x: u8, y: u8) -> u8 {
  130. (x - 1) + ((y - 1) * WIDTH as u8)
  131. }
  132. /// Translate post to x,y in board.
  133. pub const fn xy(pos: u8) -> (u8, u8) {
  134. ((pos % WIDTH), (pos / WIDTH))
  135. }
  136. const DEBUG_OUTPUT: bool = false;
  137. /*
  138. (0 .. 10)
  139. .map(|_| HashSet::<usize>::new())
  140. .collect();
  141. let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
  142. */
  143. impl Sudoku {
  144. pub fn new() -> Self {
  145. // let b : HashSet<u8> = HashSet::from_iter(1..=9);
  146. let mut initial: Possible = Possible(set_bits(10));
  147. initial.set(0, false);
  148. let s = Sudoku {
  149. board: [0; MAX_SIZE as usize],
  150. possible: [initial; MAX_SIZE as usize],
  151. };
  152. s
  153. }
  154. pub fn clear(&mut self) {
  155. let mut initial = Possible(set_bits(10));
  156. initial.set(0, false);
  157. self.board = [0; MAX_SIZE as usize];
  158. self.possible = [initial; MAX_SIZE as usize];
  159. }
  160. /// Load puzzle from a string.
  161. /// Note, we load from (top,left), to (bottom,left) by columns.
  162. pub fn load_from_tld(&mut self, start_ch: char, blank: char, s: &str) {
  163. self.clear();
  164. let mut x: u8 = 0;
  165. let mut y: u8 = 0;
  166. for ch in s.chars() {
  167. if ch != blank {
  168. self.set(x, y, (ch as u8 - start_ch as u8) + 1);
  169. }
  170. y += 1;
  171. if y >= WIDTH {
  172. y = 0;
  173. x += 1;
  174. }
  175. }
  176. }
  177. /// Load puzzle from a string.
  178. /// This loads from (top,left) to (top,right), by rows.
  179. pub fn load_from_tlr(&mut self, start_ch: char, blank: char, s: &str) {
  180. self.clear();
  181. let mut i: u8 = 0;
  182. for ch in s.chars() {
  183. if ch != blank {
  184. self.set(xy(i).0, xy(i).1, (ch as u8 - start_ch as u8) + 1);
  185. }
  186. i += 1;
  187. }
  188. }
  189. pub fn save_to_tld(&self, mut start_ch: char, blank: char) -> String {
  190. let mut result = String::new();
  191. result.reserve(MAX_SIZE as usize);
  192. start_ch = (start_ch as u8 - 1) as char;
  193. let mut x: u8 = 0;
  194. let mut y: u8 = 0;
  195. for i in 0..MAX_SIZE {
  196. if self.board[pos(x, y) as usize] == 0 {
  197. result.push(blank);
  198. } else {
  199. result.push((start_ch as u8 + self.board[i as usize]) as char);
  200. }
  201. y += 1;
  202. if y >= WIDTH {
  203. y = 0;
  204. x += 1;
  205. }
  206. }
  207. result
  208. }
  209. pub fn save_to_tlr(&self, mut start_ch: char, blank: char) -> String {
  210. let mut result = String::new();
  211. result.reserve(MAX_SIZE as usize);
  212. start_ch = (start_ch as u8 - 1) as char;
  213. for i in 0..MAX_SIZE {
  214. if self.board[i as usize] == 0 {
  215. result.push(blank);
  216. } else {
  217. result.push((start_ch as u8 + self.board[i as usize]) as char);
  218. }
  219. }
  220. result
  221. }
  222. pub fn set(&mut self, x: u8, y: u8, value: u8) {
  223. self.board[pos(x, y) as usize] = value;
  224. // Ok, update the possible
  225. let mut g = for_row(y);
  226. // g.for_row(x, y);
  227. for g in g.0 {
  228. // remove value from these sets.
  229. self.possible[g as usize].set(value, false);
  230. // self.possible[g as usize].take(&value);
  231. }
  232. g = for_column(x);
  233. // g.for_column(x, y);
  234. for g in g.0 {
  235. // remove value from these sets.
  236. self.possible[g as usize].set(value, false);
  237. // self.possible[g as usize].take(&value);
  238. }
  239. g = for_cell(which_cell(x, y));
  240. // g.for_block(x, y);
  241. for g in g.0 {
  242. // remove value from these sets.
  243. self.possible[g as usize].set(value, false);
  244. // self.possible[g as usize].take(&value);
  245. }
  246. self.possible[pos(x, y) as usize].clear();
  247. }
  248. pub fn display(&self) {
  249. println!("╔═══╦═══╦═══╗");
  250. for y in 0..WIDTH {
  251. print!("║");
  252. for x in 0..WIDTH {
  253. let item = self.board[pos(x as u8, y as u8) as usize];
  254. if item == 0 {
  255. print!(" ");
  256. } else if (item >= 1) && (item <= 9) {
  257. print!("{}", item);
  258. }
  259. if x % 3 == 2 {
  260. print!("║");
  261. }
  262. }
  263. println!("");
  264. if y % 3 == 2 {
  265. if y + 1 == WIDTH {
  266. println!("╚═══╩═══╩═══╝");
  267. } else {
  268. println!("╠═══╬═══╬═══╣");
  269. }
  270. }
  271. }
  272. }
  273. pub fn display_possible(&self) {
  274. for y in 0..WIDTH {
  275. for x in 0..WIDTH {
  276. // print!("p={:?}", self.possible[pos(x, y) as usize]);
  277. let mut possible = String::new();
  278. for p in self.possible[pos(x, y) as usize].iter() {
  279. // print!("{},", p);
  280. possible += format!("{},", p).as_str();
  281. }
  282. // for i in 0..SIZE {
  283. // let &pos = self.possible[pos(x, y) as usize];
  284. print!("({},{}):", x, y);
  285. // print!("{:20}", format!("{:?}", self.possible[pos(x, y) as usize]));
  286. print!("{:9}", possible);
  287. /*
  288. if pos == 0 {
  289. print!(" ");
  290. } else {
  291. print!("{}", pos);
  292. }
  293. */
  294. // }
  295. // print!(" ");
  296. }
  297. println!("");
  298. }
  299. }
  300. pub fn puzzle_complete(&self) -> bool {
  301. for i in 0..MAX_SIZE {
  302. if self.board[i as usize] == 0 {
  303. return false;
  304. }
  305. }
  306. true
  307. }
  308. fn calculate_possible(&mut self, total_solutions: &mut u16, solutions: &mut Vec<SudokuBoard>) -> bool {
  309. for idx in 0..MAX_SIZE {
  310. if self.board[idx as usize] == 0 {
  311. // Ok, there's a blank here
  312. let (x, y) = xy(idx);
  313. if DEBUG_OUTPUT {
  314. println!("idx={} ({},{})", idx, x, y);
  315. self.display();
  316. }
  317. 'outer: for possible in 1..=9 {
  318. let mut g = for_row(y);
  319. for p in g.0 {
  320. if self.board[p as usize] == possible {
  321. continue 'outer;
  322. }
  323. }
  324. g = for_column(x);
  325. for p in g.0 {
  326. if self.board[p as usize] == possible {
  327. continue 'outer;
  328. }
  329. }
  330. // check cell
  331. let cell = which_cell(x, y);
  332. g = for_cell(cell);
  333. for p in g.0 {
  334. if self.board[p as usize] == possible {
  335. continue 'outer;
  336. }
  337. }
  338. // Ok, it could go here!
  339. if DEBUG_OUTPUT {
  340. println!("({},{})={}", x, y, possible);
  341. }
  342. self.board[idx as usize] = possible;
  343. if self.puzzle_complete() {
  344. if *total_solutions < solutions.capacity() as u16 {
  345. solutions.push(self.board);
  346. }
  347. *total_solutions += 1;
  348. /*
  349. println!("**SOLUTION**");
  350. self.display();
  351. println!("***");
  352. */
  353. break;
  354. } else {
  355. if self.calculate_possible(total_solutions, solutions) {
  356. return true;
  357. }
  358. }
  359. }
  360. self.board[idx as usize] = 0;
  361. return false;
  362. }
  363. }
  364. false
  365. }
  366. pub fn bruteforce_solver(&self) -> u16 {
  367. let mut workset = Sudoku {
  368. board: self.board,
  369. possible: [Possible(0); MAX_SIZE as usize],
  370. };
  371. let mut total_solutions: u16 = 0;
  372. let mut solutions = Vec::new();
  373. solutions.reserve(1);
  374. workset.calculate_possible(&mut total_solutions, &mut solutions);
  375. // return number of solutions.
  376. if solutions.len() > 0 {
  377. println!("*** A solution:");
  378. workset.board = solutions[0];
  379. workset.display();
  380. println!("***");
  381. }
  382. total_solutions
  383. }
  384. pub fn make(&mut self) {
  385. let mut rng = ChaCha20Rng::from_entropy();
  386. self.fill_board(&mut rng);
  387. }
  388. fn fill_board(&mut self, rng: &mut ChaCha20Rng) -> bool {
  389. let backup = Sudoku {
  390. board: self.board,
  391. possible: self.possible,
  392. };
  393. for idx in 0..MAX_SIZE {
  394. if self.board[idx as usize] == 0 {
  395. let (x, y) = xy(idx);
  396. let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
  397. let mut total_available: u8 = 0;
  398. for t in self.possible[idx as usize].iter() {
  399. available[total_available as usize] = t;
  400. total_available += 1;
  401. }
  402. if total_available == 0 {
  403. // No possible moves remain.
  404. /*
  405. self.board = backup.board;
  406. self.possible = backup.possible;
  407. */
  408. return false;
  409. }
  410. // Randomize the possible items.
  411. available[0..total_available as usize].shuffle(rng);
  412. for v_idx in 0..total_available {
  413. let value = available[v_idx as usize];
  414. self.set(x, y, value);
  415. if self.fill_board(rng) {
  416. return true;
  417. }
  418. // failure
  419. self.board = backup.board;
  420. self.possible = backup.possible;
  421. }
  422. // We've run out of possible.
  423. return false;
  424. }
  425. }
  426. // We've visited everything, and it isn't 0.
  427. return true;
  428. }
  429. pub fn make_(&mut self) {
  430. self.clear();
  431. let mut rng = ChaCha20Rng::from_entropy();
  432. let pick_one = |this: &Self, rng: &mut ChaCha20Rng, idx: u8| -> Option<u8> {
  433. let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
  434. let mut total_available: u8 = 0;
  435. for t in this.possible[idx as usize].iter() {
  436. available[total_available as usize] = t;
  437. total_available += 1;
  438. }
  439. if total_available == 1 {
  440. return Some(available[0]);
  441. }
  442. if total_available == 0 {
  443. return None;
  444. }
  445. Some(available[rng.gen_range(0..total_available as usize)])
  446. };
  447. for i in 0..MAX_SIZE {
  448. let (x, y) = xy(i);
  449. if self.board[i as usize] == 0 {
  450. // Ok, we found a blank space.
  451. let value = pick_one(self, &mut rng, i);
  452. if value.is_some() {
  453. let value = value.unwrap();
  454. if DEBUG_OUTPUT {
  455. println!("Set({},{})={}", x, y, value);
  456. }
  457. self.set(x, y, value);
  458. }
  459. }
  460. }
  461. }
  462. pub fn solve(&mut self, debug: bool) -> bool {
  463. // Pass 1: Look for singles in the possible sets.
  464. let mut found_something = false;
  465. for i in 0..MAX_SIZE {
  466. if self.possible[i as usize].count_set() == 1 {
  467. // Get the value
  468. let value = self.possible[i as usize].iter().next().unwrap();
  469. // Found one!
  470. if debug {
  471. println!("Set1 {:?} to {}", xy(i), value);
  472. }
  473. self.set(xy(i).0, xy(i).1, value);
  474. found_something = true;
  475. }
  476. }
  477. let mut g = Group::new();
  478. let mut values = Possible(0); // HashSet<u8> = HashSet::new();
  479. let mut group_process = |this: &mut Self, grp: &Group| {
  480. // Collect all the possible values within the group.
  481. values.clear();
  482. for gidx in 0..WIDTH {
  483. // println!("possible: {:?}", this.possible[grp.items[gidx as usize] as usize]);
  484. for v in this.possible[grp.0[gidx as usize] as usize].iter() {
  485. values.set(v, true);
  486. }
  487. // values.extend(this.possible[grp.0[gidx as usize] as usize]);
  488. // println!("now : {:?}", this.possible[grp.items[gidx as usize] as usize]);
  489. }
  490. // println!("values {:?}", values);
  491. // Now, check for singles.
  492. for v in values.iter() {
  493. let mut count = 0;
  494. let mut pos = 0;
  495. for gidx in 0..WIDTH {
  496. if this.possible[grp.0[gidx as usize] as usize].get(v) {
  497. // if this.possible[grp.0[gidx as usize] as usize].contains(&v) {
  498. count += 1;
  499. pos = grp.0[gidx as usize];
  500. if count > 1 {
  501. break;
  502. }
  503. }
  504. }
  505. if count == 1 {
  506. // don't need this, it was v!
  507. // let value = this.possible[pos as usize].iter().next().cloned().unwrap();
  508. if debug {
  509. println!("Set2 {:?} to {}", xy(pos), v);
  510. }
  511. this.set(xy(pos).0, xy(pos).1, v);
  512. found_something = true;
  513. }
  514. }
  515. };
  516. // Change to 0..WIDTH ... Keep it simple.
  517. for i in 0..WIDTH {
  518. let mut g = for_column(i);
  519. // g.for_column(i, 1);
  520. group_process(self, &g);
  521. g = for_row(i);
  522. // g.for_row(1, i);
  523. group_process(self, &g);
  524. g = for_cell(i);
  525. // g.for_iter(i);
  526. group_process(self, &g);
  527. }
  528. if found_something {
  529. return found_something;
  530. }
  531. if debug {
  532. println!("Looking for pairs...");
  533. }
  534. // PAIR processing.
  535. for i in 0..WIDTH {
  536. g.for_iter(i);
  537. for gidx in 0..WIDTH - 1 {
  538. let gpos = g.0[gidx as usize];
  539. if self.possible[gpos as usize].count_set() == 2 {
  540. // Found a pair
  541. for fidx in gidx + 1..WIDTH {
  542. let fpos = g.0[fidx as usize];
  543. if self.possible[fpos as usize].count_set() == 2 {
  544. // Ok, there's another pair
  545. // if self.possible[gpos as usize].is_subset(&self.possible[fpos as usize])
  546. if self.possible[gpos as usize] == self.possible[fpos as usize] {
  547. // Ok, they have the same values!
  548. // Ok, remove the items in the pair from the cell.
  549. // Don't touch the gpos/fpos records. Keep those!
  550. let mut values: [u8; 2] = [0, 0];
  551. let mut vpos = 0;
  552. for z in self.possible[gpos as usize].iter() {
  553. values[vpos] = z;
  554. vpos += 1;
  555. }
  556. let mut pair_removed = false;
  557. // Check to see if anything was removed.
  558. for remove in 0..WIDTH {
  559. if (gidx == remove) || (fidx == remove) {
  560. continue;
  561. }
  562. // Ok, these aren't the ones to save, so:
  563. let rpos = g.0[remove as usize];
  564. if self.possible[rpos as usize].get(values[0]) {
  565. self.possible[rpos as usize].set(values[0], false);
  566. found_something = true;
  567. pair_removed = true;
  568. }
  569. if self.possible[rpos as usize].get(values[1]) {
  570. self.possible[rpos as usize].set(values[1], false);
  571. found_something = true;
  572. pair_removed = true;
  573. }
  574. }
  575. // Check the x's and y's to see if we can also process a row/column too.
  576. if xy(gpos).0 == xy(fpos).0 {
  577. // Matching X - process column
  578. let column = xy(gpos).0;
  579. vpos = 0;
  580. for z in self.possible[gpos as usize].iter() {
  581. values[vpos] = z;
  582. vpos += 1;
  583. }
  584. for remove in 0..WIDTH {
  585. if (remove == xy(gpos).1) || (remove == xy(fpos).1) {
  586. continue;
  587. }
  588. if self.possible[pos(column, remove) as usize]
  589. .get(values[0])
  590. {
  591. self.possible[pos(column, remove) as usize]
  592. .set(values[0], false);
  593. found_something = true;
  594. pair_removed = true;
  595. }
  596. if self.possible[pos(column, remove) as usize]
  597. .get(values[1])
  598. {
  599. self.possible[pos(column, remove) as usize]
  600. .set(values[1], false);
  601. found_something = true;
  602. pair_removed = true;
  603. }
  604. }
  605. }
  606. if xy(gpos).1 == xy(fpos).1 {
  607. // Matching Y - process row
  608. let row = xy(gpos).1;
  609. vpos = 0;
  610. for z in self.possible[gpos as usize].iter() {
  611. values[vpos] = z;
  612. vpos += 1;
  613. }
  614. for remove in 0..WIDTH {
  615. if (remove == xy(gpos).0) || (remove == xy(fpos).0) {
  616. continue;
  617. }
  618. if self.possible[pos(remove, row) as usize].get(values[0]) {
  619. self.possible[pos(remove, row) as usize]
  620. .set(values[0], false);
  621. found_something = true;
  622. pair_removed = true;
  623. }
  624. if self.possible[pos(remove, row) as usize].get(values[1]) {
  625. self.possible[pos(remove, row) as usize]
  626. .set(values[1], false);
  627. found_something = true;
  628. pair_removed = true;
  629. }
  630. }
  631. }
  632. if pair_removed {
  633. if debug {
  634. println!(
  635. "Pair found! {} {}: {} {:?} and {} {:?} !",
  636. gidx,
  637. fidx,
  638. gpos,
  639. xy(gpos),
  640. fpos,
  641. xy(fpos)
  642. );
  643. }
  644. }
  645. }
  646. }
  647. }
  648. }
  649. }
  650. }
  651. found_something
  652. }
  653. }