2014-02-07 20:08:32 +01:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-10 17:32:48 -08: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 17:39:08 -07:00
|
|
|
// ignore-pretty very bad with line comments
|
|
|
|
|
2015-03-05 18:33:58 -08:00
|
|
|
#![feature(box_syntax, core)]
|
2014-07-19 00:45:17 +12:00
|
|
|
#![allow(non_snake_case)]
|
2013-10-23 04:49:18 -04:00
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::io;
|
2015-01-01 23:53:35 -08:00
|
|
|
use std::iter::repeat;
|
2015-02-16 16:04:02 +02:00
|
|
|
use std::env;
|
2011-11-20 01:53:12 +01: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-24 23:27:20 -08:00
|
|
|
type grid = Vec<Vec<u8>>;
|
2011-11-20 01:53:12 +01:00
|
|
|
|
2013-03-17 11:41:03 +01:00
|
|
|
struct Sudoku {
|
|
|
|
grid: grid
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl Sudoku {
|
2013-03-21 19:07:54 -07:00
|
|
|
pub fn new(g: grid) -> Sudoku {
|
2013-03-17 11:41:03 +01:00
|
|
|
return Sudoku { grid: g }
|
|
|
|
}
|
|
|
|
|
2014-12-20 15:20:51 +13:00
|
|
|
pub fn from_vec(vec: &[[u8;9];9]) -> Sudoku {
|
2015-02-18 09:05:34 -05:00
|
|
|
let g = (0..9).map(|i| {
|
|
|
|
(0..9).map(|j| { vec[i][j] }).collect()
|
2015-01-01 23:53:35 -08:00
|
|
|
}).collect();
|
2013-03-17 11:41:03 +01:00
|
|
|
return Sudoku::new(g)
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
pub fn read(reader: &mut BufRead) -> Sudoku {
|
2014-04-15 18:17:48 -07:00
|
|
|
/* assert first line is exactly "9,9" */
|
2015-02-24 23:27:20 -08:00
|
|
|
let mut s = String::new();
|
|
|
|
reader.read_line(&mut s).unwrap();
|
|
|
|
assert_eq!(s, "9,9\n");
|
2013-03-17 11:41:03 +01:00
|
|
|
|
2015-03-03 10:42:26 +02:00
|
|
|
let mut g = repeat(vec![0, 0, 0, 0, 0, 0, 0, 0, 0])
|
2015-01-01 23:53:35 -08:00
|
|
|
.take(10).collect::<Vec<_>>();
|
2013-12-08 16:12:07 +09:00
|
|
|
for line in reader.lines() {
|
2014-03-21 22:37:41 +11:00
|
|
|
let line = line.unwrap();
|
2015-02-01 21:53:25 -05:00
|
|
|
let comps: Vec<&str> = line
|
2014-05-19 23:19:56 -07:00
|
|
|
.trim()
|
|
|
|
.split(',')
|
|
|
|
.collect();
|
2013-06-09 23:10:50 +10:00
|
|
|
|
2015-02-18 09:05:34 -05:00
|
|
|
if comps.len() == 3 {
|
2015-01-01 23:53:35 -08:00
|
|
|
let row = comps[0].parse::<u8>().unwrap();
|
|
|
|
let col = comps[1].parse::<u8>().unwrap();
|
2015-02-24 23:27:20 -08:00
|
|
|
g[row as usize][col as usize] = comps[2].parse().unwrap();
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("Invalid sudoku file");
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Sudoku::new(g)
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
pub fn write(&self, writer: &mut Write) {
|
2015-01-26 15:46:12 -05:00
|
|
|
for row in 0u8..9u8 {
|
2015-02-24 23:27:20 -08:00
|
|
|
write!(writer, "{}", self.grid[row as usize][0]);
|
2015-01-26 15:46:12 -05:00
|
|
|
for col in 1u8..9u8 {
|
2015-02-24 23:27:20 -08:00
|
|
|
write!(writer, " {}", self.grid[row as usize][col as usize]);
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
2013-10-17 21:08:48 -07:00
|
|
|
write!(writer, "\n");
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// solve sudoku grid
|
|
|
|
pub fn solve(&mut self) {
|
2014-03-05 14:02:44 -08:00
|
|
|
let mut work: Vec<(u8, u8)> = Vec::new(); /* queue of uncolored fields */
|
2015-03-03 10:42:26 +02:00
|
|
|
for row in 0..9 {
|
|
|
|
for col in 0..9 {
|
2015-02-24 23:27:20 -08:00
|
|
|
let color = self.grid[row as usize][col as usize];
|
2015-03-03 10:42:26 +02:00
|
|
|
if color == 0 {
|
2013-06-11 19:13:42 -07:00
|
|
|
work.push((row, col));
|
|
|
|
}
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-18 09:05:34 -05:00
|
|
|
let mut ptr = 0;
|
2013-05-14 18:52:12 +09:00
|
|
|
let end = work.len();
|
2014-01-19 19:21:14 +11:00
|
|
|
while ptr < end {
|
2014-10-14 23:05:01 -07:00
|
|
|
let (row, col) = work[ptr];
|
2013-03-17 11:41:03 +01:00
|
|
|
// is there another color to try?
|
2015-02-24 23:27:20 -08:00
|
|
|
let the_color = self.grid[row as usize][col as usize] +
|
2014-03-05 15:28:08 -08:00
|
|
|
(1 as u8);
|
|
|
|
if self.next_color(row, col, the_color) {
|
2013-03-17 11:41:03 +01:00
|
|
|
// yes: advance work list
|
2015-02-18 09:05:34 -05:00
|
|
|
ptr = ptr + 1;
|
2013-03-17 11:41:03 +01:00
|
|
|
} else {
|
|
|
|
// no: redo this field aft recoloring pred; unless there is none
|
2015-02-18 09:05:34 -05:00
|
|
|
if ptr == 0 { panic!("No solution found for this sudoku"); }
|
|
|
|
ptr = ptr - 1;
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-17 11:41:03 +01:00
|
|
|
fn next_color(&mut self, row: u8, col: u8, start_color: u8) -> bool {
|
2015-03-03 10:42:26 +02:00
|
|
|
if start_color < 10 {
|
2011-11-20 01:53:12 +01:00
|
|
|
// colors not yet used
|
2015-02-17 21:41:32 +01:00
|
|
|
let mut avail: Box<_> = box Colors::new(start_color);
|
2011-11-20 01:53:12 +01:00
|
|
|
|
|
|
|
// drop colors already in use in neighbourhood
|
2014-06-24 23:11:57 -07:00
|
|
|
self.drop_colors(&mut *avail, row, col);
|
2011-11-20 01:53:12 +01:00
|
|
|
|
|
|
|
// find first remaining color that is available
|
2013-03-17 11:41:03 +01:00
|
|
|
let next = avail.next();
|
2015-02-24 23:27:20 -08:00
|
|
|
self.grid[row as usize][col as usize] = next;
|
2015-03-03 10:42:26 +02:00
|
|
|
return 0 != next;
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
2015-03-03 10:42:26 +02:00
|
|
|
self.grid[row as usize][col as usize] = 0;
|
2012-08-01 17:30:05 -07:00
|
|
|
return false;
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// find colors available in neighbourhood of (row, col)
|
2013-03-17 11:41:03 +01:00
|
|
|
fn drop_colors(&mut self, avail: &mut Colors, row: u8, col: u8) {
|
2015-03-03 10:42:26 +02:00
|
|
|
for idx in 0..9 {
|
2014-10-14 23:05:01 -07:00
|
|
|
/* check same column fields */
|
2015-02-24 23:27:20 -08:00
|
|
|
avail.remove(self.grid[idx as usize][col as usize]);
|
2014-10-14 23:05:01 -07:00
|
|
|
/* check same row fields */
|
2015-02-24 23:27:20 -08:00
|
|
|
avail.remove(self.grid[row as usize][idx as usize]);
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// check same block fields
|
2015-03-03 10:42:26 +02: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-24 23:27:20 -08:00
|
|
|
avail.remove(self.grid[alt_row as usize][alt_col as usize]);
|
2013-08-01 18:35:46 -04:00
|
|
|
}
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
}
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stores available colors as simple bitfield, bit 0 is always unset
|
|
|
|
struct Colors(u16);
|
|
|
|
|
2015-03-03 10:42:26 +02:00
|
|
|
static HEADS: u16 = (1 << 10) - 1; /* bits 9..0 */
|
2013-03-17 11:41:03 +01:00
|
|
|
|
|
|
|
impl Colors {
|
2013-03-21 19:07:54 -07:00
|
|
|
fn new(start_color: u8) -> Colors {
|
2013-03-17 11:41:03 +01:00
|
|
|
// Sets bits 9..start_color
|
2015-03-03 10:42:26 +02:00
|
|
|
let tails = !0 << start_color as usize;
|
2013-07-17 15:31:20 -04:00
|
|
|
return Colors(HEADS & tails);
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
2011-11-20 01:53:12 +01:00
|
|
|
|
2013-03-17 11:41:03 +01:00
|
|
|
fn next(&self) -> u8 {
|
2013-11-01 18:06:31 -07:00
|
|
|
let Colors(c) = *self;
|
|
|
|
let val = c & HEADS;
|
2015-03-03 10:42:26 +02:00
|
|
|
if 0 == val {
|
|
|
|
return 0;
|
2013-05-24 19:35:29 -07:00
|
|
|
} else {
|
2014-04-14 20:04:14 +10:00
|
|
|
return val.trailing_zeros() as u8
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-17 11:41:03 +01:00
|
|
|
fn remove(&mut self, color: u8) {
|
2015-03-03 10:42:26 +02:00
|
|
|
if color != 0 {
|
2013-11-01 18:06:31 -07:00
|
|
|
let Colors(val) = *self;
|
2015-03-03 10:42:26 +02:00
|
|
|
let mask = !(1 << color as usize);
|
2013-03-17 11:41:03 +01:00
|
|
|
*self = Colors(val & mask);
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-20 15:20:51 +13:00
|
|
|
static DEFAULT_SUDOKU: [[u8;9];9] = [
|
2013-03-17 11:41:03 +01:00
|
|
|
/* 0 1 2 3 4 5 6 7 8 */
|
2015-03-03 10:42:26 +02: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 11:41:03 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2014-12-20 15:20:51 +13:00
|
|
|
static DEFAULT_SOLUTION: [[u8;9];9] = [
|
2013-03-17 11:41:03 +01:00
|
|
|
/* 0 1 2 3 4 5 6 7 8 */
|
2015-03-03 10:42:26 +02: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 11:41:03 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_new_works() {
|
2015-03-03 10:42:26 +02: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 11:41:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_next_works() {
|
2015-03-03 10:42:26 +02: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 11:41:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn colors_remove_works() {
|
|
|
|
// GIVEN
|
|
|
|
let mut colors = Colors::new(1);
|
|
|
|
|
|
|
|
// WHEN
|
|
|
|
colors.remove(1);
|
|
|
|
|
|
|
|
// THEN
|
2015-03-03 10:42:26 +02:00
|
|
|
assert_eq!(colors.next(), 2);
|
2013-03-17 11:41:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-07-17 15:31:20 -04:00
|
|
|
fn check_DEFAULT_SUDOKU_solution() {
|
2013-03-17 11:41:03 +01:00
|
|
|
// GIVEN
|
2013-07-17 15:31:20 -04:00
|
|
|
let mut sudoku = Sudoku::from_vec(&DEFAULT_SUDOKU);
|
|
|
|
let solution = Sudoku::from_vec(&DEFAULT_SOLUTION);
|
2013-03-17 11:41:03 +01:00
|
|
|
|
|
|
|
// WHEN
|
|
|
|
sudoku.solve();
|
|
|
|
|
|
|
|
// THEN
|
2013-03-28 18:39:09 -07:00
|
|
|
assert!(sudoku.equal(&solution));
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|
|
|
|
|
2012-10-03 19:16:27 -07:00
|
|
|
fn main() {
|
2015-02-24 23:27:20 -08:00
|
|
|
let args = env::args();
|
2015-02-16 16:04:02 +02:00
|
|
|
let use_default = args.len() == 1;
|
2013-03-17 11:41:03 +01:00
|
|
|
let mut sudoku = if use_default {
|
2013-07-17 15:31:20 -04:00
|
|
|
Sudoku::from_vec(&DEFAULT_SUDOKU)
|
2011-11-20 01:53:12 +01:00
|
|
|
} else {
|
2015-02-24 23:27:20 -08:00
|
|
|
let stdin = io::stdin();
|
|
|
|
let mut locked = stdin.lock();
|
|
|
|
Sudoku::read(&mut locked)
|
2011-11-20 01:53:12 +01:00
|
|
|
};
|
2013-03-17 11:41:03 +01:00
|
|
|
sudoku.solve();
|
2015-02-24 23:27:20 -08:00
|
|
|
let out = io::stdout();
|
|
|
|
sudoku.write(&mut out.lock());
|
2011-11-20 01:53:12 +01:00
|
|
|
}
|