1mod solver;
2mod strategies;
3mod sudoku;
4mod utils;
5
6#[cfg(feature = "wasm")]
7mod wasm;
8
9pub use solver::{Difficulty, SudokuSolver};
10pub use strategies::*;
11pub use sudoku::{Cell, Sudoku};
12
13#[cfg(feature = "wasm")]
14pub use wasm::*;
15
16use std::{fs, process};
17
18pub fn solve_puzzle(puzzle_str: &str, size_str: &str) {
19 let size = match size_str.parse::<usize>() {
20 Ok(s) => s,
21 Err(_) => {
22 eprintln!("Invalid size: {size_str}");
23 process::exit(1);
24 }
25 };
26
27 let puzzle = match Sudoku::from_string(puzzle_str, size) {
28 Ok(p) => p,
29 Err(e) => {
30 eprintln!("Error parsing puzzle: {e}");
31 process::exit(1);
32 }
33 };
34
35 println!("Original puzzle:");
36 println!("{puzzle}");
37
38 let mut solver = SudokuSolver::new();
39
40 match solver.solve_with_stats(puzzle) {
41 Ok((solution, stats)) => {
42 println!("Solution found!");
43 println!("{solution}");
44 println!("\nSolver Statistics:");
45 println!("Iterations: {}", stats.iterations);
46 println!("Cells filled: {}", stats.cells_filled);
47 println!("Backtrack steps: {}", stats.backtrack_steps);
48 println!("Strategies used:");
49 for (strategy, count) in stats.strategies_used {
50 println!(" {strategy}: {count}");
51 }
52 }
53 Err(e) => {
54 eprintln!("Failed to solve puzzle: {e}");
55 process::exit(1);
56 }
57 }
58}
59
60pub fn solve_from_file(file_path: &str, size_str: &str) {
61 let puzzle_str = match fs::read_to_string(file_path) {
62 Ok(content) => content.trim().to_string(),
63 Err(e) => {
64 eprintln!("Error reading file: {e}");
65 process::exit(1);
66 }
67 };
68
69 solve_puzzle(&puzzle_str, size_str);
70}
71
72pub fn generate_puzzle(size_str: &str, difficulty_str: &str) {
73 let size = match size_str.parse::<usize>() {
74 Ok(s) => s,
75 Err(_) => {
76 eprintln!("Invalid size: {size_str}");
77 process::exit(1);
78 }
79 };
80
81 let difficulty = match difficulty_str.to_lowercase().as_str() {
82 "easy" => Difficulty::Easy,
83 "medium" => Difficulty::Medium,
84 "hard" => Difficulty::Hard,
85 "expert" => Difficulty::Expert,
86 _ => {
87 eprintln!(
88 "Invalid difficulty: {difficulty_str}. Use easy, medium, hard, or expert"
89 );
90 process::exit(1);
91 }
92 };
93
94 let mut solver = SudokuSolver::new();
95
96 match solver.generate_puzzle(size, difficulty) {
97 Ok(puzzle) => {
98 println!("Generated {difficulty_str} puzzle ({size}x{size}):");
99 println!("{puzzle}");
100 }
101 Err(e) => {
102 eprintln!("Failed to generate puzzle: {e}");
103 process::exit(1);
104 }
105 }
106}
107
108pub fn validate_puzzle(puzzle_str: &str, size_str: &str) {
109 let size = match size_str.parse::<usize>() {
110 Ok(s) => s,
111 Err(_) => {
112 eprintln!("Invalid size: {size_str}");
113 process::exit(1);
114 }
115 };
116
117 let puzzle = match Sudoku::from_string(puzzle_str, size) {
118 Ok(p) => p,
119 Err(e) => {
120 eprintln!("Error parsing puzzle: {e}");
121 process::exit(1);
122 }
123 };
124
125 println!("Puzzle:");
126 println!("{puzzle}");
127
128 if puzzle.is_valid() {
129 println!("✓ Puzzle is valid!");
130
131 if puzzle.is_complete() {
132 println!("✓ Puzzle is complete and solved!");
133 } else {
134 println!("! Puzzle is valid but not yet complete.");
135 }
136 } else {
137 println!("✗ Puzzle is invalid!");
138
139 if !puzzle.is_valid_rows() {
140 println!(" - Invalid rows detected");
141 }
142 if !puzzle.is_valid_cols() {
143 println!(" - Invalid columns detected");
144 }
145 if !puzzle.is_valid_boxes() {
146 println!(" - Invalid boxes detected");
147 }
148 }
149}
150
151pub fn get_hint(puzzle_str: &str, size_str: &str) {
152 let size = match size_str.parse::<usize>() {
153 Ok(s) => s,
154 Err(_) => {
155 eprintln!("Invalid size: {size_str}");
156 process::exit(1);
157 }
158 };
159
160 let mut puzzle = match Sudoku::from_string(puzzle_str, size) {
161 Ok(p) => p,
162 Err(e) => {
163 eprintln!("Error parsing puzzle: {e}");
164 process::exit(1);
165 }
166 };
167
168 println!("Current puzzle:");
169 println!("{puzzle}");
170
171 let mut solver = SudokuSolver::new();
172
173 match solver.get_hint(&mut puzzle) {
174 Some((row, col, value)) => {
175 println!(
176 "Hint: Place {} at position ({}, {})",
177 value,
178 row + 1,
179 col + 1
180 );
181 puzzle.set(row, col, value).unwrap();
182 println!("\nPuzzle with hint applied:");
183 println!("{puzzle}");
184 }
185 None => {
186 println!("No obvious hint available. You might need to use more advanced techniques.");
187 }
188 }
189}