|
@@ -1,3 +1,11 @@
|
|
|
+//! Sudoku creator and solver.
|
|
|
+//!
|
|
|
+//! This handles boards 9x9, 16x16 and 25x25.
|
|
|
+//!
|
|
|
+//! AnyBoard contains the sudoku board.
|
|
|
+//! AnyPossible tracks possibilities where values can go on the board.
|
|
|
+//! AnySolver solves sudoku AnyBoard.
|
|
|
+
|
|
|
// pub mod group;
|
|
|
use crate::bits::*;
|
|
|
use crate::group::*;
|
|
@@ -451,9 +459,51 @@ impl AnyBoard {
|
|
|
}
|
|
|
false
|
|
|
}
|
|
|
+
|
|
|
+ /// Flip board X and Y
|
|
|
+ pub fn flip(&mut self) {
|
|
|
+ let temp = self.clone();
|
|
|
+ for x in 0..self.width {
|
|
|
+ for y in 0..self.width {
|
|
|
+ self[(x, y)] = temp[(y, x)]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Flip board around X
|
|
|
+ pub fn flip_x(&mut self) {
|
|
|
+ let mut temp = vec![0; self.width as usize];
|
|
|
+
|
|
|
+ for y in 0..self.width {
|
|
|
+ for x in 0..self.width {
|
|
|
+ temp[x as usize] = self[(x, y)];
|
|
|
+ }
|
|
|
+ for x in 0..self.width {
|
|
|
+ self[(x, y)] = temp[self.width as usize - 1 - x as usize];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Flip board around Y
|
|
|
+ pub fn flip_y(&mut self) {
|
|
|
+ let mut temp = vec![0; self.width as usize];
|
|
|
+
|
|
|
+ for x in 0..self.width {
|
|
|
+ for y in 0..self.width {
|
|
|
+ temp[y as usize] = self[(x, y)];
|
|
|
+ }
|
|
|
+ for y in 0..self.width {
|
|
|
+ self[(x, y)] = temp[self.width as usize - 1 - y as usize];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+//
|
|
|
// Ok! This is interesting:
|
|
|
+//
|
|
|
+// This allows you to index the board by (u8,u8) or usize.
|
|
|
+//
|
|
|
|
|
|
use std::ops::{Index, IndexMut};
|
|
|
|
|
@@ -1183,7 +1233,6 @@ impl AnySolver {
|
|
|
self.possible.display();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
let cell_start = self.group.cell_start(last_cell_found);
|
|
|
let found_x = self.board.xy(col_found).0;
|
|
|
if OUTPUT {
|
|
@@ -1220,7 +1269,6 @@ impl AnySolver {
|
|
|
self.possible.display();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2682,7 +2730,10 @@ mod tests {
|
|
|
solver.possible.display();
|
|
|
println!("Pairs: {:?}", pairs);
|
|
|
// let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![(vec![0, 1, 2], vec![2, 3, 4])];
|
|
|
- let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![(vec![3,4,5,6,7,8],vec![0,1,5,6,7,8]),(vec![0, 1, 2], vec![2, 3, 4])];
|
|
|
+ let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![
|
|
|
+ (vec![3, 4, 5, 6, 7, 8], vec![0, 1, 5, 6, 7, 8]),
|
|
|
+ (vec![0, 1, 2], vec![2, 3, 4]),
|
|
|
+ ];
|
|
|
assert_eq!(pairs.0, expected);
|
|
|
/*
|
|
|
(1,1):3,4,5 (2,1):3,4,5 (3,1):3,4,5 (4,1):1,2,6,7,8,9 (5,1):1,2,6,7,8,9 (6,1):1,2,6,7,8,9 (7,1):1,2,6,7,8,9 (8,1):1,2,6,7,8,9 (9,1):1,2,6,7,8,9
|
|
@@ -2979,13 +3030,325 @@ mod tests {
|
|
|
println!("Pairs [cell index 3]: {:?}", pairs);
|
|
|
// Pairs [cell index 3]: ([([0, 3, 6], [2, 3, 4])], true)
|
|
|
// [1, 2, 4, 5, 7, 8], [0, 1, 5, 6, 7, 8]
|
|
|
- let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![(vec![1,2,4,5,7,8],vec![0,1,5,6,7,8]),(vec![0, 3, 6], vec![2, 3, 4])];
|
|
|
+ let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![
|
|
|
+ (vec![1, 2, 4, 5, 7, 8], vec![0, 1, 5, 6, 7, 8]),
|
|
|
+ (vec![0, 3, 6], vec![2, 3, 4]),
|
|
|
+ ];
|
|
|
assert_eq!(pairs.0, expected);
|
|
|
|
|
|
// solver.finalize_cell(3);
|
|
|
// solver.possible.display();
|
|
|
}
|
|
|
|
|
|
+ #[test]
|
|
|
+ fn flip_board_test() {
|
|
|
+ let mut base_board = AnyBoard::new(3);
|
|
|
+ let result = base_board.load_from_tld(
|
|
|
+ 'b',
|
|
|
+ '_',
|
|
|
+ "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g",
|
|
|
+ );
|
|
|
+
|
|
|
+ assert!(result.is_ok());
|
|
|
+ // Clone the board here, I want to modify it with flip calls.
|
|
|
+
|
|
|
+ let mut board = base_board.clone();
|
|
|
+ let strings = board.to_strings();
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ " 17 83 ",
|
|
|
+ " 73 68 ",
|
|
|
+ "2 9 4 1",
|
|
|
+ " 1 7 ",
|
|
|
+ " 2 9 ",
|
|
|
+ " 14 86 ",
|
|
|
+ " 83 19 ",
|
|
|
+ " ",
|
|
|
+ "4 2 5 6"
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║ 1║7 8║3 ║
|
|
|
+ ║ 73║ ║68 ║
|
|
|
+ ║2 ║9 4║ 1║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║ ║1 7║ ║
|
|
|
+ ║ 2 ║ ║ 9 ║
|
|
|
+ ║ 14║ ║86 ║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║ 8║3 1║9 ║
|
|
|
+ ║ ║ ║ ║
|
|
|
+ ║4 2║ ║5 6║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ let mut solver = AnySolver::new_from(&board);
|
|
|
+ assert!(solver.validate_board());
|
|
|
+
|
|
|
+ solver.reset_possible();
|
|
|
+
|
|
|
+ if !solver.solve_logic() {
|
|
|
+ println!("Failed to solve by logic!");
|
|
|
+ solver.board.display();
|
|
|
+ }
|
|
|
+ solver.board.display();
|
|
|
+
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║541║768║329║
|
|
|
+ ║973║512║684║
|
|
|
+ ║286║934║751║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║869║157║243║
|
|
|
+ ║325║486║197║
|
|
|
+ ║714║293║865║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║658║341║972║
|
|
|
+ ║197║625║438║
|
|
|
+ ║432║879║516║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ assert!(solver.board.complete());
|
|
|
+
|
|
|
+ let strings = solver.board.to_strings();
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ "541768329",
|
|
|
+ "973512684",
|
|
|
+ "286934751",
|
|
|
+ "869157243",
|
|
|
+ "325486197",
|
|
|
+ "714293865",
|
|
|
+ "658341972",
|
|
|
+ "197625438",
|
|
|
+ "432879516"
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ // Reset the board, flip it, and try this again!
|
|
|
+
|
|
|
+ board.copy(&base_board);
|
|
|
+ board.flip();
|
|
|
+ let strings = board.to_strings();
|
|
|
+ board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║ 2║ ║ 4║
|
|
|
+ ║ 7 ║ 21║ ║
|
|
|
+ ║13 ║ 4║8 2║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║7 9║1 ║3 ║
|
|
|
+ ║ ║ ║ ║
|
|
|
+ ║8 4║7 ║1 ║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║36 ║ 8║9 5║
|
|
|
+ ║ 8 ║ 96║ ║
|
|
|
+ ║ 1║ ║ 6║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ " 2 4",
|
|
|
+ " 7 21 ",
|
|
|
+ "13 48 2",
|
|
|
+ "7 91 3 ",
|
|
|
+ " ",
|
|
|
+ "8 47 1 ",
|
|
|
+ "36 89 5",
|
|
|
+ " 8 96 ",
|
|
|
+ " 1 6",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ let mut solver = AnySolver::new_from(&board);
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ solver.reset_possible();
|
|
|
+ if !solver.solve_logic() {
|
|
|
+ println!("Failed to solve by logic!");
|
|
|
+ solver.board.display();
|
|
|
+ }
|
|
|
+ solver.board.display();
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ assert!(solver.board.complete());
|
|
|
+
|
|
|
+ let strings = solver.board.to_strings();
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ "592837614",
|
|
|
+ "478621593",
|
|
|
+ "136954872",
|
|
|
+ "759142368",
|
|
|
+ "613589427",
|
|
|
+ "824763159",
|
|
|
+ "367218945",
|
|
|
+ "285496731",
|
|
|
+ "941375286",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ // Reset the board, flip it, and try this again!
|
|
|
+
|
|
|
+ board.copy(&base_board);
|
|
|
+ board.flip_x();
|
|
|
+ let strings = board.to_strings();
|
|
|
+ board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║ 3║8 7║1 ║
|
|
|
+ ║ 86║ ║37 ║
|
|
|
+ ║1 ║4 9║ 2║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║ ║7 1║ ║
|
|
|
+ ║ 9 ║ ║ 2 ║
|
|
|
+ ║ 68║ ║41 ║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║ 9║1 3║8 ║
|
|
|
+ ║ ║ ║ ║
|
|
|
+ ║6 5║ ║2 4║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ " 38 71 ",
|
|
|
+ " 86 37 ",
|
|
|
+ "1 4 9 2",
|
|
|
+ " 7 1 ",
|
|
|
+ " 9 2 ",
|
|
|
+ " 68 41 ",
|
|
|
+ " 91 38 ",
|
|
|
+ " ",
|
|
|
+ "6 5 2 4",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ let mut solver = AnySolver::new_from(&board);
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ solver.reset_possible();
|
|
|
+ if !solver.solve_logic() {
|
|
|
+ println!("Failed to solve by logic!");
|
|
|
+ solver.board.display();
|
|
|
+ }
|
|
|
+ solver.board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║923║867║145║
|
|
|
+ ║486║215║379║
|
|
|
+ ║157║439║682║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║342║751║968║
|
|
|
+ ║791║684║523║
|
|
|
+ ║568║392║417║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║279║143║856║
|
|
|
+ ║834║526║791║
|
|
|
+ ║615║978║234║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ assert!(solver.board.complete());
|
|
|
+
|
|
|
+ let strings = solver.board.to_strings();
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ "923867145",
|
|
|
+ "486215379",
|
|
|
+ "157439682",
|
|
|
+ "342751968",
|
|
|
+ "791684523",
|
|
|
+ "568392417",
|
|
|
+ "279143856",
|
|
|
+ "834526791",
|
|
|
+ "615978234",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ // Reset the board, flip it, and try this again!
|
|
|
+
|
|
|
+ board.copy(&base_board);
|
|
|
+ board.flip_y();
|
|
|
+ let strings = board.to_strings();
|
|
|
+ board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║4 2║ ║5 6║
|
|
|
+ ║ ║ ║ ║
|
|
|
+ ║ 8║3 1║9 ║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║ 14║ ║86 ║
|
|
|
+ ║ 2 ║ ║ 9 ║
|
|
|
+ ║ ║1 7║ ║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║2 ║9 4║ 1║
|
|
|
+ ║ 73║ ║68 ║
|
|
|
+ ║ 1║7 8║3 ║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ "4 2 5 6",
|
|
|
+ " ",
|
|
|
+ " 83 19 ",
|
|
|
+ " 14 86 ",
|
|
|
+ " 2 9 ",
|
|
|
+ " 1 7 ",
|
|
|
+ "2 9 4 1",
|
|
|
+ " 73 68 ",
|
|
|
+ " 17 83 ",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ let mut solver = AnySolver::new_from(&board);
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ solver.reset_possible();
|
|
|
+ if !solver.solve_logic() {
|
|
|
+ println!("Failed to solve by logic!");
|
|
|
+ solver.board.display();
|
|
|
+ }
|
|
|
+ solver.board.display();
|
|
|
+ /*
|
|
|
+ ╔═══╦═══╦═══╗
|
|
|
+ ║432║879║516║
|
|
|
+ ║197║625║438║
|
|
|
+ ║658║341║972║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║714║293║865║
|
|
|
+ ║325║486║197║
|
|
|
+ ║869║157║243║
|
|
|
+ ╠═══╬═══╬═══╣
|
|
|
+ ║286║934║751║
|
|
|
+ ║973║512║684║
|
|
|
+ ║541║768║329║
|
|
|
+ ╚═══╩═══╩═══╝
|
|
|
+ */
|
|
|
+ assert!(solver.validate_board());
|
|
|
+ assert!(solver.board.complete());
|
|
|
+
|
|
|
+ let strings = solver.board.to_strings();
|
|
|
+ assert_eq!(
|
|
|
+ strings,
|
|
|
+ vec![
|
|
|
+ "432879516",
|
|
|
+ "197625438",
|
|
|
+ "658341972",
|
|
|
+ "714293865",
|
|
|
+ "325486197",
|
|
|
+ "869157243",
|
|
|
+ "286934751",
|
|
|
+ "973512684",
|
|
|
+ "541768329",
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
10/13/2024
|
|
|
This assumes the solver is working correctly.
|