2014-02-07 13:08:32 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-10 19:32:48 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-05-10 19:39:08 -05:00
|
|
|
// ignore-pretty very bad with line comments
|
|
|
|
|
2015-03-05 20:33:58 -06:00
|
|
|
#![feature(box_syntax, core)]
|
2014-07-18 07:45:17 -05:00
|
|
|
#![allow(non_snake_case)]
|
2013-10-23 03:49:18 -05:00
|
|
|
|
2015-02-25 01:27:20 -06:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::io;
|
2015-02-16 08:04:02 -06:00
|
|
|
use std::env;
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// Computes a single solution to a given 9x9 sudoku
|
|
|
|
//
|
|
|
|
// Call with "-" to read input sudoku from stdin
|
|
|
|
//
|
|
|
|
// The expected line-based format is:
|
|
|
|
//
|
|
|
|
// 9,9
|
|
|
|
// <row>,<column>,<color>
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
|
|
|
|
// A color of 0 indicates an empty field.
|
|
|
|
//
|
|
|
|
// If called without arguments, sudoku solves a built-in example sudoku
|
|
|
|
//
|
|
|
|
|
|
|
|
// internal type of sudoku grids
|
2015-02-25 01:27:20 -06:00
|
|
|
type grid = Vec<Vec<u8>>;
|
2011-11-19 18:53:12 -06:00
|
|
|
|
2013-03-17 05:41:03 -05:00
|
|
|
struct Sudoku {
|
|
|
|
grid: grid
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl Sudoku {
|
2013-03-21 21:07:54 -05:00
|
|
|
pub fn new(g: grid) -> Sudoku {
|
2013-03-17 05:41:03 -05:00
|
|
|
return Sudoku { grid: g }
|
|
|
|
}
|
|
|
|
|
2014-12-19 20:20:51 -06:00
|
|
|
pub fn from_vec(vec: &[[u8;9];9]) -> Sudoku {
|
2015-02-18 08:05:34 -06:00
|
|
|
let g = (0..9).map(|i| {
|
|
|
|
(0..9).map(|j| { vec[i][j] }).collect()
|
2015-01-02 01:53:35 -06:00
|
|
|
}).collect();
|
2013-03-17 05:41:03 -05:00
|
|
|
return Sudoku::new(g)
|
|
|
|
}
|
|
|
|
|
2015-02-25 01:27:20 -06:00
|
|
|
pub fn read(reader: &mut BufRead) -> Sudoku {
|
2014-04-15 20:17:48 -05:00
|
|
|
/* assert first line is exactly "9,9" */
|
2015-02-25 01:27:20 -06:00
|
|
|
let mut s = String::new();
|
|
|
|
reader.read_line(&mut s).unwrap();
|
|
|
|
assert_eq!(s, "9,9\n");
|
2013-03-17 05:41:03 -05:00
|
|
|
|
2015-07-08 15:52:55 -05:00
|
|
|
let mut g = vec![vec![0, 0, 0, 0, 0, 0, 0, 0, 0]; 10];
|
2013-12-08 01:12:07 -06:00
|
|
|
for line in reader.lines() {
|
2014-03-21 06:37:41 -05:00
|
|
|
let line = line.unwrap();
|
2015-02-01 20:53:25 -06:00
|
|
|
let comps: Vec<&str> = line
|
2014-05-20 01:19:56 -05:00
|
|
|
.trim()
|
|
|
|
.split(',')
|
|
|
|
.collect();
|
2013-06-09 08:10:50 -05:00
|
|
|
|
2015-02-18 08:05:34 -06:00
|
|
|
if comps.len() == 3 {
|
2015-01-02 01:53:35 -06:00
|
|
|
let row = comps[0].parse::<u8>().unwrap();
|
|
|
|
let col = comps[1].parse::<u8>().unwrap();
|
2015-02-25 01:27:20 -06:00
|
|
|
g[row as usize][col as usize] = comps[2].parse().unwrap();
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
else {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("Invalid sudoku file");
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Sudoku::new(g)
|
|
|
|
}
|
|
|
|
|
2015-02-25 01:27:20 -06:00
|
|
|
pub fn write(&self, writer: &mut Write) {
|
2015-01-26 14:46:12 -06:00
|
|
|
for row in 0u8..9u8 {
|
2015-02-25 01:27:20 -06:00
|
|
|
write!(writer, "{}", self.grid[row as usize][0]);
|
2015-01-26 14:46:12 -06:00
|
|
|
for col in 1u8..9u8 {
|
2015-02-25 01:27:20 -06:00
|
|
|
write!(writer, " {}", self.grid[row as usize][col as usize]);
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
2013-10-17 23:08:48 -05:00
|
|
|
write!(writer, "\n");
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// solve sudoku grid
|
|
|
|
pub fn solve(&mut self) {
|
2014-03-05 16:02:44 -06:00
|
|
|
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
2015-03-03 02:42:26 -06:00
|
|
|
for row in 0..9 {
|
|
|
|
for col in 0..9 {
|
2015-02-25 01:27:20 -06:00
|
|
|
let color = self.grid[row as usize][col as usize];
|
2015-03-03 02:42:26 -06:00
|
|
|
if color == 0 {
|
2013-06-11 21:13:42 -05:00
|
|
|
work.push((row, col));
|
|
|
|
}
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-18 08:05:34 -06:00
|
|
|
let mut ptr = 0;
|
2013-05-14 04:52:12 -05:00
|
|
|
let end = work.len();
|
2014-01-19 02:21:14 -06:00
|
|
|
while ptr < end {
|
2014-10-15 01:05:01 -05:00
|
|
|
let (row, col) = work[ptr];
|
2013-03-17 05:41:03 -05:00
|
|
|
// is there another color to try?
|
2015-02-25 01:27:20 -06:00
|
|
|
let the_color = self.grid[row as usize][col as usize] +
|
2014-03-05 17:28:08 -06:00
|
|
|
(1 as u8);
|
|
|
|
if self.next_color(row, col, the_color) {
|
2013-03-17 05:41:03 -05:00
|
|
|
// yes: advance work list
|
2015-02-18 08:05:34 -06:00
|
|
|
ptr = ptr + 1;
|
2013-03-17 05:41:03 -05:00
|
|
|
} else {
|
|
|
|
// no: redo this field aft recoloring pred; unless there is none
|
2015-02-18 08:05:34 -06:00
|
|
|
if ptr == 0 { panic!("No solution found for this sudoku"); }
|
|
|
|
ptr = ptr - 1;
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-17 05:41:03 -05:00
|
|
|
fn next_color(&mut self, row: u8, col: u8, start_color: u8) -> bool {
|
2015-03-03 02:42:26 -06:00
|
|
|
if start_color < 10 {
|
2011-11-19 18:53:12 -06:00
|
|
|
// colors not yet used
|
2015-02-17 14:41:32 -06:00
|
|
|
let mut avail: Box<_> = box Colors::new(start_color);
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// drop colors already in use in neighbourhood
|
2014-06-25 01:11:57 -05:00
|
|
|
self.drop_colors(&mut *avail, row, col);
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// find first remaining color that is available
|
2013-03-17 05:41:03 -05:00
|
|
|
let next = avail.next();
|
2015-02-25 01:27:20 -06:00
|
|
|
self.grid[row as usize][col as usize] = next;
|
2015-03-03 02:42:26 -06:00
|
|
|
return 0 != next;
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
2015-03-03 02:42:26 -06:00
|
|
|
self.grid[row as usize][col as usize] = 0;
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// find colors available in neighbourhood of (row, col)
|
2013-03-17 05:41:03 -05:00
|
|
|
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
2015-03-03 02:42:26 -06:00
|
|
|
for idx in 0..9 {
|
2014-10-15 01:05:01 -05:00
|
|
|
/* check same column fields */
|
2015-02-25 01:27:20 -06:00
|
|
|
avail.remove(self.grid[idx as usize][col as usize]);
|
2014-10-15 01:05:01 -05:00
|
|
|
/* check same row fields */
|
2015-02-25 01:27:20 -06:00
|
|
|
avail.remove(self.grid[row as usize][idx as usize]);
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// check same block fields
|
2015-03-03 02:42:26 -06:00
|
|
|
let row0 = (row / 3) * 3;
|
|
|
|
let col0 = (col / 3) * 3;
|
|
|
|
for alt_row in row0..row0 + 3 {
|
|
|
|
for alt_col in col0..col0 + 3 {
|
2015-02-25 01:27:20 -06:00
|
|
|
avail.remove(self.grid[alt_row as usize][alt_col as usize]);
|
2013-08-01 17:35:46 -05:00
|
|
|
}
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stores available colors as simple bitfield, bit 0 is always unset
|
|
|
|
struct Colors(u16);
|
|
|
|
|
2015-03-03 02:42:26 -06:00
|
|
|
static HEADS: u16 = (1 << 10) - 1; /* bits 9..0 */
|
2013-03-17 05:41:03 -05:00
|
|
|
|
|
|
|
impl Colors {
|
2013-03-21 21:07:54 -05:00
|
|
|
fn new(start_color: u8) -> Colors {
|
2013-03-17 05:41:03 -05:00
|
|
|
// Sets bits 9..start_color
|
2015-03-03 02:42:26 -06:00
|
|
|
let tails = !0 << start_color as usize;
|
2013-07-17 14:31:20 -05:00
|
|
|
return Colors(HEADS & tails);
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
2011-11-19 18:53:12 -06:00
|
|
|
|
2013-03-17 05:41:03 -05:00
|
|
|
fn next(&self) -> u8 {
|
2013-11-01 20:06:31 -05:00
|
|
|
let Colors(c) = *self;
|
|
|
|
let val = c & HEADS;
|
2015-03-03 02:42:26 -06:00
|
|
|
if 0 == val {
|
|
|
|
return 0;
|
2013-05-24 21:35:29 -05:00
|
|
|
} else {
|
2014-04-14 05:04:14 -05:00
|
|
|
return val.trailing_zeros() as u8
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-17 05:41:03 -05:00
|
|
|
fn remove(&mut self, color: u8) {
|
2015-03-03 02:42:26 -06:00
|
|
|
if color != 0 {
|
2013-11-01 20:06:31 -05:00
|
|
|
let Colors(val) = *self;
|
2015-03-03 02:42:26 -06:00
|
|
|
let mask = !(1 << color as usize);
|
2013-03-17 05:41:03 -05:00
|
|
|
*self = Colors(val & mask);
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 20:20:51 -06:00
|
|
|
static DEFAULT_SUDOKU: [[u8;9];9] = [
|
2013-03-17 05:41:03 -05:00
|
|
|
/* 0 1 2 3 4 5 6 7 8 */
|
2015-03-03 02:42:26 -06:00
|
|
|
/* 0 */ [0, 4, 0, 6, 0, 0, 0, 3, 2],
|
|
|
|
/* 1 */ [0, 0, 8, 0, 2, 0, 0, 0, 0],
|
|
|
|
/* 2 */ [7, 0, 0, 8, 0, 0, 0, 0, 0],
|
|
|
|
/* 3 */ [0, 0, 0, 5, 0, 0, 0, 0, 0],
|
|
|
|
/* 4 */ [0, 5, 0, 0, 0, 3, 6, 0, 0],
|
|
|
|
/* 5 */ [6, 8, 0, 0, 0, 0, 0, 9, 0],
|
|
|
|
/* 6 */ [0, 9, 5, 0, 0, 6, 0, 7, 0],
|
|
|
|
/* 7 */ [0, 0, 0, 0, 4, 0, 0, 6, 0],
|
|
|
|
/* 8 */ [4, 0, 0, 0, 0, 7, 2, 0, 3]
|
2013-03-17 05:41:03 -05:00
|
|
|
];
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2014-12-19 20:20:51 -06:00
|
|
|
static DEFAULT_SOLUTION: [[u8;9];9] = [
|
2013-03-17 05:41:03 -05:00
|
|
|
/* 0 1 2 3 4 5 6 7 8 */
|
2015-03-03 02:42:26 -06:00
|
|
|
/* 0 */ [1, 4, 9, 6, 7, 5, 8, 3, 2],
|
|
|
|
/* 1 */ [5, 3, 8, 1, 2, 9, 7, 4, 6],
|
|
|
|
/* 2 */ [7, 2, 6, 8, 3, 4, 1, 5, 9],
|
|
|
|
/* 3 */ [9, 1, 4, 5, 6, 8, 3, 2, 7],
|
|
|
|
/* 4 */ [2, 5, 7, 4, 9, 3, 6, 1, 8],
|
|
|
|
/* 5 */ [6, 8, 3, 7, 1, 2, 5, 9, 4],
|
|
|
|
/* 6 */ [3, 9, 5, 2, 8, 6, 4, 7, 1],
|
|
|
|
/* 7 */ [8, 7, 2, 3, 4, 1, 9, 6, 5],
|
|
|
|
/* 8 */ [4, 6, 1, 9, 5, 7, 2, 8, 3]
|
2013-03-17 05:41:03 -05:00
|
|
|
];
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_new_works() {
|
2015-03-03 02:42:26 -06:00
|
|
|
assert_eq!(*Colors::new(1), 1022);
|
|
|
|
assert_eq!(*Colors::new(2), 1020);
|
|
|
|
assert_eq!(*Colors::new(3), 1016);
|
|
|
|
assert_eq!(*Colors::new(4), 1008);
|
|
|
|
assert_eq!(*Colors::new(5), 992);
|
|
|
|
assert_eq!(*Colors::new(6), 960);
|
|
|
|
assert_eq!(*Colors::new(7), 896);
|
|
|
|
assert_eq!(*Colors::new(8), 768);
|
|
|
|
assert_eq!(*Colors::new(9), 512);
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_next_works() {
|
2015-03-03 02:42:26 -06:00
|
|
|
assert_eq!(Colors(0).next(), 0);
|
|
|
|
assert_eq!(Colors(2).next(), 1);
|
|
|
|
assert_eq!(Colors(4).next(), 2);
|
|
|
|
assert_eq!(Colors(8).next(), 3);
|
|
|
|
assert_eq!(Colors(16).next(), 4);
|
|
|
|
assert_eq!(Colors(32).next(), 5);
|
|
|
|
assert_eq!(Colors(64).next(), 6);
|
|
|
|
assert_eq!(Colors(128).next(), 7);
|
|
|
|
assert_eq!(Colors(256).next(), 8);
|
|
|
|
assert_eq!(Colors(512).next(), 9);
|
|
|
|
assert_eq!(Colors(1024).next(), 0);
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_remove_works() {
|
|
|
|
// GIVEN
|
|
|
|
let mut colors = Colors::new(1);
|
|
|
|
|
|
|
|
// WHEN
|
|
|
|
colors.remove(1);
|
|
|
|
|
|
|
|
// THEN
|
2015-03-03 02:42:26 -06:00
|
|
|
assert_eq!(colors.next(), 2);
|
2013-03-17 05:41:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-07-17 14:31:20 -05:00
|
|
|
fn check_DEFAULT_SUDOKU_solution() {
|
2013-03-17 05:41:03 -05:00
|
|
|
// GIVEN
|
2013-07-17 14:31:20 -05:00
|
|
|
let mut sudoku = Sudoku::from_vec(&DEFAULT_SUDOKU);
|
|
|
|
let solution = Sudoku::from_vec(&DEFAULT_SOLUTION);
|
2013-03-17 05:41:03 -05:00
|
|
|
|
|
|
|
// WHEN
|
|
|
|
sudoku.solve();
|
|
|
|
|
|
|
|
// THEN
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(sudoku.equal(&solution));
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
2012-10-03 21:16:27 -05:00
|
|
|
fn main() {
|
2015-02-25 01:27:20 -06:00
|
|
|
let args = env::args();
|
2015-02-16 08:04:02 -06:00
|
|
|
let use_default = args.len() == 1;
|
2013-03-17 05:41:03 -05:00
|
|
|
let mut sudoku = if use_default {
|
2013-07-17 14:31:20 -05:00
|
|
|
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
2011-11-19 18:53:12 -06:00
|
|
|
} else {
|
2015-02-25 01:27:20 -06:00
|
|
|
let stdin = io::stdin();
|
|
|
|
let mut locked = stdin.lock();
|
|
|
|
Sudoku::read(&mut locked)
|
2011-11-19 18:53:12 -06:00
|
|
|
};
|
2013-03-17 05:41:03 -05:00
|
|
|
sudoku.solve();
|
2015-02-25 01:27:20 -06:00
|
|
|
let out = io::stdout();
|
|
|
|
sudoku.write(&mut out.lock());
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|