diff --git a/src/main.rs b/src/main.rs index 046ce93..82eafee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ #![feature(int_roundings)] use rand::{thread_rng,Rng}; use solver::Solver; -use std::io; +use std::{io,env}; mod cursor; mod solver; mod linked; @@ -14,7 +14,7 @@ mod sudoku; mod sudoku_gen; mod utils; use crate::sudoku::{Sudoku}; -use std::env; +use crate::sudoku_gen::SudokuGenerator; fn main(){ env::set_var("RUST_BACKTRACE", "1"); @@ -29,11 +29,12 @@ fn main(){ res = sudoku_problem.time_to_solve(Sudoku::solver, None);} if let Some(res) = res{ println!("found {} solutions to the problem",sudoku_problem.solutions); - let index = thread_rng().gen_range(1..res.len()); + let index = thread_rng().gen_range(0..res.len()); //for x in 0..sudoku_problem.solutions{ //if x >10{break;} println!("{:?}",res[index]); // } } + println!("sovlvable {:?}", SudokuGenerator::new(split[1].parse::().unwrap()).generate_solvable()); } diff --git a/src/matrix.rs b/src/matrix.rs index 7cab369..05942a1 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -2,7 +2,6 @@ use rand::Rng; use crate::cells::Cell; use crate::cells::CERO; use crate::linked::Linked; -use crate::utils; pub struct Matrix { pub(crate) horizontal: Linked, pub(crate) vertical: Linked, diff --git a/src/sudoku.rs b/src/sudoku.rs index 9bfab5a..414703a 100644 --- a/src/sudoku.rs +++ b/src/sudoku.rs @@ -6,7 +6,7 @@ use crate::{cells::Cell, cells::CERO, matrix::Matrix}; const HARD_CODED_MAX: usize =100_000; pub struct Sudoku { - sudoku: String, + pub(crate) sudoku: String, dimension: usize, pub(crate) solutions: usize, pub(crate) recursion_depth: usize, @@ -65,6 +65,10 @@ impl Sudoku { } } } + pub fn set_new_sudoku(&mut self, sudoku:String){ + self.solutions =0usize; + self.sudoku =sudoku; + } fn sudoku_to_sparse(&self) -> Vec> { let mut sparse: Vec> = Vec::new(); if self.dimension < 4 { diff --git a/src/sudoku_gen.rs b/src/sudoku_gen.rs index 48d465f..ecb2af9 100644 --- a/src/sudoku_gen.rs +++ b/src/sudoku_gen.rs @@ -1,10 +1,11 @@ -use crate::{sudoku::Sudoku, solver::Solver}; -use rand::{thread_rng, Rng}; +use crate::{sudoku::{Sudoku, self}, solver::Solver}; +use rand::{thread_rng, Rng, seq::SliceRandom}; use crate::utils; pub(crate) struct SudokuGenerator{ generated_sudokus: Vec, - blank: Sudoku + blank: Sudoku, + dimension: usize } impl SudokuGenerator { @@ -14,26 +15,78 @@ impl SudokuGenerator { generated_sudokus:Vec::new(), blank: { let sudoku= { - let sudoku: String = utils::vec_to_sudoku_string(vec![0;size*size*size*size]); + let sudoku: String = utils::vec_to_sudoku_string(&vec![0;size*size*size*size]); let returned_sudoku = Sudoku::new(sudoku.as_str(),size); returned_sudoku }; sudoku - } + },dimension:size } } - #[allow(dead_code)] - pub(crate) fn generate(&mut self) ->Option{ + pub fn generate(&mut self) ->Option>>{ let sudokus = self.blank.solver(None); + if let Some(sudokus) = sudokus{ + return Some(sudokus) + } + None + } + + pub fn generate_one_full(&mut self) -> Option{ + let sudokus = self.generate(); let mut rng = thread_rng(); if let Some(mut sudokus) = sudokus{ let picked_board = sudokus.remove(rng.gen_range(0..sudokus.len())); - return Some(utils::vec_to_sudoku_string(picked_board)) + return Some(utils::vec_to_sudoku_string(&picked_board)) } return None } - + + pub fn generate_solvable(&mut self) -> Vec{ + let mut fails = 0; + let posibilities = self.dimension * self.dimension; + let mut picks: Vec = (0usize..posibilities*posibilities as usize).collect(); + let mut rng = thread_rng(); + let sudoku = self.generate_one_full().unwrap(); + let mut last_sudoku = Vec::new(); + let mut sudoku_to_return = sudoku::Sudoku::new(sudoku.as_str(), self.dimension); + picks.shuffle(&mut rng); + + let first_sudoku = utils::string_to_sudoku_vec(sudoku.as_str()); + + let mut curr_sudoku = utils::string_to_sudoku_vec(sudoku.as_str()); + while let Some(pick) = picks.pop(){ + curr_sudoku[pick] = 0usize; + sudoku_to_return.set_new_sudoku(utils::vec_to_sudoku_string(&curr_sudoku)); + if fails >=10000{ + return curr_sudoku + } + let result = sudoku_to_return.solver(None); + if let Some( result) = result{ + last_sudoku =utils::string_to_sudoku_vec(sudoku_to_return.sudoku.as_str()); + if result.len()==1{ + println!("current sudoku: {:?}", curr_sudoku ); + let mut possible_good_grid = curr_sudoku.clone(); + possible_good_grid.shuffle(&mut rng); + sudoku_to_return.set_new_sudoku(utils::vec_to_sudoku_string(&possible_good_grid)); + if let Some(checked) = sudoku_to_return.solver(None){ + if result.len() == 1 { + curr_sudoku = utils::string_to_sudoku_vec(sudoku_to_return.sudoku.as_str()); + + }else{curr_sudoku = last_sudoku; fails+=1} + }else { + curr_sudoku = last_sudoku; + fails +=1; + } + }else { + curr_sudoku = last_sudoku; + fails +=1 + } + + } + } + curr_sudoku + } } diff --git a/src/utils.rs b/src/utils.rs index 746e4e7..2d34816 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,15 @@ -pub(crate) fn vec_to_sudoku_string(sudoku_vec: Vec) -> String{ +pub(crate) fn vec_to_sudoku_string(sudoku_vec: &Vec) -> String{ - sudoku_vec - .into_iter() - .map(|v| v.to_string()) - .fold(String::new(),|mut a,b|a.to_owned()+&b) + let to_return = sudoku_vec + .into_iter() + .map(|v| v.to_string()) + .fold(String::new(),|a,b|a.to_owned()+&b); + to_return +} + +pub(crate) fn string_to_sudoku_vec(sudoku_str: &str) -> Vec{ + + sudoku_str.chars() + .map(|v|v.to_digit(10).unwrap() as usize) + .collect() }