Skip to main content

sudoku/
sudoku.rs

1//! A Sudoku problem from RosettaCode (https://rosettacode.org/wiki/Sudoku#Rust)
2//! rewritten with the use of ranged_integers library
3
4#![allow(incomplete_features)]
5#![feature(adt_const_params,generic_const_exprs)]
6
7use ranged_integers::*;
8
9pub const ROW_SIZE : usize = 9;
10
11pub type Val = Ranged<0, 9>;
12pub type RowIndex = Ranged<0, {({ROW_SIZE - 1}) as _}>;
13pub type Sudoku = [[Val; 9]; 9];
14
15pub fn is_valid(val: Val, x: RowIndex, y: RowIndex, sudoku_ar: &Sudoku) -> bool {
16    r!(0..=8).into_iter().all( |i|
17        sudoku_ar[x][i] != val && 
18        sudoku_ar[i][y] != val && {
19            r!(0..=2).into_iter().all(|i| r!(0..=2).into_iter().all(|j| 
20                sudoku_ar[x / r!(3) * r!(3) + i][y / r!(3) * r!(3) + j] != val
21            ))
22        }
23    )
24}
25
26pub fn place_number(pos: Ranged<0, 80>, sudoku_ar: &mut Sudoku) -> bool {
27    pos.iter_up()
28        .find_map(|p| {
29                let (x, y) = (p % r!(9), p / r!(9));
30                if sudoku_ar[x][y] == r!(0) {Some((x,y))} else {None}
31            })
32        .is_none_or(|(x, y)| {
33            for n in r!(1..=9) {
34                if is_valid(n.expand(), x, y, sudoku_ar) {
35                    sudoku_ar[x][y] = n.expand();
36                    let next = if let Some(next) = (pos + r!(1)).fit() {next} else {return true};
37                    if place_number(next,sudoku_ar) {
38                        return true;
39                    }
40                    sudoku_ar[x][y] = r!([]0);
41                }
42            }
43            false
44        })
45}
46
47pub fn pretty_print(sudoku_ar: Sudoku) {
48    let line_sep = "------+-------+------";
49    println!("{line_sep}");
50    for (i, row) in sudoku_ar.iter().enumerate() {
51        for (j, val) in row.iter().enumerate() {
52            print!("{val} ");
53            if j == 2 || j == 5 {
54                print!("| ");
55            }
56        }
57        println!();
58        if i % 3 == 2 {
59            println!("{line_sep}");
60        }
61    }
62}
63
64fn solve(sudoku_ar: &mut Sudoku)->bool {
65    place_number(r!([] 0), sudoku_ar)
66}
67
68macro_rules! rangedarr {
69    ($($e:literal),* $(,)?) => {  [$( r!([] $e) ),*]  };
70} 
71
72fn main() {
73    let mut sudoku_ar: Sudoku = [
74        rangedarr![8, 5, 0, 0, 0, 2, 4, 0, 0],
75        rangedarr![7, 2, 0, 0, 0, 0, 0, 0, 9],
76        rangedarr![0, 0, 4, 0, 0, 0, 0, 0, 0],
77        rangedarr![0, 0, 0, 1, 0, 7, 0, 0, 2],
78        rangedarr![3, 0, 5, 0, 0, 0, 9, 0, 0],
79        rangedarr![0, 4, 0, 0, 0, 0, 0, 0, 0],
80        rangedarr![0, 0, 0, 0, 8, 0, 0, 7, 0],
81        rangedarr![0, 1, 7, 0, 0, 0, 0, 0, 0],
82        rangedarr![0, 0, 0, 0, 3, 6, 0, 4, 0],
83    ];
84
85    if solve(&mut sudoku_ar) {
86        pretty_print(sudoku_ar);
87    }
88    else {
89        println!("Unsolvable");
90    }
91}