Initial cell restrictions and url print.
This commit is contained in:
		
							parent
							
								
									338309fde6
								
							
						
					
					
						commit
						9901c6832f
					
				|  | @ -2,6 +2,15 @@ | |||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bitmaps" | ||||
| version = "3.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "sudoku-solver" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "bitmaps", | ||||
| ] | ||||
|  |  | |||
|  | @ -6,3 +6,4 @@ edition = "2021" | |||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| bitmaps = "3.*" | ||||
|  |  | |||
							
								
								
									
										131
									
								
								src/board.rs
								
								
								
								
							
							
						
						
									
										131
									
								
								src/board.rs
								
								
								
								
							|  | @ -1,37 +1,11 @@ | |||
| use std::fmt::{self, Write}; | ||||
| 
 | ||||
| pub enum Square { | ||||
|     Value(u8), | ||||
|     Options(Vec<u8>), | ||||
| } | ||||
| 
 | ||||
| impl Square { | ||||
|     pub fn from_char(c: char) -> Square { | ||||
|         match c { | ||||
|             '1' => Square::Value(1), | ||||
|             '2' => Square::Value(2), | ||||
|             '3' => Square::Value(3), | ||||
|             '4' => Square::Value(4), | ||||
|             '5' => Square::Value(5), | ||||
|             '6' => Square::Value(6), | ||||
|             '7' => Square::Value(7), | ||||
|             '8' => Square::Value(8), | ||||
|             '9' => Square::Value(9), | ||||
|             '.' => Square::Options(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]), | ||||
|             _ => panic!("Unexpected character in input: {}", c), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn to_str(&self) -> String { | ||||
|         match self { | ||||
|             Square::Options(_) => " ".to_string(), | ||||
|             Square::Value(v) => v.to_string(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| use crate::iterators::SquareIter; | ||||
| use crate::square::Square; | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Board { | ||||
|     squares: Vec<Square>, | ||||
|     squares: [Square; 81], | ||||
| } | ||||
| 
 | ||||
| impl Board { | ||||
|  | @ -41,9 +15,102 @@ impl Board { | |||
|         } | ||||
|         let mut squares = Vec::new(); | ||||
|         for c in str.chars() { | ||||
|             squares.push(Square::from_char(c)) | ||||
|             squares.push(Square::from_char(c)); | ||||
|         } | ||||
|         Board { squares } | ||||
|         let mut board = Board { | ||||
|             squares: squares.try_into().unwrap(), | ||||
|         }; | ||||
|         board.restrict_marks(); | ||||
|         board | ||||
|     } | ||||
| 
 | ||||
|     pub fn restrict_marks(&mut self) { | ||||
|         let self_copy = self.clone(); | ||||
|         for (index, ref mut square) in self.squares.iter_mut().enumerate() { | ||||
|             if let Square::Options(ref mut opt) = square { | ||||
|                 self_copy | ||||
|                     .row_from_index(index) | ||||
|                     .filter_map(|sq| match sq { | ||||
|                         Square::Value(x) => Some(x), | ||||
|                         _ => None, | ||||
|                     }) | ||||
|                     .for_each(|value| { | ||||
|                         opt.set((value - 1) as usize, false); | ||||
|                     }); | ||||
|                 self_copy | ||||
|                     .col_from_index(index) | ||||
|                     .filter_map(|sq| match sq { | ||||
|                         Square::Value(x) => Some(x), | ||||
|                         _ => None, | ||||
|                     }) | ||||
|                     .for_each(|value| { | ||||
|                         opt.set((value - 1) as usize, false); | ||||
|                     }); | ||||
|                 self_copy | ||||
|                     .box_from_index(index) | ||||
|                     .filter_map(|sq| match sq { | ||||
|                         Square::Value(x) => Some(x), | ||||
|                         _ => None, | ||||
|                     }) | ||||
|                     .for_each(|value| { | ||||
|                         opt.set((value - 1) as usize, false); | ||||
|                     }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn row_from_index(&self, index: usize) -> SquareIter { | ||||
|         SquareIter::from_row(&self.squares, index / 9) | ||||
|     } | ||||
| 
 | ||||
|     pub fn col_from_index(&self, index: usize) -> SquareIter { | ||||
|         SquareIter::from_col(&self.squares, index % 9) | ||||
|     } | ||||
| 
 | ||||
|     pub fn box_from_index(&self, index: usize) -> SquareIter { | ||||
|         let row = index / 27; | ||||
|         let col = (index % 9) / 3; | ||||
|         SquareIter::from_box(&self.squares, (row * 3) + col) | ||||
|     } | ||||
| 
 | ||||
|     fn url_puzzle_str(&self) -> String { | ||||
|         self.squares | ||||
|             .iter() | ||||
|             .map(|sq| match sq { | ||||
|                 Square::Value(x) => x.to_string(), | ||||
|                 _ => ".".to_string(), | ||||
|             }) | ||||
|             .fold(String::new(), |a, b| a + &b) | ||||
|     } | ||||
| 
 | ||||
|     fn url_marks_str(&self) -> String { | ||||
|         self.squares | ||||
|             .iter() | ||||
|             .map(|sq| match sq { | ||||
|                 Square::Options(opts) => { | ||||
|                     opts.into_iter() | ||||
|                         .map(|a| a + 1) | ||||
|                         .fold(String::new(), |mut a, b| { | ||||
|                             a.push_str(&b.to_string()); | ||||
|                             a | ||||
|                         }) | ||||
|                 } | ||||
|                 _ => String::new(), | ||||
|             }) | ||||
|             .fold(String::new(), |mut a, b| { | ||||
|                 a.push(','); | ||||
|                 a.push_str(&b); | ||||
|                 a | ||||
|             })[1..] | ||||
|             .to_string() | ||||
|     } | ||||
| 
 | ||||
|     pub fn to_url(&self) -> String { | ||||
|         format!( | ||||
|             "https://tiramisu.one/sudoku/?p={}&m={}", | ||||
|             self.url_puzzle_str(), | ||||
|             self.url_marks_str() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,87 @@ | |||
| use crate::square::Square; | ||||
| 
 | ||||
| fn to_row(squares: &[Square; 81], row: usize) -> [Square; 9] { | ||||
|     [ | ||||
|         squares[(9 * row) + 0].clone(), | ||||
|         squares[(9 * row) + 1].clone(), | ||||
|         squares[(9 * row) + 2].clone(), | ||||
|         squares[(9 * row) + 3].clone(), | ||||
|         squares[(9 * row) + 4].clone(), | ||||
|         squares[(9 * row) + 5].clone(), | ||||
|         squares[(9 * row) + 6].clone(), | ||||
|         squares[(9 * row) + 7].clone(), | ||||
|         squares[(9 * row) + 8].clone(), | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
| fn to_col(squares: &[Square; 81], col: usize) -> [Square; 9] { | ||||
|     [ | ||||
|         squares[(9 * 0) + col].clone(), | ||||
|         squares[(9 * 1) + col].clone(), | ||||
|         squares[(9 * 2) + col].clone(), | ||||
|         squares[(9 * 3) + col].clone(), | ||||
|         squares[(9 * 4) + col].clone(), | ||||
|         squares[(9 * 5) + col].clone(), | ||||
|         squares[(9 * 6) + col].clone(), | ||||
|         squares[(9 * 7) + col].clone(), | ||||
|         squares[(9 * 8) + col].clone(), | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
| static BOX_ROOTS: [usize; 9] = [0, 3, 6, 27, 30, 36, 54, 57, 60]; | ||||
| 
 | ||||
| fn to_box(squares: &[Square; 81], box_num: usize) -> [Square; 9] { | ||||
|     let root = BOX_ROOTS[box_num]; | ||||
|     [ | ||||
|         squares[root].clone(), | ||||
|         squares[root + 1].clone(), | ||||
|         squares[root + 2].clone(), | ||||
|         squares[root + 9].clone(), | ||||
|         squares[root + 10].clone(), | ||||
|         squares[root + 11].clone(), | ||||
|         squares[root + 18].clone(), | ||||
|         squares[root + 19].clone(), | ||||
|         squares[root + 20].clone(), | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
| pub struct SquareIter { | ||||
|     squares: [Square; 9], | ||||
|     curr: usize, | ||||
| } | ||||
| 
 | ||||
| impl SquareIter { | ||||
|     pub fn from_row(squares: &[Square; 81], row: usize) -> SquareIter { | ||||
|         SquareIter { | ||||
|             squares: to_row(squares, row), | ||||
|             curr: 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_col(squares: &[Square; 81], col: usize) -> SquareIter { | ||||
|         SquareIter { | ||||
|             squares: to_col(squares, col), | ||||
|             curr: 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_box(squares: &[Square; 81], boxn: usize) -> SquareIter { | ||||
|         SquareIter { | ||||
|             squares: to_box(squares, boxn), | ||||
|             curr: 0, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Iterator for SquareIter { | ||||
|     type Item = Square; | ||||
| 
 | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         if self.curr >= 9 { | ||||
|             None | ||||
|         } else { | ||||
|             self.curr += 1; | ||||
|             Some(self.squares[self.curr - 1].clone()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,4 +1,6 @@ | |||
| mod board; | ||||
| mod iterators; | ||||
| mod square; | ||||
| 
 | ||||
| fn main() { | ||||
|     let nyt_hard = "3...184.9\ | ||||
|  | @ -12,4 +14,5 @@ fn main() { | |||
|                     5........";
 | ||||
|     let sudoku_board = board::Board::from_string(nyt_hard); | ||||
|     println!("{:#?}", sudoku_board); | ||||
|     println!("{}", sudoku_board.to_url()); | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,32 @@ | |||
| use bitmaps::Bitmap; | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum Square { | ||||
|     Value(u8), | ||||
|     Options(Bitmap<9>), | ||||
| } | ||||
| 
 | ||||
| impl Square { | ||||
|     pub fn from_char(c: char) -> Square { | ||||
|         match c { | ||||
|             '1' => Square::Value(1), | ||||
|             '2' => Square::Value(2), | ||||
|             '3' => Square::Value(3), | ||||
|             '4' => Square::Value(4), | ||||
|             '5' => Square::Value(5), | ||||
|             '6' => Square::Value(6), | ||||
|             '7' => Square::Value(7), | ||||
|             '8' => Square::Value(8), | ||||
|             '9' => Square::Value(9), | ||||
|             '.' => Square::Options(Bitmap::mask(9)), | ||||
|             _ => panic!("Unexpected character in input: {}", c), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn to_str(&self) -> String { | ||||
|         match self { | ||||
|             Square::Options(_) => " ".to_string(), | ||||
|             Square::Value(v) => v.to_string(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue