sudoku.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. // pub mod group;
  2. use crate::group::*;
  3. // use std::collections::HashSet;
  4. use std::string::String;
  5. const SIZE: u8 = 3;
  6. /// Width of the sudoku board.
  7. const WIDTH: u8 = SIZE*SIZE;
  8. /// Size (width * height) of the board.
  9. const MAX_SIZE: u8 = WIDTH * WIDTH; // 81;
  10. // Use bitfields instead of HashSets.
  11. use bit_field::BitField;
  12. extern crate rand_chacha;
  13. // use rand::prelude::*;
  14. use rand::seq::SliceRandom;
  15. use rand_chacha::rand_core::SeedableRng;
  16. use rand_chacha::ChaCha20Rng;
  17. use rand::distributions::{Distribution, Uniform};
  18. // If I wanted to do 4x4 or 5x5, I would need more bits. (u32).
  19. #[derive(Debug, Copy, Clone, PartialEq)]
  20. pub struct Bits(u16);
  21. /// Set bits number of bits to 1 (true)
  22. pub const fn set_bits(bits: u8) -> u16 {
  23. (1 << (bits)) - 1
  24. }
  25. impl Bits {
  26. /// clear all bits
  27. pub fn clear(&mut self) {
  28. self.0 = 0;
  29. }
  30. /// set bit to state of value.
  31. pub fn set(&mut self, bit: u8, value: bool) {
  32. self.0.set_bit(bit as usize, value);
  33. }
  34. /// get state of bit.
  35. pub fn get(&self, bit: u8) -> bool {
  36. self.0.get_bit(bit as usize)
  37. }
  38. /// set bits on, given number of bits initially to set.
  39. pub fn set_bits(&mut self, bits: u8) {
  40. self.0 = set_bits(bits);
  41. }
  42. /// count number of bits set.
  43. pub fn count_set(&self) -> u8 {
  44. let mut count = 0;
  45. for i in 0..u16::BIT_LENGTH {
  46. if self.get(i as u8) {
  47. count += 1;
  48. }
  49. }
  50. count
  51. }
  52. }
  53. struct BitsIterator<'a> {
  54. possible: &'a Bits,
  55. index: u8,
  56. }
  57. impl Bits {
  58. fn iter(&self) -> BitsIterator {
  59. BitsIterator {
  60. possible: self,
  61. index: 1,
  62. }
  63. }
  64. }
  65. impl<'a> Iterator for BitsIterator<'a> {
  66. type Item = u8;
  67. fn next(&mut self) -> Option<u8> {
  68. while (self.index < u16::BIT_LENGTH as u8) && (!self.possible.get(self.index)) {
  69. self.index += 1;
  70. // println!("index = {}", self.index);
  71. }
  72. if self.index == u16::BIT_LENGTH as u8 {
  73. None
  74. } else {
  75. self.index += 1;
  76. Some(self.index - 1)
  77. }
  78. }
  79. }
  80. #[cfg(test)]
  81. mod tests {
  82. use crate::sudoku::*;
  83. #[test]
  84. fn check_possible_bitset() {
  85. let mut p = Bits(0);
  86. p.clear();
  87. for i in 0..9 {
  88. let mut result = p.get(i);
  89. assert_eq!(result, false);
  90. p.set(i, true);
  91. result = p.get(i);
  92. assert_eq!(result, true);
  93. }
  94. }
  95. #[test]
  96. fn check_possible_iter() {
  97. let mut p = Bits(0);
  98. p.set(3, true);
  99. p.set(5, true);
  100. p.set(6, true);
  101. assert_eq!(3, p.count_set());
  102. let values: Vec<u8> = p.iter().collect();
  103. assert_eq!(values, vec!(3, 5, 6));
  104. assert_eq!(3, p.count_set());
  105. p.set(0, true);
  106. assert_eq!(4, p.count_set());
  107. }
  108. #[test]
  109. fn check_bits() {
  110. // Set bits 0-5 (6 bits total)
  111. let p = Bits(set_bits(6));
  112. for i in 0..6 {
  113. let result = p.get(i);
  114. assert_eq!(result, true);
  115. }
  116. assert_eq!(p.get(6), false);
  117. }
  118. }
  119. pub type SudokuBoard = [u8; MAX_SIZE as usize];
  120. pub type Possible = [Bits; MAX_SIZE as usize];
  121. pub type SudokuPossible = [Bits; MAX_SIZE as usize];
  122. #[derive(Debug, Clone, Copy)]
  123. pub struct Board([u8; MAX_SIZE as usize]);
  124. #[derive(Debug, Clone, Copy)]
  125. pub struct BoardPossible([Bits; MAX_SIZE as usize]);
  126. /*
  127. I probably should keep board and possible separate from one another.
  128. Possible is only used when solving the puzzles, and only used by the
  129. logic solver. Not needed by brute-force.
  130. Ok, the problem is that the possible doesn't make any sense to be
  131. unlinked in any way from the board. I think they have to be together.
  132. */
  133. /*
  134. #[derive(Debug, Clone, Copy)]
  135. pub struct SudokuPossible {
  136. pub possible: [Possible; MAX_SIZE as usize];
  137. }
  138. */
  139. impl BoardPossible {
  140. /// Display the possibles.
  141. /// This should be in the Possible struct, not here.
  142. pub fn display(&self) {
  143. for y in 0..WIDTH {
  144. for x in 0..WIDTH {
  145. // print!("p={:?}", self.possible[pos(x, y) as usize]);
  146. let mut possible = String::new();
  147. for p in self.0[pos(x, y) as usize].iter() {
  148. // print!("{},", p);
  149. possible += format!("{},", p).as_str();
  150. }
  151. // for i in 0..SIZE {
  152. // let &pos = self.possible[pos(x, y) as usize];
  153. print!("({},{}):", x, y);
  154. // print!("{:20}", format!("{:?}", self.possible[pos(x, y) as usize]));
  155. print!("{:9}", possible);
  156. /*
  157. if pos == 0 {
  158. print!(" ");
  159. } else {
  160. print!("{}", pos);
  161. }
  162. */
  163. // }
  164. // print!(" ");
  165. }
  166. println!("");
  167. }
  168. }
  169. }
  170. #[derive(Debug, Clone, Copy)]
  171. pub struct Sudoku {
  172. pub board: [u8; MAX_SIZE as usize], // Board
  173. pub possible: [Bits; MAX_SIZE as usize], // BoardPossible
  174. }
  175. /// Translate x,y to position in board.
  176. pub const fn pos(x: u8, y: u8) -> u8 {
  177. x + (y * WIDTH as u8)
  178. }
  179. /// Translate x,y (with starting index of 1) to position in board.
  180. pub const fn pos1(x: u8, y: u8) -> u8 {
  181. (x - 1) + ((y - 1) * WIDTH as u8)
  182. }
  183. /// Translate post to x,y in board.
  184. pub const fn xy(pos: u8) -> (u8, u8) {
  185. ((pos % WIDTH), (pos / WIDTH))
  186. }
  187. const DEBUG_OUTPUT: bool = false;
  188. /*
  189. (0 .. 10)
  190. .map(|_| HashSet::<usize>::new())
  191. .collect();
  192. let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
  193. */
  194. impl Sudoku {
  195. pub fn new() -> Self {
  196. // 10 = WIDTH + 1
  197. // This would need to be changed in order to handle 4x4 or 5x5.
  198. // NOTE: We ignore bit 0, we use bits 1-9 (for 3x3).
  199. let mut initial: Bits = Bits(set_bits(10));
  200. initial.set(0, false);
  201. let s = Sudoku {
  202. board: [0; MAX_SIZE as usize],
  203. possible: [initial; MAX_SIZE as usize],
  204. };
  205. s
  206. }
  207. pub fn clear_possible(&mut self) {
  208. let mut initial = Bits(set_bits(10));
  209. initial.set(0, false);
  210. self.possible = [initial; MAX_SIZE as usize];
  211. }
  212. pub fn clear(&mut self) {
  213. let mut initial = Bits(set_bits(10));
  214. initial.set(0, false);
  215. self.board = [0; MAX_SIZE as usize];
  216. self.possible = [initial; MAX_SIZE as usize];
  217. }
  218. /// Load puzzle from a string.
  219. /// Note, we load from (top,left) going down, to (bottom,left) by columns.
  220. pub fn load_from_tld(&mut self, start_ch: char, blank: char, s: &str) {
  221. self.clear();
  222. let mut x: u8 = 0;
  223. let mut y: u8 = 0;
  224. for ch in s.chars() {
  225. if ch != blank {
  226. self.set(x, y, (ch as u8 - start_ch as u8) + 1);
  227. }
  228. y += 1;
  229. if y >= WIDTH {
  230. y = 0;
  231. x += 1;
  232. }
  233. }
  234. }
  235. /// Load puzzle from a string.
  236. /// This loads from (top,left) going right, to (top,right), by rows.
  237. pub fn load_from_tlr(&mut self, start_ch: char, blank: char, s: &str) {
  238. self.clear();
  239. let mut i: u8 = 0;
  240. for ch in s.chars() {
  241. if ch != blank {
  242. self.set(xy(i).0, xy(i).1, (ch as u8 - start_ch as u8) + 1);
  243. }
  244. i += 1;
  245. }
  246. }
  247. pub fn save_to_tld(&self, mut start_ch: char, blank: char) -> String {
  248. let mut result = String::new();
  249. result.reserve(MAX_SIZE as usize);
  250. start_ch = (start_ch as u8 - 1) as char;
  251. let mut x: u8 = 0;
  252. let mut y: u8 = 0;
  253. for _i in 0..MAX_SIZE {
  254. if self.board[pos(x, y) as usize] == 0 {
  255. result.push(blank);
  256. } else {
  257. result.push((start_ch as u8 + self.board[pos(x,y) as usize]) as char);
  258. }
  259. y += 1;
  260. if y >= WIDTH {
  261. y = 0;
  262. x += 1;
  263. }
  264. }
  265. result
  266. }
  267. pub fn save_to_tlr(&self, mut start_ch: char, blank: char) -> String {
  268. let mut result = String::new();
  269. result.reserve(MAX_SIZE as usize);
  270. start_ch = (start_ch as u8 - 1) as char;
  271. for i in 0..MAX_SIZE {
  272. if self.board[i as usize] == 0 {
  273. result.push(blank);
  274. } else {
  275. result.push((start_ch as u8 + self.board[i as usize]) as char);
  276. }
  277. }
  278. result
  279. }
  280. pub fn get(&self, x:u8, y:u8) -> u8 {
  281. self.board[pos(x,y) as usize]
  282. }
  283. /*
  284. This set does more then it needs to.
  285. When setting a location, it also updates the possible.
  286. This needs to be moved into something else. Putting it into Possible?
  287. */
  288. pub fn set(&mut self, x: u8, y: u8, value: u8) {
  289. self.board[pos(x, y) as usize] = value;
  290. // Ok, update the possible
  291. let mut g = for_row(y);
  292. // g.for_row(x, y);
  293. for g in g.0 {
  294. // remove value from these sets.
  295. self.possible[g as usize].set(value, false);
  296. // self.possible[g as usize].take(&value);
  297. }
  298. g = for_column(x);
  299. // g.for_column(x, y);
  300. for g in g.0 {
  301. // remove value from these sets.
  302. self.possible[g as usize].set(value, false);
  303. // self.possible[g as usize].take(&value);
  304. }
  305. g = for_cell(which_cell(x, y));
  306. // g.for_block(x, y);
  307. for g in g.0 {
  308. // remove value from these sets.
  309. self.possible[g as usize].set(value, false);
  310. // self.possible[g as usize].take(&value);
  311. }
  312. self.possible[pos(x, y) as usize].clear();
  313. }
  314. /// Reset the Possible
  315. /// - For when a new puzzle has been loaded.
  316. /// - When something has changed, and the possibles are out of sync.
  317. pub fn reset_possible(&mut self) {
  318. // Reset the possible.
  319. self.clear_possible();
  320. for y in 0..WIDTH {
  321. for x in 0..WIDTH {
  322. let item: u8 = self.board[pos(x as u8, y as u8) as usize];
  323. if item != 0 {
  324. let mut g: &Group = for_row(y);
  325. for g in g.0 {
  326. self.possible[g as usize].set(item, false);
  327. }
  328. g = for_column(x);
  329. for g in g.0 {
  330. self.possible[g as usize].set(item, false);
  331. }
  332. g = for_cell(which_cell(x,y));
  333. for g in g.0 {
  334. self.possible[g as usize].set(item, false);
  335. }
  336. self.possible[pos(x,y) as usize].clear();
  337. }
  338. }
  339. }
  340. }
  341. /// Display the sudoku puzzle.
  342. pub fn display(&self) {
  343. println!("╔═══╦═══╦═══╗");
  344. for y in 0..WIDTH {
  345. print!("║");
  346. for x in 0..WIDTH {
  347. let item = self.board[pos(x as u8, y as u8) as usize];
  348. if item == 0 {
  349. print!(" ");
  350. } else if (item >= 1) && (item <= 9) {
  351. print!("{}", item);
  352. }
  353. if x % 3 == 2 {
  354. print!("║");
  355. }
  356. }
  357. println!("");
  358. if y % 3 == 2 {
  359. if y + 1 == WIDTH {
  360. println!("╚═══╩═══╩═══╝");
  361. } else {
  362. println!("╠═══╬═══╬═══╣");
  363. }
  364. }
  365. }
  366. }
  367. /// Display the possibles.
  368. /// This should be in the Possible struct, not here.
  369. pub fn display_possible(&self) {
  370. for y in 0..WIDTH {
  371. for x in 0..WIDTH {
  372. // print!("p={:?}", self.possible[pos(x, y) as usize]);
  373. let mut possible = String::new();
  374. for p in self.possible[pos(x, y) as usize].iter() {
  375. // print!("{},", p);
  376. possible += format!("{},", p).as_str();
  377. }
  378. // for i in 0..SIZE {
  379. // let &pos = self.possible[pos(x, y) as usize];
  380. print!("({},{}):", x, y);
  381. // print!("{:20}", format!("{:?}", self.possible[pos(x, y) as usize]));
  382. print!("{:9}", possible);
  383. /*
  384. if pos == 0 {
  385. print!(" ");
  386. } else {
  387. print!("{}", pos);
  388. }
  389. */
  390. // }
  391. // print!(" ");
  392. }
  393. println!("");
  394. }
  395. }
  396. /// Is the puzzle complete?
  397. /// Have all of the locations been filled with a value?
  398. /// - This does not validate that it is a correct puzzle,
  399. /// - It doesn't check for duplicate digits (for example).
  400. pub fn puzzle_complete(&self) -> bool {
  401. for i in 0..MAX_SIZE {
  402. if self.board[i as usize] == 0 {
  403. return false;
  404. }
  405. }
  406. true
  407. }
  408. /// Recursive brute-force solver
  409. /// - As possibilities are tried, it recursively calls itself to see
  410. /// if there are any solutions with the given possibility.
  411. fn calculate_possible(&mut self, total_solutions: &mut u16, solutions: &mut Vec<SudokuBoard>) -> bool {
  412. for idx in 0..MAX_SIZE {
  413. if self.board[idx as usize] == 0 {
  414. // Ok, there's a blank here
  415. let (x, y) = xy(idx);
  416. if DEBUG_OUTPUT {
  417. println!("idx={} ({},{})", idx, x, y);
  418. self.display();
  419. }
  420. 'outer: for possible in 1..=9 {
  421. let mut g = for_row(y);
  422. for p in g.0 {
  423. if self.board[p as usize] == possible {
  424. continue 'outer;
  425. }
  426. }
  427. g = for_column(x);
  428. for p in g.0 {
  429. if self.board[p as usize] == possible {
  430. continue 'outer;
  431. }
  432. }
  433. // check cell
  434. let cell = which_cell(x, y);
  435. g = for_cell(cell);
  436. for p in g.0 {
  437. if self.board[p as usize] == possible {
  438. continue 'outer;
  439. }
  440. }
  441. // Ok, it could go here!
  442. if DEBUG_OUTPUT {
  443. println!("({},{})={}", x, y, possible);
  444. }
  445. self.board[idx as usize] = possible;
  446. if self.puzzle_complete() {
  447. if *total_solutions < solutions.capacity() as u16 {
  448. solutions.push(self.board);
  449. }
  450. *total_solutions += 1;
  451. /*
  452. println!("**SOLUTION**");
  453. self.display();
  454. println!("***");
  455. */
  456. break;
  457. } else {
  458. if self.calculate_possible(total_solutions, solutions) {
  459. return true;
  460. }
  461. }
  462. }
  463. self.board[idx as usize] = 0;
  464. return false;
  465. }
  466. }
  467. false
  468. }
  469. /// Brute-force solver
  470. /// - Prints out a (one) solution.
  471. /// - Returns the number of solutions found.
  472. pub fn bruteforce_solver(&self) -> u16 {
  473. let mut workset = Sudoku {
  474. board: self.board,
  475. possible: [Bits(0); MAX_SIZE as usize],
  476. };
  477. let mut total_solutions: u16 = 0;
  478. let mut solutions = Vec::new();
  479. solutions.reserve(1);
  480. workset.calculate_possible(&mut total_solutions, &mut solutions);
  481. // return number of solutions.
  482. if solutions.len() > 0 {
  483. println!("*** A solution:");
  484. workset.board = solutions[0];
  485. workset.display();
  486. println!("***");
  487. }
  488. total_solutions
  489. }
  490. /// Make a sudoku puzzle.
  491. /// This gives us a fully solved puzzle.
  492. pub fn make(&mut self) {
  493. let mut rng = ChaCha20Rng::from_entropy();
  494. self.fill_board(&mut rng);
  495. // Ok, this gives us a random (but fully solved) puzzle.
  496. }
  497. /// Fill puzzle with random
  498. /// - This is like the brute-force solver, it calls itself recursively
  499. /// and backtraces if a solution can't be found.
  500. fn fill_board(&mut self, rng: &mut ChaCha20Rng) -> bool {
  501. let backup = Sudoku {
  502. board: self.board,
  503. possible: self.possible,
  504. };
  505. for idx in 0..MAX_SIZE {
  506. if self.board[idx as usize] == 0 {
  507. let (x, y) = xy(idx);
  508. let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
  509. let mut total_available: u8 = 0;
  510. for t in self.possible[idx as usize].iter() {
  511. available[total_available as usize] = t;
  512. total_available += 1;
  513. }
  514. if total_available == 0 {
  515. // No possible moves remain.
  516. /*
  517. self.board = backup.board;
  518. self.possible = backup.possible;
  519. */
  520. return false;
  521. }
  522. // Randomize the possible items.
  523. available[0..total_available as usize].shuffle(rng);
  524. for v_idx in 0..total_available {
  525. let value = available[v_idx as usize];
  526. self.set(x, y, value);
  527. if self.fill_board(rng) {
  528. return true;
  529. }
  530. // failure
  531. self.board = backup.board;
  532. self.possible = backup.possible;
  533. }
  534. // We've run out of possible.
  535. return false;
  536. }
  537. }
  538. // We've visited everything, and it isn't 0.
  539. return true;
  540. }
  541. /// Puzzle generation
  542. /// - Removes a number, tests to see if the puzzle can still be solved by logic.
  543. /// - Returns true when still a valid, solvable puzzle.
  544. /// - Otherwise, restores number and returns false.
  545. pub fn remove(&mut self) -> bool {
  546. // Find a number, remove it. Save position.
  547. let mut rng = ChaCha20Rng::from_entropy();
  548. let puzrange = Uniform::new(0, WIDTH);
  549. let mut x = 0;
  550. let mut y = 0;
  551. let mut value: u8 = 0;
  552. while value == 0 {
  553. x = puzrange.sample(&mut rng);
  554. y = puzrange.sample(&mut rng);
  555. value = self.get(x,y);
  556. }
  557. self.set(x,y,0);
  558. // Clone, and solve by logic.
  559. let mut puzcopy = self.clone();
  560. puzcopy.reset_possible();
  561. /*
  562. puzcopy.display();
  563. puzcopy.display_possible();
  564. */
  565. // If solvable, return true.
  566. while puzcopy.solve(false) {};
  567. /*
  568. puzcopy.display();
  569. puzcopy.display_possible();
  570. */
  571. if puzcopy.puzzle_complete() {
  572. return true;
  573. }
  574. // If not solvable, restore number, return false.
  575. self.set(x,y,value);
  576. return false;
  577. }
  578. /*
  579. fn make_(&mut self) {
  580. self.clear();
  581. let mut rng = ChaCha20Rng::from_entropy();
  582. let pick_one = |this: &Self, rng: &mut ChaCha20Rng, idx: u8| -> Option<u8> {
  583. let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
  584. let mut total_available: u8 = 0;
  585. for t in this.possible[idx as usize].iter() {
  586. available[total_available as usize] = t;
  587. total_available += 1;
  588. }
  589. if total_available == 1 {
  590. return Some(available[0]);
  591. }
  592. if total_available == 0 {
  593. return None;
  594. }
  595. Some(available[rng.gen_range(0..total_available as usize)])
  596. };
  597. for i in 0..MAX_SIZE {
  598. let (x, y) = xy(i);
  599. if self.board[i as usize] == 0 {
  600. // Ok, we found a blank space.
  601. let value = pick_one(self, &mut rng, i);
  602. if value.is_some() {
  603. let value = value.unwrap();
  604. if DEBUG_OUTPUT {
  605. println!("Set({},{})={}", x, y, value);
  606. }
  607. self.set(x, y, value);
  608. }
  609. }
  610. }
  611. }
  612. */
  613. /// Solve, using logic alone
  614. /// - Returns true when something was added to the board.
  615. /// - Call solve until it returns false.
  616. pub fn solve(&mut self, debug: bool) -> bool {
  617. // Pass 1: Look for singles in the possible sets.
  618. let mut found_something = false;
  619. for i in 0..MAX_SIZE {
  620. if self.possible[i as usize].count_set() == 1 {
  621. // Get the value
  622. let value = self.possible[i as usize].iter().next().unwrap();
  623. // Found one!
  624. if debug {
  625. println!("Set1 {:?} to {}", xy(i), value);
  626. }
  627. self.set(xy(i).0, xy(i).1, value);
  628. found_something = true;
  629. }
  630. }
  631. let mut g = Group::new();
  632. let mut values = Bits(0); // HashSet<u8> = HashSet::new();
  633. let mut group_process = |this: &mut Self, grp: &Group| {
  634. // Collect all the possible values within the group.
  635. values.clear();
  636. for gidx in 0..WIDTH {
  637. // println!("possible: {:?}", this.possible[grp.items[gidx as usize] as usize]);
  638. for v in this.possible[grp.0[gidx as usize] as usize].iter() {
  639. values.set(v, true);
  640. }
  641. // values.extend(this.possible[grp.0[gidx as usize] as usize]);
  642. // println!("now : {:?}", this.possible[grp.items[gidx as usize] as usize]);
  643. }
  644. // println!("values {:?}", values);
  645. // Now, check for singles.
  646. for v in values.iter() {
  647. let mut count = 0;
  648. let mut pos = 0;
  649. for gidx in 0..WIDTH {
  650. if this.possible[grp.0[gidx as usize] as usize].get(v) {
  651. // if this.possible[grp.0[gidx as usize] as usize].contains(&v) {
  652. count += 1;
  653. pos = grp.0[gidx as usize];
  654. if count > 1 {
  655. break;
  656. }
  657. }
  658. }
  659. if count == 1 {
  660. // don't need this, it was v!
  661. // let value = this.possible[pos as usize].iter().next().cloned().unwrap();
  662. if debug {
  663. println!("Set2 {:?} to {}", xy(pos), v);
  664. }
  665. this.set(xy(pos).0, xy(pos).1, v);
  666. found_something = true;
  667. }
  668. }
  669. };
  670. // Change to 0..WIDTH ... Keep it simple.
  671. for i in 0..WIDTH {
  672. let mut g = for_column(i);
  673. // g.for_column(i, 1);
  674. group_process(self, &g);
  675. g = for_row(i);
  676. // g.for_row(1, i);
  677. group_process(self, &g);
  678. g = for_cell(i);
  679. // g.for_iter(i);
  680. group_process(self, &g);
  681. }
  682. if found_something {
  683. return found_something;
  684. }
  685. if debug {
  686. println!("Looking for pairs...");
  687. }
  688. // PAIR processing.
  689. for i in 0..WIDTH {
  690. g.for_iter(i);
  691. for gidx in 0..WIDTH - 1 {
  692. let gpos = g.0[gidx as usize];
  693. if self.possible[gpos as usize].count_set() == 2 {
  694. // Found a pair
  695. for fidx in gidx + 1..WIDTH {
  696. let fpos = g.0[fidx as usize];
  697. if self.possible[fpos as usize].count_set() == 2 {
  698. // Ok, there's another pair
  699. // if self.possible[gpos as usize].is_subset(&self.possible[fpos as usize])
  700. if self.possible[gpos as usize] == self.possible[fpos as usize] {
  701. // Ok, they have the same values!
  702. // Ok, remove the items in the pair from the cell.
  703. // Don't touch the gpos/fpos records. Keep those!
  704. let mut values: [u8; 2] = [0, 0];
  705. let mut vpos = 0;
  706. for z in self.possible[gpos as usize].iter() {
  707. values[vpos] = z;
  708. vpos += 1;
  709. }
  710. let mut pair_removed = false;
  711. // Check to see if anything was removed.
  712. for remove in 0..WIDTH {
  713. if (gidx == remove) || (fidx == remove) {
  714. continue;
  715. }
  716. // Ok, these aren't the ones to save, so:
  717. let rpos = g.0[remove as usize];
  718. if self.possible[rpos as usize].get(values[0]) {
  719. self.possible[rpos as usize].set(values[0], false);
  720. found_something = true;
  721. pair_removed = true;
  722. }
  723. if self.possible[rpos as usize].get(values[1]) {
  724. self.possible[rpos as usize].set(values[1], false);
  725. found_something = true;
  726. pair_removed = true;
  727. }
  728. }
  729. // Check the x's and y's to see if we can also process a row/column too.
  730. if xy(gpos).0 == xy(fpos).0 {
  731. // Matching X - process column
  732. let column = xy(gpos).0;
  733. vpos = 0;
  734. for z in self.possible[gpos as usize].iter() {
  735. values[vpos] = z;
  736. vpos += 1;
  737. }
  738. for remove in 0..WIDTH {
  739. if (remove == xy(gpos).1) || (remove == xy(fpos).1) {
  740. continue;
  741. }
  742. if self.possible[pos(column, remove) as usize]
  743. .get(values[0])
  744. {
  745. self.possible[pos(column, remove) as usize]
  746. .set(values[0], false);
  747. found_something = true;
  748. pair_removed = true;
  749. }
  750. if self.possible[pos(column, remove) as usize]
  751. .get(values[1])
  752. {
  753. self.possible[pos(column, remove) as usize]
  754. .set(values[1], false);
  755. found_something = true;
  756. pair_removed = true;
  757. }
  758. }
  759. }
  760. if xy(gpos).1 == xy(fpos).1 {
  761. // Matching Y - process row
  762. let row = xy(gpos).1;
  763. vpos = 0;
  764. for z in self.possible[gpos as usize].iter() {
  765. values[vpos] = z;
  766. vpos += 1;
  767. }
  768. for remove in 0..WIDTH {
  769. if (remove == xy(gpos).0) || (remove == xy(fpos).0) {
  770. continue;
  771. }
  772. if self.possible[pos(remove, row) as usize].get(values[0]) {
  773. self.possible[pos(remove, row) as usize]
  774. .set(values[0], false);
  775. found_something = true;
  776. pair_removed = true;
  777. }
  778. if self.possible[pos(remove, row) as usize].get(values[1]) {
  779. self.possible[pos(remove, row) as usize]
  780. .set(values[1], false);
  781. found_something = true;
  782. pair_removed = true;
  783. }
  784. }
  785. }
  786. if pair_removed {
  787. if debug {
  788. println!(
  789. "Pair found! {} {}: {} {:?} and {} {:?} !",
  790. gidx,
  791. fidx,
  792. gpos,
  793. xy(gpos),
  794. fpos,
  795. xy(fpos)
  796. );
  797. }
  798. }
  799. }
  800. }
  801. }
  802. }
  803. }
  804. }
  805. found_something
  806. }
  807. }