-
Notifications
You must be signed in to change notification settings - Fork 0
/
valid_sudoku.rs
135 lines (118 loc) · 4.18 KB
/
valid_sudoku.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// Determine if a `9 x 9` Sudoku board is valid. Only the filled cells need to
/// be validated according to the following rules:
///
/// Each row must contain the digits `1-9` without repetition.
///
/// Each column must contain the digits `1-9` without repetition.
///
/// Each of the nine `3 x 3` sub-boxes of the grid must contain the digits `1-9`
/// without repetition.
///
/// Note:
/// * A Sudoku board (partially filled) could be valid but is not necessarily
/// solvable.
///
/// * Only the filled cells need to be validated according to the mentioned
/// rules.
struct Solution;
impl Solution {
fn char_to_index(c: char) -> usize {
c.to_digit(10).unwrap_or_default() as usize
}
fn is_valid_component<F>(board: &Vec<Vec<char>>, f: F) -> bool
where F: Fn(&Vec<Vec<char>>, usize) -> char {
let mut result = true;
let mut working = vec![0; 10];
for i in 0..9 {
let value = f(board, i);
if value != '.' {
let w = Self::char_to_index(value);
if working[w] == w {
result = false;
break;
} else { working[w] = w; }
}
}
result
}
fn is_valid_section(board: &Vec<Vec<char>>, sec: usize) -> bool {
let row_offset = match sec {
0 | 1 | 2 => 0,
3 | 4 | 5 => 3,
6 | 7 | 8 => 6,
_ => 0,
};
let col_offset = match sec {
0 | 3 | 6 => 0,
1 | 4 | 7 => 3,
2 | 5 | 8 => 6,
_ => 0,
};
Self::is_valid_component(board, |board, num| {
let (row, col) = match num {
0 => (0 + row_offset, 0 + col_offset),
1 => (0 + row_offset, 1 + col_offset),
2 => (0 + row_offset, 2 + col_offset),
3 => (1 + row_offset, 0 + col_offset),
4 => (1 + row_offset, 1 + col_offset),
5 => (1 + row_offset, 2 + col_offset),
6 => (2 + row_offset, 0 + col_offset),
7 => (2 + row_offset, 1 + col_offset),
8 => (2 + row_offset, 2 + col_offset),
_ => (0, 0)
};
board[row][col]
})
}
fn is_valid_column(board: &Vec<Vec<char>>, col: usize) -> bool {
Self::is_valid_component(board, |board, row| board[row][col])
}
fn is_valid_row(board: &Vec<Vec<char>>, row: usize) -> bool {
Self::is_valid_component(board, |board, col| board[row][col])
}
pub fn is_valid_sudoku(board: Vec<Vec<char>>) -> bool {
let mut result = true;
for i in 0..9 {
result = result && Self::is_valid_row(&board, i);
result = result && Self::is_valid_column(&board, i);
result = result && Self::is_valid_section(&board, i);
}
result
}
}
#[cfg(test)]
mod tests {
use super::Solution;
#[test]
fn example_1() {
let board = vec![
vec!['5','3','.','.','7','.','.','.','.'],
vec!['6','.','.','1','9','5','.','.','.'],
vec!['.','9','8','.','.','.','.','6','.'],
vec!['8','.','.','.','6','.','.','.','3'],
vec!['4','.','.','8','.','3','.','.','1'],
vec!['7','.','.','.','2','.','.','.','6'],
vec!['.','6','.','.','.','.','2','8','.'],
vec!['.','.','.','4','1','9','.','.','5'],
vec!['.','.','.','.','8','.','.','7','9']
];
let result = Solution::is_valid_sudoku(board);
assert!(result);
}
#[test]
fn example_2() {
let board = vec![
vec!['8','3','.','.','7','.','.','.','.'],
vec!['6','.','.','1','9','5','.','.','.'],
vec!['.','9','8','.','.','.','.','6','.'],
vec!['8','.','.','.','6','.','.','.','3'],
vec!['4','.','.','8','.','3','.','.','1'],
vec!['7','.','.','.','2','.','.','.','6'],
vec!['.','6','.','.','.','.','2','8','.'],
vec!['.','.','.','4','1','9','.','.','5'],
vec!['.','.','.','.','8','.','.','7','9']
];
let result = Solution::is_valid_sudoku(board);
assert!(!result);
}
}