From 6dee732b717198378f7367827593ff1767c1b7dd Mon Sep 17 00:00:00 2001 From: Pat Allan Date: Fri, 24 May 2013 15:35:38 +1000 Subject: [PATCH] Hack night attempt. --- README.md | 2 + bin/su_solver | 8 +++ lib/su_solver.rb | 10 ++++ lib/su_solver/grid.rb | 69 +++++++++++++++++++++ lib/su_solver/solver.rb | 18 ++++++ spec/acceptance/solver_spec.rb | 9 +++ spec/spec_helper.rb | 2 + spec/su_solver/grid_spec.rb | 106 +++++++++++++++++++++++++++++++++ spec/su_solver/solver_spec.rb | 7 +++ 9 files changed, 231 insertions(+) create mode 100644 README.md create mode 100755 bin/su_solver create mode 100644 lib/su_solver.rb create mode 100644 lib/su_solver/grid.rb create mode 100644 lib/su_solver/solver.rb create mode 100644 spec/acceptance/solver_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/su_solver/grid_spec.rb create mode 100644 spec/su_solver/solver_spec.rb diff --git a/README.md b/README.md new file mode 100644 index 0000000..b43927c --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ + su_solver 78534789253478954300789... + diff --git a/bin/su_solver b/bin/su_solver new file mode 100755 index 0000000..eabe86b --- /dev/null +++ b/bin/su_solver @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +# -*- mode: ruby -*- + +$LOAD_PATH.unshift './lib' + +require 'su_solver' + +SuSolver.solve ARGV[0].dup diff --git a/lib/su_solver.rb b/lib/su_solver.rb new file mode 100644 index 0000000..7595a6d --- /dev/null +++ b/lib/su_solver.rb @@ -0,0 +1,10 @@ +module SuSolver + def self.solve(sudoku) + grid = SuSolver::Grid.new sudoku + SuSolver::Solver.solve grid + grid.to_s + end +end + +require 'su_solver/grid' +require 'su_solver/solver' diff --git a/lib/su_solver/grid.rb b/lib/su_solver/grid.rb new file mode 100644 index 0000000..e629d9c --- /dev/null +++ b/lib/su_solver/grid.rb @@ -0,0 +1,69 @@ +class SuSolver::Grid + VALUES = %w( 1 2 3 4 5 6 7 8 9 ) + + def initialize(string) + @string = string + end + + def rows + @string.scan(/\d{9}/) + end + + def columns + @string.scan(/\d{9}/).collect { |row| row.scan(/\d/) }.transpose.collect &:join + end + + def get_grid_value(row, column) + @string[column + (row * 9)] + end + + def set_grid_value(row, column, value) + @string[column + (row * 9)] = value + end + + def valid? + rows.each do |row| + return false unless row.split(/./).uniq.count == 9 + end + columns.each do |column| + return false unless column.split(/./).uniq.count == 9 + end + groups.each do |group| + return false unless group.split(/./).uniq.count == 9 + end + end + + def solved? + @string['0'].nil? + end + + def missing_values(set) + VALUES - set.scan(/./) + end + + def available_values(row, column) + missing_values(rows[row]) & + missing_values(columns[column]) & + missing_values(group_for(row, column)) + end + + def groups + @string.scan(/\d\d\d/).each_slice(9).collect do |block| + gr = Array.new(3, '') + block.each_with_index do |item, index| + gr[index % 3] += item + end + gr + end.flatten + end + + def to_s + @string + end + + private + + def group_for(row, column) + groups[(column / 3) + ((row / 3) * 3)] + end +end diff --git a/lib/su_solver/solver.rb b/lib/su_solver/solver.rb new file mode 100644 index 0000000..226ea18 --- /dev/null +++ b/lib/su_solver/solver.rb @@ -0,0 +1,18 @@ +class SuSolver::Solver + def self.solve(grid) + until grid.solved? + (0..8).each do |row| + (0..8).each do |column| + next unless grid.get_grid_value(row, column) == '0' + + values = grid.available_values(row, column) + if values.length == 1 + grid.set_grid_value(row, column, values.first) + end + end + end + + puts "--> #{grid.to_s}" + end + end +end diff --git a/spec/acceptance/solver_spec.rb b/spec/acceptance/solver_spec.rb new file mode 100644 index 0000000..57f573b --- /dev/null +++ b/spec/acceptance/solver_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' + +describe 'Sudoku Solver' do + it "solves a puzzle" do + solution = SuSolver.solve '052006000160900004049803620400000800083201590001000002097305240200009056000100970' + + solution.should == '352476189168952734749813625425697813683241597971538462897365241214789356536124978' + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..e741227 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'rspec' +require 'su_solver' diff --git a/spec/su_solver/grid_spec.rb b/spec/su_solver/grid_spec.rb new file mode 100644 index 0000000..4592384 --- /dev/null +++ b/spec/su_solver/grid_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +describe SuSolver::Grid do + let(:grid) { SuSolver::Grid.new(input) } + let(:input) { '052006000160900004049803620400000800083201590001000002097305240200009056000100970'} + + describe "#set_grid_value" do + it 'updates the first row' do + grid.set_grid_value(0, 0, "5") + grid.rows.first.should == "552006000" + end + + it 'updates the last row' do + grid.set_grid_value(8, 0, "9") + grid.rows.last.should == "900100970" + end + end + + describe "#valid?" do + it 'should have valid columns and rows' do + + # grid.should be_valid + end + end + + describe "#missing_values" do + it 'gives us the missing values' do + grid.missing_values('012345678').should == ['9'] + grid.missing_values('002345678').should =~ ['9', '1'] + end + end + + describe '#available_values' do + it 'returns all available values for a given cell' do + grid.available_values(0, 0).should =~ ['3', '7', '8'] + end + end + + context "invalid grid" do + let(:input) { "111111111111111111111111111111111111111111111111111111111111111111111111111111111" } + + it "should not be valid" do + grid.should_not be_valid + end + end + + + describe "#solved?" do + it "returns true when no zeros are in the grid" do + SuSolver::Grid.new('123456789123456789123456789123456789123456789123456789123456789123456789123456789').should be_solved + end + + it "returns false when at least one zero is in the grid" do + SuSolver::Grid.new('123456789123456789120456789123456789123456789123456789123456789123456789123456789').should_not be_solved + end + end + + describe '#rows' do + it 'returns an array' do + grid.rows.should be_an(Array) + end + + it 'returns a correct row' do + grid.rows.first.should == '052006000' + grid.rows.last.should == '000100970' + end + + it 'returns 9 rows' do + grid.rows.size.should == 9 + end + end + + describe '#columns' do + let(:input) { '012345678012345678012345678012345678012345678012345678012345678012345678012345678'} + + it 'returns an array' do + grid.columns.should be_an(Array) + end + + it 'returns a correct column' do + grid.columns.first.should == '000000000' + grid.columns.last.should == '888888888' + end + + it 'returns 9 columns' do + grid.columns.size.should == 9 + end + end + + describe '#groups' do + let(:input) { '352476189168952734749813625425697813683241597971538462897365241214789356536124978' } + + it 'returns an array' do + grid.groups.should be_an(Array) + end + + it 'returns the correct groups' do + grid.groups.first.should == '352168749' + grid.groups.last.should == '241356978' + end + + it 'returns 9 groups' do + grid.groups.size.should == 9 + end + end +end \ No newline at end of file diff --git a/spec/su_solver/solver_spec.rb b/spec/su_solver/solver_spec.rb new file mode 100644 index 0000000..84e3971 --- /dev/null +++ b/spec/su_solver/solver_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe SuSolver::Solver + describe '.solve' do + # + end +end