use rand::Rng;
use consts::*;
use types::{Entry, PubEntry, BlockFormatParseError, LineFormatParseError, NotEnoughRows};
use solver::SudokuSolver;
use generator::SudokuGenerator;
use std::{fmt, slice, iter, hash, cmp};
#[cfg(feature="serde")] use ::serde::{de, Serialize, Serializer, Deserialize, Deserializer};
#[derive(Copy, Clone)]
pub struct Sudoku(pub(crate) [u8; 81]);
#[cfg(feature="serde")]
impl Serialize for Sudoku {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer
{
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_str_line())
} else {
serializer.serialize_bytes(&self.0)
}
}
}
#[cfg(feature="serde")] struct ByteSudoku;
#[cfg(feature="serde")] struct StrSudoku;
#[cfg(feature="serde")]
impl<'de> de::Visitor<'de> for ByteSudoku {
type Value = Sudoku;
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(formatter, "81 numbers from 0 to 9 inclusive")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
Sudoku::from_bytes_slice(v).map_err(|_| {
E::custom("byte array has incorrect length or contains numbers not from 0 to 9")
})
}
}
#[cfg(feature="serde")]
impl<'de> de::Visitor<'de> for StrSudoku {
type Value = Sudoku;
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(formatter, "81 numbers from 0 to 9 inclusive")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Sudoku::from_str_line(v).map_err(E::custom)
}
}
#[cfg(feature="serde")]
impl<'de> Deserialize<'de> for Sudoku {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(StrSudoku)
} else {
deserializer.deserialize_bytes(ByteSudoku)
}
}
}
impl PartialEq for Sudoku {
fn eq(&self, other: &Sudoku) -> bool {
self.0[..] == other.0[..]
}
}
impl PartialOrd for Sudoku {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl Ord for Sudoku {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl hash::Hash for Sudoku {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher
{
self.0.hash(state)
}
}
impl Eq for Sudoku {}
impl fmt::Debug for Sudoku {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(fmt)
}
}
type R = ::rand::rngs::ThreadRng;
pub type Iter<'a> = iter::Map<slice::Iter<'a, u8>, fn(&u8)->Option<u8>>;
impl Sudoku {
pub fn generate_filled() -> Self {
SudokuGenerator::generate_filled()
}
pub fn generate_unique() -> Self {
Sudoku::generate_unique_from( Sudoku::generate_filled() )
}
pub fn generate_unique_from(mut sudoku: Sudoku) -> Self {
let mut cell_order = [0; 81];
cell_order.iter_mut()
.enumerate()
.for_each(|(cell, place)| *place = cell);
::rand::thread_rng().shuffle(&mut cell_order);
const CUTOFF: usize = 20;
let mut sudoku_tmp = sudoku;
for &cell in &cell_order[..CUTOFF] {
sudoku_tmp.0[cell] = 0;
}
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
} else {
for &cell in &cell_order[..CUTOFF] {
let mut sudoku_tmp = sudoku;
sudoku_tmp.0[cell] = 0;
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
}
}
}
let mut n_cell = CUTOFF;
while n_cell < 50 {
let mut sudoku_tmp = sudoku;
let cell1 = cell_order[n_cell];
let cell2 = cell_order[n_cell+1];
sudoku_tmp.0[cell1] = 0;
sudoku_tmp.0[cell2] = 0;
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
n_cell += 2;
continue
}
sudoku_tmp.0[cell2] = sudoku.0[cell2];
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
n_cell += 2;
continue
}
sudoku_tmp.0[cell1] = sudoku.0[cell1];
sudoku_tmp.0[cell2] = 0;
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
}
n_cell += 2;
}
for &cell in &cell_order[50..] {
let mut sudoku_tmp = sudoku;
sudoku_tmp.0[cell] = 0;
if sudoku_tmp.is_uniquely_solvable() {
sudoku = sudoku_tmp;
}
}
sudoku
}
pub fn from_bytes_slice(bytes: &[u8]) -> Result<Sudoku, ()> {
if bytes.len() != 81 { return Err(()) }
let mut sudoku = Sudoku([0; 81]);
match bytes.iter().all(|&byte| byte <= 9) {
true => {
sudoku.0.copy_from_slice(bytes);
Ok(sudoku)
},
false => Err(())
}
}
pub fn from_bytes(bytes: [u8; 81]) -> Result<Sudoku, ()> {
match bytes.iter().all(|&byte| byte <= 9) {
true => Ok(Sudoku(bytes)),
false => Err(()),
}
}
pub fn from_str_line(s: &str) -> Result<Sudoku, LineFormatParseError> {
let chars = s.as_bytes();
let mut grid = [0; N_CELLS];
let mut i = 0;
for (cell, &ch) in grid.iter_mut().zip(chars) {
match ch {
b'_' | b'.' => *cell = 0,
b'0' ... b'9' => *cell = ch - b'0',
b' ' | b'\t' => return Err(LineFormatParseError::NotEnoughCells(i)),
_ => return Err(
LineFormatParseError::InvalidEntry(
PubEntry {
cell: i,
ch: s[i as usize..].chars().next().unwrap(),
}
)
),
}
i += 1;
}
if i != 81 {
return Err(LineFormatParseError::NotEnoughCells(i))
}
if let Some(&ch) = chars.get(81) {
match ch {
b'\t' | b' ' | b'\r' | b'\n' | b';' | b',' => (),
b'_' | b'.' | b'0'...b'9' => {
return Err(LineFormatParseError::TooManyCells)
},
_ => return Err(LineFormatParseError::MissingCommentDelimiter),
}
}
Ok(Sudoku(grid))
}
pub fn from_str_block(s: &str) -> Result<Sudoku, BlockFormatParseError> {
let mut grid = [0; N_CELLS];
#[derive(PartialEq)]
enum Format {
Unknown,
Delimited,
DelimitedPlus,
Bare,
}
let mut format = Format::Unknown;
let mut n_line_sud = 0;
for (n_line_str, line) in s.lines().enumerate() {
if n_line_sud == 9 {
match line.trim().is_empty() {
true => break,
false => return Err(BlockFormatParseError::TooManyRows),
}
}
if (format == Format::Delimited || format == Format::DelimitedPlus)
&& (n_line_str == 3 || n_line_str == 7)
{
if n_line_str == 3 && (line.starts_with("---+---+---") || line.starts_with("---+---+--- ")) {
format = Format::DelimitedPlus;
}
if format == Format::Delimited {
match !(line.starts_with("-----------") || line.starts_with("----------- ")) {
true => return Err(BlockFormatParseError::IncorrectFieldDelimiter),
false => continue,
}
}
if format == Format::DelimitedPlus {
match !(line.starts_with("---+---+---") || line.starts_with("---+---+--- ")) {
true => return Err(BlockFormatParseError::IncorrectFieldDelimiter),
false => continue,
}
}
}
let mut n_col_sud = 0;
for (str_col, ch) in line.chars().enumerate() {
if n_col_sud == 9 {
match ch {
' ' | '\t' => break,
'1'...'9' | '_' | '.' | '0' => return Err(BlockFormatParseError::InvalidLineLength(n_line_sud)),
_ => return Err(BlockFormatParseError::MissingCommentDelimiter(n_line_sud))
}
}
if str_col == 3 || str_col == 7 {
if format == Format::Unknown {
format = if ch == '|' { Format::Delimited } else { Format::Bare };
}
if format == Format::Delimited || format == Format::DelimitedPlus {
match ch {
'|' => continue,
_ => return Err(BlockFormatParseError::IncorrectFieldDelimiter),
}
}
}
let cell = n_line_sud * 9 + n_col_sud;
match ch {
'_' | '.' => grid[cell as usize] = 0,
'0'...'9' => grid[cell as usize] = ch as u8 - b'0',
_ => return Err(BlockFormatParseError::InvalidEntry(PubEntry{cell: cell as u8, ch })),
}
n_col_sud += 1;
}
if n_col_sud != 9 {
return Err(BlockFormatParseError::InvalidLineLength(n_line_sud))
}
n_line_sud += 1;
}
if n_line_sud != 9 {
return Err(BlockFormatParseError::NotEnoughRows(n_line_sud+1))
}
Ok(Sudoku(grid))
}
pub fn from_str_block_permissive(s: &str) -> Result<Sudoku, NotEnoughRows>
{
let mut grid = [0; N_CELLS];
let mut valid_rows = 0;
for line in s.lines() {
let mut row_vals = [0; 9];
let mut nums_in_row = 0;
for ch in line.chars() {
if ['.', '_'].contains(&ch) {
row_vals[nums_in_row] = 0;
nums_in_row += 1;
} else if '0' <= ch && ch <= '9' {
row_vals[nums_in_row] = ch as u8 - b'0';
nums_in_row += 1;
}
if nums_in_row == 9 {
grid[valid_rows*9..valid_rows*9 + 9].copy_from_slice(&row_vals);
valid_rows += 1;
break
}
}
if valid_rows == 9 {
return Ok(Sudoku(grid))
}
}
Err(NotEnoughRows(valid_rows as u8))
}
pub fn solve(&mut self) -> bool {
match self.clone().solve_one() {
Some(solution) => {
*self = solution;
true
},
None => false,
}
}
pub fn solve_one(self) -> Option<Sudoku> {
let mut buf = [[0; 81]];
match self.solve_at_most_buffer(&mut buf, 1) == 1 {
true => Some(Sudoku(buf[0])),
false => None,
}
}
pub fn solve_unique(self) -> Option<Sudoku> {
let mut nums_contained: u16 = 0;
let mut n_clues = 0;
self.iter()
.filter_map(|id| id)
.for_each(|num| {
nums_contained |= 1 << num;
n_clues += 1;
});
if n_clues < 17 || nums_contained.count_ones() < 8 {
return None
};
let mut solution = [[0; 81]];
let n_solutions = self.solve_at_most_buffer(&mut solution, 2);
match n_solutions == 1 {
true => Some(Sudoku(solution[0])),
false => None,
}
}
pub fn count_at_most(self, limit: usize) -> usize {
SudokuSolver::from_sudoku(self)
.ok()
.map_or(0, |solver| solver.count_at_most(limit))
}
pub fn is_uniquely_solvable(self) -> bool {
self.count_at_most(2) == 1
}
pub fn solve_at_most(self, limit: usize) -> Vec<Sudoku> {
SudokuSolver::from_sudoku(self)
.ok()
.map_or(vec![], |solver| solver.solve_at_most(limit))
}
pub fn solve_at_most_buffer(self, target: &mut [[u8; 81]], limit: usize) -> usize {
SudokuSolver::from_sudoku(self)
.ok()
.map_or(0, |solver| solver.solve_at_most_buffer(target, limit))
}
pub fn is_solved(&self) -> bool {
SudokuSolver::from_sudoku(*self)
.ok()
.as_ref()
.map_or(false, SudokuSolver::is_solved)
}
pub fn n_clues(&self) -> u8 {
self.0.iter().filter(|&&num| num != 0).count() as u8
}
pub fn shuffle(&mut self) {
let rng = &mut ::rand::thread_rng();
self.shuffle_digits(rng);
self.shuffle_bands(rng);
self.shuffle_stacks(rng);
for i in 0..3 {
self.shuffle_cols_of_stack(rng, i);
self.shuffle_rows_of_band(rng, i);
}
if rng.gen() {
self.transpose();
}
}
#[inline]
fn shuffle_digits(&mut self, rng: &mut R) {
let mut digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut permutation = rng.gen_range(0, 362880u32);
for n_choices in (1..10).rev() {
let num = permutation % n_choices;
permutation /= n_choices;
digits.swap(n_choices as usize, 1 + num as usize);
}
for num in self.0.iter_mut() {
*num = digits[*num as usize];
}
}
#[inline]
fn shuffle_rows_of_band(&mut self, rng: &mut R, band: u8) {
debug_assert!(band < 3);
let first_row = band*3;
self.swap_rows(first_row, rng.gen_range(first_row, first_row+3));
self.swap_rows(first_row+1, rng.gen_range(first_row+1, first_row+3));
}
#[inline]
fn shuffle_cols_of_stack(&mut self, rng: &mut R, stack: u8) {
debug_assert!(stack < 3);
let first_col = stack*3;
self.swap_cols(first_col, rng.gen_range(first_col, first_col+3));
self.swap_cols(first_col+1, rng.gen_range(first_col+1, first_col+3));
}
#[inline]
fn shuffle_bands(&mut self, rng: &mut R) {
self.swap_bands(0, rng.gen_range(0, 3));
self.swap_bands(1, rng.gen_range(1, 3));
}
#[inline]
fn shuffle_stacks(&mut self, rng: &mut R) {
self.swap_stacks(0, rng.gen_range(0, 3));
self.swap_stacks(1, rng.gen_range(1, 3));
}
#[inline]
fn swap_rows(&mut self, row1: u8, row2: u8) {
if row1 == row2 { return }
let start1 = (row1*9) as usize;
let start2 = (row2*9) as usize;
self.swap_cells(
(start1..start1+9).zip(start2..start2+9)
)
}
#[inline]
fn swap_cols(&mut self, col1: u8, col2: u8) {
if col1 == col2 { return }
debug_assert!(col1 < 9);
debug_assert!(col2 < 9);
self.swap_cells(
(0..9).map(|row| (row*9 + col1 as usize, row*9 + col2 as usize))
)
}
#[inline]
fn swap_stacks(&mut self, stack1: u8, stack2: u8) {
if stack1 == stack2 { return }
debug_assert!(stack1 < 3);
debug_assert!(stack2 < 3);
for inner_col in 0..3 {
self.swap_cols(stack1*3+inner_col, stack2*3+inner_col);
}
}
#[inline]
fn swap_bands(&mut self, band1: u8, band2: u8) {
if band1 == band2 { return }
debug_assert!(band1 < 3);
debug_assert!(band2 < 3);
for inner_row in 0..3 {
self.swap_cols(band1*3+inner_row, band2*3+inner_row);
}
}
#[inline]
fn transpose(&mut self) {
use ::std::iter::repeat;
self.swap_cells(
(0..9)
.flat_map(|row| repeat(row).zip(row+1..9))
.map(|(row, col)| (row*9+col, col*9+row))
)
}
#[inline]
fn swap_cells(&mut self, iter: impl Iterator<Item=(usize, usize)>) {
for (idx1, idx2) in iter {
debug_assert!(idx1 != idx2);
let a = self.0[idx1];
let b = self.0[idx2];
self.0[idx1] = b;
self.0[idx2] = a;
}
}
pub fn iter(&self) -> Iter {
self.0.iter().map(num_to_opt)
}
pub fn to_bytes(self) -> [u8; 81] {
self.0
}
pub fn to_str_line(&self) -> SudokuLine {
let mut chars = [0; 81];
for (char_, entry) in chars.iter_mut().zip(self.iter()) {
*char_ = match entry {
Some(num) => num + b'0',
None => b'.',
};
}
SudokuLine(chars)
}
}
fn num_to_opt(num: &u8) -> Option<u8> {
if *num == 0 { None } else { Some(*num) }
}
impl fmt::Display for Sudoku {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for entry in self.0.iter().enumerate().map(|(cell, &num)| Entry { cell: cell as u8, num } ) {
try!( match (entry.row(), entry.col()) {
(_, 3) | (_, 6) => write!(f, " "),
(3, 0) | (6, 0) => write!(f, "\n\n"),
(_, 0) => write!(f, "\n"),
_ => Ok(()),
});
try!( match entry.num() {
0 => write!(f, "_"),
1...9 => write!(f, "{}", entry.num()),
_ => unreachable!(),
});
}
Ok(())
}
}
#[derive(Copy, Clone)]
pub struct SudokuLine([u8; 81]);
impl PartialOrd for SudokuLine {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(other)
}
}
impl Ord for SudokuLine {
fn cmp(&self, other: &Self) -> cmp::Ordering {
(**self).cmp(other)
}
}
impl hash::Hash for SudokuLine {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher
{
(**self).hash(state)
}
}
impl PartialEq for SudokuLine {
fn eq(&self, other: &SudokuLine) -> bool {
self.0[..] == other.0[..]
}
}
impl Eq for SudokuLine {}
impl fmt::Debug for SudokuLine {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(fmt)
}
}
impl ::core::ops::Deref for SudokuLine {
type Target = str;
fn deref(&self) -> &Self::Target {
::core::str::from_utf8(&self.0).unwrap()
}
}
use ::core::ops::Deref;
impl ::core::fmt::Display for SudokuLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.deref())
}
}