Skip to content

Instantly share code, notes, and snippets.

@hskang9
Created October 7, 2022 16:27
Show Gist options
  • Save hskang9/d93928eb7e18d21d5cb2c9738708a229 to your computer and use it in GitHub Desktop.
Save hskang9/d93928eb7e18d21d5cb2c9738708a229 to your computer and use it in GitHub Desktop.
use std::io::{Error, ErrorKind};
use std::str::FromStr;
use std::collections::HashSet;
use std::convert::TryInto;
const WIDTH : usize = 9;
const GRID_SIZE : usize = WIDTH * WIDTH;
#[derive(Debug, PartialEq)]
struct Sudoku {
pub grid: [i32; GRID_SIZE],
}
impl Sudoku {
pub fn new(grid : [i32; GRID_SIZE]) -> Sudoku {
Sudoku {
grid
}
}
pub fn get_row_iter(&self, idx: usize) -> impl Iterator<Item = &i32> {
let slice = &self.grid[WIDTH * idx ..];
slice.iter().take(WIDTH)
}
pub fn get_col_iter(&self, idx: usize) -> impl Iterator<Item = &i32> {
let slice = &self.grid[idx..];
slice.iter().step_by(WIDTH)
}
pub fn get_square_iter(&self, idx: usize) -> impl Iterator<Item = &i32> {
let idx1 = (idx / 3) * 3 * WIDTH + (idx % 3) * 3;
let idx2 = idx1 + WIDTH;
let idx3 = idx2 + WIDTH;
let it1 = self.grid[idx1..].iter().take(3);
let it2 = self.grid[idx2..].iter().take(3);
let it3 = self.grid[idx3..].iter().take(3);
it1.chain(it2.chain(it3))
}
pub fn as_rows(&self) -> Vec<impl Iterator<Item = &i32>> {
let v : Vec<usize> = (0..WIDTH).collect();
v.iter().map( |&i| self.get_row_iter(i) ).collect()
}
pub fn as_cols(&self) -> Vec<impl Iterator<Item = &i32>> {
let v : Vec<usize> = (0..WIDTH).collect();
v.iter().map( |&i| self.get_col_iter(i) ).collect()
}
pub fn as_squares(&self) -> Vec<impl Iterator<Item = &i32>> {
let v : Vec<usize> = (0..WIDTH).collect();
v.iter().map( |&i| self.get_square_iter(i) ).collect()
}
fn is_section_complete<'a> (it : impl Iterator<Item = &'a i32>) -> bool {
static VALUES : [i32; WIDTH] = [1,2,3,4,5,6,7,8,9];
let set1 : HashSet<&i32> = VALUES.iter().collect();
let set2 : HashSet<&i32> = it.collect();
set1 == set2
}
pub fn valid(&self) -> bool {
for row in self.as_rows() {
if !Sudoku::is_section_complete(row) { return false }
}
for col in self.as_cols() {
if !Sudoku::is_section_complete(col) { return false }
}
for sqr in self.as_squares() {
if !Sudoku::is_section_complete(sqr) { return false }
}
true
}
}
impl FromStr for Sudoku {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut grid = vec![];
let rows = s.split("\n").collect::<Vec<&str>>();
for row in rows {
if row.len() != WIDTH {
return Err(Error::new(ErrorKind::InvalidData, "Invalid row length"));
} else {
for c in row.chars() {
if !c.is_digit(10) {
return Err(Error::new(ErrorKind::InvalidData, "Invalid number"));
}
grid.push(c.to_digit(10).unwrap() as i32);
}
}
}
println!("{:?} {}", grid, grid.len());
let grid_slice: [i32; GRID_SIZE] = grid[..GRID_SIZE].try_into().unwrap();
println!("{:?}", grid_slice);
Ok(Sudoku::new(grid_slice))
}
}
fn main () {
let s: Sudoku = "123456789\n\
456789123\n\
789123456\n\
234567891\n\
567891234\n\
891234567\n\
345678912\n\
678912345\n\
912345678".parse().unwrap();
println!("{:?}", s);
println!("{}", s.valid());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_sudoku() {
let sudoku: Sudoku = "534678912\n\
672195348\n\
198342567\n\
859761423\n\
426853791\n\
713924856\n\
961537284\n\
287419635\n\
345286179"
.parse()
.unwrap();
assert!(sudoku.valid());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment