Skip to content

Commit e97ed43

Browse files
committed
Refactor module structure, rename types, and bump version to 0.2.0
1 parent 4cbe4ea commit e97ed43

8 files changed

Lines changed: 572 additions & 669 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Sudoku in Rust.
66

77
This project is licensed under either of the following licenses, at your option:
88

9-
- Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/qntx/gors/blob/main/LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
10-
- MIT license ([LICENSE-MIT](https://github.com/qntx/gors/blob/main/LICENSE-MIT) or https://opensource.org/licenses/MIT)
9+
- Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/qntx/gors/blob/main/LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
10+
- MIT license ([LICENSE-MIT](https://github.com/qntx/gors/blob/main/LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
1111

1212
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in kand by you, as defined in the Apache-2.0 license, shall be dually licensed as above, without any additional terms or conditions.

sodo/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sodo"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
description = "Sudoku in Rust"
55
license = "MIT OR Apache-2.0"
66
edition = "2024"

sodo/src/lib.rs

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,69 @@
11
mod solver;
22
mod strategy;
3-
mod sudoku;
3+
mod sodo;
44

5-
pub use solver::{Difficulty, SolverStats, SudokuSolver};
6-
pub use strategy::{get_all_strategies, SolvingStrategy};
7-
pub use sudoku::{Cell, Sudoku};
5+
pub use solver::{Difficulty, Solver, Stats};
6+
pub use strategy::{all as all_strategies, Strategy};
7+
pub use sodo::{Cell, Sudoku};
88

99
use std::{fs, process};
1010

11-
fn parse_size(size_str: &str) -> usize {
12-
size_str.parse().unwrap_or_else(|_| {
13-
eprintln!("Invalid size: {size_str}");
11+
fn parse_size(s: &str) -> usize {
12+
s.parse().unwrap_or_else(|_| {
13+
eprintln!("Invalid size: {s}");
1414
process::exit(1)
1515
})
1616
}
1717

18-
fn parse_puzzle(puzzle_str: &str, size: usize) -> Sudoku {
19-
Sudoku::from_string(puzzle_str, size).unwrap_or_else(|e| {
18+
fn parse_puzzle(s: &str, size: usize) -> Sudoku {
19+
Sudoku::from_string(s, size).unwrap_or_else(|e| {
2020
eprintln!("Error parsing puzzle: {e}");
2121
process::exit(1)
2222
})
2323
}
2424

25+
/// Solves a puzzle from string.
2526
pub fn solve_puzzle(puzzle_str: &str, size_str: &str) {
2627
let size = parse_size(size_str);
2728
let puzzle = parse_puzzle(puzzle_str, size);
2829

2930
println!("Original puzzle:");
3031
println!("{puzzle}");
3132

32-
let mut solver = SudokuSolver::new();
33+
let mut solver = Solver::new();
3334

3435
match solver.solve_with_stats(puzzle) {
3536
Ok((solution, stats)) => {
3637
println!("Solution found!");
3738
println!("{solution}");
38-
println!("\nSolver Statistics:");
39-
println!("Iterations: {}", stats.iterations);
40-
println!("Cells filled: {}", stats.cells_filled);
41-
println!("Backtrack steps: {}", stats.backtrack_steps);
42-
println!("Strategies used:");
43-
for (strategy, count) in stats.strategies_used {
44-
println!(" {strategy}: {count}");
39+
println!("\nStatistics:");
40+
println!(" Iterations: {}", stats.iterations);
41+
println!(" Cells filled: {}", stats.cells_filled);
42+
println!(" Backtracks: {}", stats.backtracks);
43+
println!(" Strategies:");
44+
for (name, count) in &stats.strategies_used {
45+
println!(" {name}: {count}");
4546
}
4647
}
4748
Err(e) => {
48-
eprintln!("Failed to solve puzzle: {e}");
49+
eprintln!("Failed to solve: {e}");
4950
process::exit(1);
5051
}
5152
}
5253
}
5354

54-
pub fn solve_from_file(file_path: &str, size_str: &str) {
55-
let puzzle_str = fs::read_to_string(file_path)
55+
/// Solves a puzzle from file.
56+
pub fn solve_from_file(path: &str, size_str: &str) {
57+
let content = fs::read_to_string(path)
5658
.map(|s| s.trim().to_string())
5759
.unwrap_or_else(|e| {
5860
eprintln!("Error reading file: {e}");
5961
process::exit(1)
6062
});
61-
solve_puzzle(&puzzle_str, size_str);
63+
solve_puzzle(&content, size_str);
6264
}
6365

66+
/// Generates a puzzle.
6467
pub fn generate_puzzle(size_str: &str, difficulty_str: &str) {
6568
let size = parse_size(size_str);
6669
let difficulty = match difficulty_str.to_lowercase().as_str() {
@@ -69,25 +72,26 @@ pub fn generate_puzzle(size_str: &str, difficulty_str: &str) {
6972
"hard" => Difficulty::Hard,
7073
"expert" => Difficulty::Expert,
7174
_ => {
72-
eprintln!("Invalid difficulty: {difficulty_str}. Use easy, medium, hard, or expert");
75+
eprintln!("Invalid difficulty: {difficulty_str}");
7376
process::exit(1)
7477
}
7578
};
7679

77-
let mut solver = SudokuSolver::new();
80+
let mut solver = Solver::new();
7881

79-
match solver.generate_puzzle(size, difficulty) {
82+
match solver.generate(size, difficulty) {
8083
Ok(puzzle) => {
8184
println!("Generated {difficulty_str} puzzle ({size}x{size}):");
8285
println!("{puzzle}");
8386
}
8487
Err(e) => {
85-
eprintln!("Failed to generate puzzle: {e}");
88+
eprintln!("Failed to generate: {e}");
8689
process::exit(1);
8790
}
8891
}
8992
}
9093

94+
/// Validates a puzzle.
9195
pub fn validate_puzzle(puzzle_str: &str, size_str: &str) {
9296
let size = parse_size(size_str);
9397
let puzzle = parse_puzzle(puzzle_str, size);
@@ -96,51 +100,45 @@ pub fn validate_puzzle(puzzle_str: &str, size_str: &str) {
96100
println!("{puzzle}");
97101

98102
if puzzle.is_valid() {
99-
println!("✓ Puzzle is valid!");
100-
103+
println!("Valid!");
101104
if puzzle.is_complete() {
102-
println!("✓ Puzzle is complete and solved!");
105+
println!("Complete and solved!");
103106
} else {
104-
println!("! Puzzle is valid but not yet complete.");
107+
println!("Not yet complete.");
105108
}
106109
} else {
107-
println!("✗ Puzzle is invalid!");
108-
109-
if !puzzle.is_valid_rows() {
110-
println!(" - Invalid rows detected");
110+
println!("Invalid!");
111+
if !puzzle.valid_rows() {
112+
println!(" - Invalid rows");
111113
}
112-
if !puzzle.is_valid_cols() {
113-
println!(" - Invalid columns detected");
114+
if !puzzle.valid_cols() {
115+
println!(" - Invalid columns");
114116
}
115-
if !puzzle.is_valid_boxes() {
116-
println!(" - Invalid boxes detected");
117+
if !puzzle.valid_boxes() {
118+
println!(" - Invalid boxes");
117119
}
118120
}
119121
}
120122

123+
/// Gets a hint for the puzzle.
121124
pub fn get_hint(puzzle_str: &str, size_str: &str) {
122125
let size = parse_size(size_str);
123126
let mut puzzle = parse_puzzle(puzzle_str, size);
124127

125128
println!("Current puzzle:");
126129
println!("{puzzle}");
127130

128-
let mut solver = SudokuSolver::new();
129-
130-
match solver.get_hint(&mut puzzle) {
131-
Some((row, col, value)) => {
132-
println!(
133-
"Hint: Place {} at position ({}, {})",
134-
value,
135-
row + 1,
136-
col + 1
137-
);
138-
puzzle.set(row, col, value).unwrap();
139-
println!("\nPuzzle with hint applied:");
131+
let solver = Solver::new();
132+
133+
match solver.hint(&puzzle) {
134+
Some((r, c, val)) => {
135+
println!("Hint: Place {val} at ({}, {})", r + 1, c + 1);
136+
let _ = puzzle.set(r, c, val);
137+
println!("\nWith hint applied:");
140138
println!("{puzzle}");
141139
}
142140
None => {
143-
println!("No obvious hint available. You might need to use more advanced techniques.");
141+
println!("No obvious hint available.");
144142
}
145143
}
146144
}

0 commit comments

Comments
 (0)