Simple Sudoku solver in Rust
General


Run clippy. It will automatically tell you such things as:


equality checks against true are unnecessary

  --&gt; src/main.rs:20:57
   |
20 |             return Some(candidates.iter().position(|&amp;x| x == true).unwrap() as u8 + 1);
   |                                                         ^^^^^^^^^ 

it is more idiomatic to loop over references to containers instead of using explicit iteration methods

  --&gt; src/main.rs:26:18
   |
26 |         for i in row.iter() {
   |                  ^^^^^^^^^^ help: to write this more concisely, try: `&amp;row`

redundant pattern matching, consider using is_none()

  --&gt; src/main.rs:97:16
   |
97 |         if let None = grid.next() {
   |         -------^^^^-------------- help: try this: `if grid.next().is_none()`


Cell is a name of a type in the standard library, so I was a bit confused to start with. Not sure of a better name.


main


Use while or while let instead of a loop.
The continue is not useful, it's at the end of the block. Switch to an if let instead.
Why isn't the return value of your iterator used? Why don't you use that instead of getting grid.current?
Why is grid.current even part of the grid in the first place?


Grid


If you want to document a function, use ///, not //.
Don't cast booleans as a number. I'm honestly surprised this even compiles. Instead, count the true values
Memorize all the available Iterator methods. In this case, any and all are valuable.


Grid::check_square


There's no need to specify the type of square.
I don't think it's useful to cram the square data into a tuple. Instead, whip up a little closure to perform the same work.
I like Itertools. Here, I use its cartesian_product.




extern crate itertools;

use itertools::Itertools;

type Cell = (usize, usize);

struct Grid {
    data: [[u8; 9]; 9],
    current: Cell,
}

impl Grid {
    /// Search possible candidates for a given cell.
    /// If one candidate exists, return it.
    fn check(&amp;mut self, cell: Cell) -&gt; Option&lt;u8&gt; {
        let mut candidates = [true; 9];
        for i in 1..10 {
            candidates[i - 1] &amp;= self.check_row(cell, i as u8);
            candidates[i - 1] &amp;= self.check_column(cell, i as u8);
            candidates[i - 1] &amp;= self.check_square(cell, i as u8);
        }

        if candidates.iter().filter(|&amp;&amp;x| x).count() == 1 {
            return Some(candidates.iter().position(|&amp;x| x).unwrap() as u8 + 1);
        }
        None
    }

    fn check_row(&amp;self, cell: Cell, num: u8) -&gt; bool {
        self.data[cell.0].iter().all(|&amp;i| i != num)
    }

    fn check_column(&amp;self, cell: Cell, num: u8) -&gt; bool {
        self.data.iter().all(|row| row[cell.1] != num)
    }

    fn check_square(&amp;self, cell: Cell, num: u8) -&gt; bool {
        let truncated_range_of_3 = |x| {
            let start = (x / 3) * 3;
            start..start + 3
        };

        let rows = truncated_range_of_3(cell.0);
        let cols = truncated_range_of_3(cell.1);

        rows.cartesian_product(cols).all(|(row, col)| self.data[row][col] != num)
    }
}

/// Iterate through empty cells.
impl Iterator for Grid {
    type Item = Cell;

    fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; {
        let starting_point = (self.current.0, self.current.1);
        loop {
            self.current.0 = (self.current.0 + 1) % 9;
            if self.current.0 == 0 {
                self.current.1 = (self.current.1 + 1) % 9;
            }
            if (self.current.0, self.current.1) == starting_point {
                return None;
            }
            if self.data[self.current.0][self.current.1] == 0 {
                break;
            }
        }
        Some(self.current)
    }
}

fn main() {
    let mut grid = Grid {
        data: [
            [1, 6, 4, 0, 0, 0, 0, 0, 2],
            [2, 0, 0, 4, 0, 3, 9, 1, 0],
            [0, 0, 5, 0, 8, 0, 4, 0, 7],
            [0, 9, 0, 0, 0, 6, 5, 0, 0],
            [5, 0, 0, 1, 0, 2, 0, 0, 8],
            [0, 0, 8, 9, 0, 0, 0, 3, 0],
            [8, 0, 9, 0, 4, 0, 2, 0, 0],
            [0, 7, 3, 5, 0, 9, 0, 0, 1],
            [4, 0, 0, 0, 0, 0, 6, 7, 9],
        ],
        current: (0, 0),
    };

    while let Some(_) = grid.next() {
        let empty_cell = grid.current;

        if let Some(i) = grid.check(empty_cell) {
            grid.data[empty_cell.0][empty_cell.1] = i;
        }
    }

    for row in &amp;grid.data {
        println!("{:?}", row);
    }
}


That unwrap bothers me, but I'm not sure that this is really clearer:

let mut x = candidates.iter().enumerate().filter_map(|(pos, &amp;check)| {
    if check { Some(pos as u8 + 1) } else { None }
}).fuse();

match (x.next(), x.next()) {
    (Some(pos), None) =&gt; Some(pos),
    _ =&gt; None,
}


It can be made much nicer by abandoning the array at all. This saves (a tiny bit of) stack space but also probably speeds up the program (by a tiny amount) — the function exits as soon as a second possibility is found:

fn check(&amp;mut self, cell: Cell) -&gt; Option&lt;u8&gt; {
    let mut possibilities = (1..10)
        .filter(|&amp;i| self.check_row(cell, i))
        .filter(|&amp;i| self.check_column(cell, i))
        .filter(|&amp;i| self.check_square(cell, i))
        .fuse();

    match (possibilities.next(), possibilities.next()) {
        (Some(pos), None) =&gt; Some(pos),
        _ =&gt; None,
    }
}


Good news! My version of the code passes every single test case you provided!