diff --git a/benches/solver_benches.rs b/benches/solver_benches.rs index 9ce53a0..e99c23a 100644 --- a/benches/solver_benches.rs +++ b/benches/solver_benches.rs @@ -7,7 +7,7 @@ use sudoku::{ fn benchmarks(c: &mut Criterion) { let puzzle = random_sudoku_puzzle::, AdvancedSolver, f32>( - 45, 0.0, 1000.0, + 45, 80.0, 1000.0, ); let mut solver = StochasticSolver::::from(puzzle); c.bench_function("StochasticSolver", |b| { diff --git a/src/bin/example.rs b/src/bin/example.rs index a86968d..46042f3 100644 --- a/src/bin/example.rs +++ b/src/bin/example.rs @@ -5,15 +5,15 @@ use sudoku::{ techniques::{ hidden_pair_blk, hidden_pair_col, hidden_pair_row, hidden_single_blk, hidden_single_col, hidden_single_row, naked_pair_blk, naked_pair_col, naked_pair_row, naked_single, pointing, - }, Grid, + } }; fn main() { - let board = random_sudoku_puzzle::, AdvancedSolver, f32>( + let grid = random_sudoku_puzzle::, AdvancedSolver, f32>( 45, 140.0, 2000.0, ); - let puzzle = FullState::from(board); - println!("{}", Grid(board)); + let puzzle = FullState::from(grid); + println!("{}", grid); let res_hidden_single_row = hidden_single_row(&puzzle); let res_hidden_single_col = hidden_single_col(&puzzle); let res_hidden_single_blk = hidden_single_blk(&puzzle); @@ -36,7 +36,7 @@ fn main() { println!("naked pair in col: {:?}", res_naked_pair_col); println!("naked pair in blk: {:?}", res_naked_pair_blk); println!("pointing: {:?}", res_pointing); - let mut solver2 = AdvancedSolver::::from(board); + let mut solver2 = AdvancedSolver::::from(grid); solver2.have_unique_solution(); println!("{}", solver2.difficulty()); } diff --git a/src/generator.rs b/src/generator.rs index 6716a7e..213ca85 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -1,20 +1,22 @@ use rand::random; +use crate::Grid; + use super::solver::{Grader, Solver}; pub fn random_sudoku_puzzle( min_blank_cnt: i32, // 需要生成的题目最少空格数 min_difficulty: T, // 题目最小难度分数 max_difficulty: T, // 题目最大难度分数 -) -> [[i8; 9]; 9] +) -> Grid where - S1: Solver + From<[[i8; 9]; 9]>, - S2: Solver + Grader + From<[[i8; 9]; 9]>, + S1: Solver + From, + S2: Solver + Grader + From, T: PartialOrd + From { loop { // 生成随机终局 - let mut puzzle = S1::from([[0; 9]; 9]).any_solution().unwrap(); + let mut puzzle = S1::from(Grid([[0; 9]; 9])).any_solution().unwrap(); let mut dug = 0; // 已经挖掉的空格数 let mut trace = vec![]; // 挖空历史记录 @@ -25,7 +27,7 @@ where let mut trace_back_cnt = 0; // 回退的次数 let trace_back_cnt_threshold = 12; // 回退次数阈值,回退次数超过此值会尝试重新生成终局 - let mut difficulty: T = 0.into(); // 搜索函数在此题目上调用的次数 + let mut difficulty: T = 0.into(); // 难度分数 while trace_back_cnt < trace_back_cnt_threshold && !(dug >= min_blank_cnt @@ -41,11 +43,11 @@ where for _ in 0..step { // 随机选取非空格 let (mut r, mut c) = (random::() % 9, random::() % 9); - while puzzle[r][c] == 0 { + while puzzle.0[r][c] == 0 { (r, c) = (random::() % 9, random::() % 9); } - trace.push((r, c, puzzle[r][c])); - puzzle[r][c] = 0; + trace.push((r, c, puzzle.0[r][c])); + puzzle.0[r][c] = 0; } // 挖空后,判断是否有唯一解 @@ -61,7 +63,7 @@ where let last = trace.pop(); if last.is_some() { let (r, c, num) = last.unwrap(); - puzzle[r][c] = num; + puzzle.0[r][c] = num; } } @@ -71,7 +73,7 @@ where let last = trace.pop(); if last.is_some() { let (r, c, num) = last.unwrap(); - puzzle[r][c] = num; + puzzle.0[r][c] = num; } } dug -= trace_back_step; diff --git a/src/grid.rs b/src/grid.rs new file mode 100644 index 0000000..81f59cc --- /dev/null +++ b/src/grid.rs @@ -0,0 +1,145 @@ +use std::fmt::Display; + +#[derive(Clone, Copy)] +pub struct Grid(pub [[i8; 9]; 9]); + +impl Display for Grid { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let grid = self.0.map(|row| { + row.map(|cell| { + if cell > 0 { + (cell as u8 + 48) as char + } else { + ' ' + } + }) + }); + writeln!(f, "┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[0][0], + grid[0][1], + grid[0][2], + grid[0][3], + grid[0][4], + grid[0][5], + grid[0][6], + grid[0][7], + grid[0][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[1][0], + grid[1][1], + grid[1][2], + grid[1][3], + grid[1][4], + grid[1][5], + grid[1][6], + grid[1][7], + grid[1][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[2][0], + grid[2][1], + grid[2][2], + grid[2][3], + grid[2][4], + grid[2][5], + grid[2][6], + grid[2][7], + grid[2][8], + )?; + writeln!(f, "┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[3][0], + grid[3][1], + grid[3][2], + grid[3][3], + grid[3][4], + grid[3][5], + grid[3][6], + grid[3][7], + grid[3][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[4][0], + grid[4][1], + grid[4][2], + grid[4][3], + grid[4][4], + grid[4][5], + grid[4][6], + grid[4][7], + grid[4][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[5][0], + grid[5][1], + grid[5][2], + grid[5][3], + grid[5][4], + grid[5][5], + grid[5][6], + grid[5][7], + grid[5][8], + )?; + writeln!(f, "┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[6][0], + grid[6][1], + grid[6][2], + grid[6][3], + grid[6][4], + grid[6][5], + grid[6][6], + grid[6][7], + grid[6][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[7][0], + grid[7][1], + grid[7][2], + grid[7][3], + grid[7][4], + grid[7][5], + grid[7][6], + grid[7][7], + grid[7][8], + )?; + writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; + writeln!( + f, + "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", + grid[8][0], + grid[8][1], + grid[8][2], + grid[8][3], + grid[8][4], + grid[8][5], + grid[8][6], + grid[8][7], + grid[8][8], + )?; + write!(f, "┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛") + } +} diff --git a/src/judge.rs b/src/judge.rs index 384c425..dc83801 100644 --- a/src/judge.rs +++ b/src/judge.rs @@ -1,3 +1,5 @@ +use crate::Grid; + use super::utils::coord_2_block; // 返回 ( @@ -5,7 +7,7 @@ use super::utils::coord_2_block; // board是否为有效的完全解 // board中违反约束的格子 // ) -pub fn judge_sudoku(board: &[[i8; 9]; 9]) -> (bool, bool, [[bool; 9]; 9]) { +pub fn judge_sudoku(board: &Grid) -> (bool, bool, [[bool; 9]; 9]) { let mut row: [[(i8, i8); 10]; 9] = [[(-1, -1); 10]; 9]; let mut col: [[(i8, i8); 10]; 9] = [[(-1, -1); 10]; 9]; let mut block: [[(i8, i8); 10]; 9] = [[(-1, -1); 10]; 9]; @@ -14,29 +16,29 @@ pub fn judge_sudoku(board: &[[i8; 9]; 9]) -> (bool, bool, [[bool; 9]; 9]) { let mut valid_cond = [[true; 9]; 9]; for r in 0..9 { for c in 0..9 { - if board[r][c] > 0 { + if board.0[r][c] > 0 { let b = coord_2_block(r, c); - if row[r][board[r][c] as usize] != (-1, -1) { + if row[r][board.0[r][c] as usize] != (-1, -1) { valid = false; valid_cond[r][c] = false; - let (r1, c1) = row[r][board[r][c] as usize]; + let (r1, c1) = row[r][board.0[r][c] as usize]; valid_cond[r1 as usize][c1 as usize] = false; } - if col[c][board[r][c] as usize] != (-1, -1) { + if col[c][board.0[r][c] as usize] != (-1, -1) { valid = false; valid_cond[r][c] = false; - let (r1, c1) = col[c][board[r][c] as usize]; + let (r1, c1) = col[c][board.0[r][c] as usize]; valid_cond[r1 as usize][c1 as usize] = false; } - if block[b][board[r][c] as usize] != (-1, -1) { + if block[b][board.0[r][c] as usize] != (-1, -1) { valid = false; valid_cond[r][c] = false; - let (r1, c1) = block[b][board[r][c] as usize]; + let (r1, c1) = block[b][board.0[r][c] as usize]; valid_cond[r1 as usize][c1 as usize] = false; } - row[r][board[r][c] as usize] = (r as i8, c as i8); - col[c][board[r][c] as usize] = (r as i8, c as i8); - block[b][board[r][c] as usize] = (r as i8, c as i8); + row[r][board.0[r][c] as usize] = (r as i8, c as i8); + col[c][board.0[r][c] as usize] = (r as i8, c as i8); + block[b][board.0[r][c] as usize] = (r as i8, c as i8); } else { full = false; } diff --git a/src/lib.rs b/src/lib.rs index 8b07831..ee2d21c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ -use std::fmt::Display; - pub mod generator; +pub mod grid; pub mod judge; pub mod solver; pub mod state; @@ -9,145 +8,4 @@ pub mod techniques; mod test; pub mod utils; -pub struct Grid(pub [[i8; 9]; 9]); - -impl Display for Grid { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let grid = self.0.map(|row| { - row.map(|cell| { - if cell > 0 { - (cell as u8 + 48) as char - } else { - ' ' - } - }) - }); - writeln!(f, "┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[0][0], - grid[0][1], - grid[0][2], - grid[0][3], - grid[0][4], - grid[0][5], - grid[0][6], - grid[0][7], - grid[0][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[1][0], - grid[1][1], - grid[1][2], - grid[1][3], - grid[1][4], - grid[1][5], - grid[1][6], - grid[1][7], - grid[1][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[2][0], - grid[2][1], - grid[2][2], - grid[2][3], - grid[2][4], - grid[2][5], - grid[2][6], - grid[2][7], - grid[2][8], - )?; - writeln!(f, "┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[3][0], - grid[3][1], - grid[3][2], - grid[3][3], - grid[3][4], - grid[3][5], - grid[3][6], - grid[3][7], - grid[3][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[4][0], - grid[4][1], - grid[4][2], - grid[4][3], - grid[4][4], - grid[4][5], - grid[4][6], - grid[4][7], - grid[4][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[5][0], - grid[5][1], - grid[5][2], - grid[5][3], - grid[5][4], - grid[5][5], - grid[5][6], - grid[5][7], - grid[5][8], - )?; - writeln!(f, "┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[6][0], - grid[6][1], - grid[6][2], - grid[6][3], - grid[6][4], - grid[6][5], - grid[6][6], - grid[6][7], - grid[6][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[7][0], - grid[7][1], - grid[7][2], - grid[7][3], - grid[7][4], - grid[7][5], - grid[7][6], - grid[7][7], - grid[7][8], - )?; - writeln!(f, "┠───┼───┼───╂───┼───┼───╂───┼───┼───┨")?; - writeln!( - f, - "┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃ {} │ {} │ {} ┃", - grid[8][0], - grid[8][1], - grid[8][2], - grid[8][3], - grid[8][4], - grid[8][5], - grid[8][6], - grid[8][7], - grid[8][8], - )?; - write!(f, "┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛") - } -} +pub use grid::Grid; diff --git a/src/solver.rs b/src/solver.rs index 7e782dc..94d1075 100644 --- a/src/solver.rs +++ b/src/solver.rs @@ -1,7 +1,9 @@ +use crate::Grid; + use super::state::State; pub trait Solver { - fn any_solution(&mut self) -> Option<[[i8; 9]; 9]>; + fn any_solution(&mut self) -> Option; fn solution_cnt(&mut self) -> u32; fn have_unique_solution(&mut self) -> bool; } diff --git a/src/solver/advanced.rs b/src/solver/advanced.rs index cc860a3..fba6255 100644 --- a/src/solver/advanced.rs +++ b/src/solver/advanced.rs @@ -6,7 +6,7 @@ use crate::{ techniques::{ hidden_pair_blk, hidden_pair_col, hidden_pair_row, hidden_single_blk, hidden_single_col, hidden_single_row, naked_pair_blk, naked_pair_col, naked_pair_row, naked_single, pointing, - }, + }, Grid, }; use super::{Grader, Solver}; @@ -20,7 +20,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - puzzle: [[i8; 9]; 9], + puzzle: Grid, state: T, solution_cnt: u32, tmp_score: f32, @@ -42,7 +42,7 @@ where } fn search(&mut self, solution_cnt_needed: u32) -> bool { - if self.state.grid().iter().flatten().all(|v| *v > 0) { + if self.state.grid().0.iter().flatten().all(|v| *v > 0) { self.solution_cnt += 1; self.score = self.tmp_score; return solution_cnt_needed <= self.solution_cnt; @@ -173,7 +173,7 @@ where } } -impl From<[[i8; 9]; 9]> for AdvancedSolver +impl From for AdvancedSolver where T: State + Fillable @@ -182,7 +182,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - fn from(puzzle: [[i8; 9]; 9]) -> Self { + fn from(puzzle: Grid) -> Self { Self { puzzle, state: T::from(puzzle), @@ -202,7 +202,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - fn any_solution(&mut self) -> Option<[[i8; 9]; 9]> { + fn any_solution(&mut self) -> Option { self.init_search(); if self.search(1) { return Some(self.state.grid()); diff --git a/src/solver/naive.rs b/src/solver/naive.rs index 7910685..082880f 100644 --- a/src/solver/naive.rs +++ b/src/solver/naive.rs @@ -3,7 +3,7 @@ use crate::{ CandidatesSettable, Fillable, State, TrackingCandidateCountOfCell, TrackingCandidates, TrackingCellCountOfCandidate, }, - techniques::{hidden_single_blk, hidden_single_col, hidden_single_row}, + techniques::{hidden_single_blk, hidden_single_col, hidden_single_row}, Grid, }; use super::{Grader, Solver}; @@ -17,7 +17,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - puzzle: [[i8; 9]; 9], + puzzle: Grid, state: T, solution_cnt: u32, invoke_cnt: i32, @@ -40,7 +40,7 @@ where fn search(&mut self, solution_cnt_needed: u32) -> bool { self.invoke_cnt += 1; - if self.state.grid().iter().flatten().all(|v| *v > 0) { + if self.state.grid().0.iter().flatten().all(|v| *v > 0) { self.solution_cnt += 1; return solution_cnt_needed <= self.solution_cnt; } @@ -64,7 +64,7 @@ where } } -impl From<[[i8; 9]; 9]> for NaiveSolver +impl From for NaiveSolver where T: State + Fillable @@ -73,7 +73,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - fn from(puzzle: [[i8; 9]; 9]) -> Self { + fn from(puzzle: Grid) -> Self { Self { puzzle, state: T::from(puzzle), @@ -92,7 +92,7 @@ where + TrackingCandidateCountOfCell + TrackingCellCountOfCandidate, { - fn any_solution(&mut self) -> Option<[[i8; 9]; 9]> { + fn any_solution(&mut self) -> Option { self.init_search(); if self.search(1) { return Some(self.state.grid()); diff --git a/src/solver/stochastic.rs b/src/solver/stochastic.rs index e1d72f2..a71045b 100644 --- a/src/solver/stochastic.rs +++ b/src/solver/stochastic.rs @@ -1,6 +1,6 @@ use super::{next_blank, Solver}; -use crate::state::{Fillable, State, TrackingCandidates}; +use crate::{state::{Fillable, State, TrackingCandidates}, Grid}; use rand::prelude::*; @@ -8,7 +8,7 @@ pub struct StochasticSolver where T: State + Fillable + TrackingCandidates, { - puzzle: [[i8; 9]; 9], + puzzle: Grid, state: T, solution_cnt: u32, } @@ -50,11 +50,11 @@ where } } -impl From<[[i8; 9]; 9]> for StochasticSolver +impl From for StochasticSolver where T: State + Fillable + TrackingCandidates, { - fn from(puzzle: [[i8; 9]; 9]) -> Self { + fn from(puzzle: Grid) -> Self { Self { puzzle, state: T::from(puzzle), @@ -67,7 +67,7 @@ impl Solver for StochasticSolver where T: State + Fillable + TrackingCandidates, { - fn any_solution(&mut self) -> Option<[[i8; 9]; 9]> { + fn any_solution(&mut self) -> Option { self.init_search(); if self.search(0, 0, 1) { return Some(self.state.grid()); diff --git a/src/state.rs b/src/state.rs index e34b7e0..748cb42 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,7 +1,9 @@ -pub trait State: From<[[i8; 9]; 9]> { +use crate::Grid; + +pub trait State: From { fn cell_val(&self, r: usize, c: usize) -> i8; fn is_cell_empty(&self, r: usize, c: usize) -> bool; - fn grid(&self) -> [[i8; 9]; 9]; + fn grid(&self) -> Grid; } pub trait TrackingCandidates: State { diff --git a/src/state/full_state.rs b/src/state/full_state.rs index b0c33f1..72f8d92 100644 --- a/src/state/full_state.rs +++ b/src/state/full_state.rs @@ -1,4 +1,7 @@ -use crate::utils::{block_idx_2_coord, coord_2_block}; +use crate::{ + utils::{block_idx_2_coord, coord_2_block}, + Grid, +}; use super::{ CandidatesSettable, Fillable, State, TrackingCandidateCountOfCell, TrackingCandidates, @@ -6,7 +9,7 @@ use super::{ }; pub struct FullState { - grid: [[i8; 9]; 9], + grid: Grid, candidates: [[[bool; 10]; 9]; 9], candidate_cnt: [[i8; 9]; 9], cell_cnt_for_candidate_in_row: [[i8; 10]; 9], @@ -21,10 +24,10 @@ pub struct FullState { )>, } -impl From<[[i8; 9]; 9]> for FullState { - fn from(puzzle: [[i8; 9]; 9]) -> Self { +impl From for FullState { + fn from(puzzle: Grid) -> Self { let mut res = Self { - grid: [[0; 9]; 9], + grid: Grid([[0; 9]; 9]), candidates: [[[true; 10]; 9]; 9], candidate_cnt: [[9; 9]; 9], cell_cnt_for_candidate_in_row: [[9; 10]; 9], @@ -34,8 +37,8 @@ impl From<[[i8; 9]; 9]> for FullState { }; for r in 0..9 { for c in 0..9 { - if puzzle[r][c] > 0 { - res.fill_cell(r, c, puzzle[r][c]); + if puzzle.0[r][c] > 0 { + res.fill_cell(r, c, puzzle.0[r][c]); } } } @@ -45,14 +48,14 @@ impl From<[[i8; 9]; 9]> for FullState { impl State for FullState { fn cell_val(&self, r: usize, c: usize) -> i8 { - self.grid[r][c] + self.grid.0[r][c] } fn is_cell_empty(&self, r: usize, c: usize) -> bool { - self.grid[r][c] == 0 + self.grid.0[r][c] == 0 } - fn grid(&self) -> [[i8; 9]; 9] { + fn grid(&self) -> Grid { self.grid } } @@ -103,7 +106,7 @@ impl Fillable for FullState { self.cell_cnt_for_candidate_in_blk, )); - self.grid[r][c] = num; + self.grid.0[r][c] = num; let num = num as usize; let b = coord_2_block(r, c); @@ -138,14 +141,14 @@ impl Fillable for FullState { for r in 0..9 { let mut cell_cnt = 0; for c in 0..9 { - cell_cnt += (self.candidates[r][c][num] && self.grid[r][c] == 0) as i8; + cell_cnt += (self.candidates[r][c][num] && self.grid.0[r][c] == 0) as i8; } self.cell_cnt_for_candidate_in_row[r][num] = cell_cnt; } for c in 0..9 { let mut cell_cnt = 0; for r in 0..9 { - cell_cnt += (self.candidates[r][c][num] && self.grid[r][c] == 0) as i8; + cell_cnt += (self.candidates[r][c][num] && self.grid.0[r][c] == 0) as i8; } self.cell_cnt_for_candidate_in_col[c][num] = cell_cnt; } @@ -153,7 +156,7 @@ impl Fillable for FullState { let mut cell_cnt = 0; for bidx in 0..9 { let (r, c) = block_idx_2_coord(b, bidx); - cell_cnt += (self.candidates[r][c][num] && self.grid[r][c] == 0) as i8; + cell_cnt += (self.candidates[r][c][num] && self.grid.0[r][c] == 0) as i8; } self.cell_cnt_for_candidate_in_blk[b][num] = cell_cnt; } @@ -162,7 +165,7 @@ impl Fillable for FullState { // 撤销上一步填充 fn unfill_cell(&mut self, r: usize, c: usize) { // 回退 - self.grid[r][c] = 0; + self.grid.0[r][c] = 0; ( self.candidates, self.candidate_cnt, diff --git a/src/state/simple_state.rs b/src/state/simple_state.rs index 4e0fac3..f8cb552 100644 --- a/src/state/simple_state.rs +++ b/src/state/simple_state.rs @@ -1,16 +1,16 @@ -use crate::utils::coord_2_block; +use crate::{utils::coord_2_block, Grid}; use super::{Fillable, State, TrackingCandidates}; pub struct SimpleState { - grid: [[i8; 9]; 9], // 棋盘 + grid: Grid, // 棋盘 row: [[bool; 10]; 9], // row[r][num] = 第r行是否存在数num col: [[bool; 10]; 9], // 同理 block: [[bool; 10]; 9], // 同理 } -impl From<[[i8; 9]; 9]> for SimpleState { - fn from(puzzle: [[i8; 9]; 9]) -> Self { +impl From for SimpleState { + fn from(puzzle: Grid) -> Self { let mut res = Self { grid: puzzle, row: [[false; 10]; 9], @@ -19,9 +19,9 @@ impl From<[[i8; 9]; 9]> for SimpleState { }; for r in 0..9 { for c in 0..9 { - res.row[r][res.grid[r][c] as usize] = true; - res.col[c][res.grid[r][c] as usize] = true; - res.block[coord_2_block(r, c)][res.grid[r][c] as usize] = true; + res.row[r][res.grid.0[r][c] as usize] = true; + res.col[c][res.grid.0[r][c] as usize] = true; + res.block[coord_2_block(r, c)][res.grid.0[r][c] as usize] = true; } } res @@ -30,14 +30,14 @@ impl From<[[i8; 9]; 9]> for SimpleState { impl State for SimpleState { fn cell_val(&self, r: usize, c: usize) -> i8 { - self.grid[r][c] + self.grid.0[r][c] } fn is_cell_empty(&self, r: usize, c: usize) -> bool { - self.grid[r][c] == 0 + self.grid.0[r][c] == 0 } - fn grid(&self) -> [[i8; 9]; 9] { + fn grid(&self) -> Grid { self.grid } } @@ -52,7 +52,7 @@ impl TrackingCandidates for SimpleState { impl Fillable for SimpleState { fn fill_cell(&mut self, r: usize, c: usize, num: i8) { let b = coord_2_block(r, c); - self.grid[r][c] = num; + self.grid.0[r][c] = num; self.row[r][num as usize] = true; self.col[c][num as usize] = true; self.block[b][num as usize] = true; @@ -60,8 +60,8 @@ impl Fillable for SimpleState { fn unfill_cell(&mut self, r: usize, c: usize) { let b = coord_2_block(r, c); - let num = self.grid[r][c]; - self.grid[r][c] = 0; + let num = self.grid.0[r][c]; + self.grid.0[r][c] = 0; self.row[r][num as usize] = false; self.col[c][num as usize] = false; self.block[b][num as usize] = false; diff --git a/src/test.rs b/src/test.rs index 8e25cb7..c30ca72 100644 --- a/src/test.rs +++ b/src/test.rs @@ -11,10 +11,10 @@ use crate::{ techniques::{ hidden_pair_row, hidden_single_blk, hidden_single_col, hidden_single_row, naked_single, }, - utils::{block_idx_2_coord, coord_2_block_idx}, + utils::{block_idx_2_coord, coord_2_block_idx}, Grid, }; -fn random_sudoku_puzzle_normal() -> [[i8; 9]; 9] { +fn random_sudoku_puzzle_normal() -> Grid { random_sudoku_puzzle::, AdvancedSolver, f32>( 45, 60.0, 1000.0, )