From fea4798ca7e554f87cd55a4c1556b5db13cde8ee Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Fri, 18 Oct 2013 16:12:07 -0700 Subject: [PATCH 1/6] first try --- .gitignore | 1 + .rspec | 1 + Gemfile | 3 + Gemfile.lock | 48 +++++++++++ Guardfile | 7 ++ lib/sudoku_reader.rb | 21 +++++ lib/sudoku_validator.rb | 69 +++++++++++++++ spec/fixtures/invalid_complete.sudoku | 11 +++ spec/fixtures/invalid_incomplete.sudoku | 11 +++ spec/fixtures/valid_complete.sudoku | 11 +++ spec/fixtures/valid_incomplete.sudoku | 11 +++ spec/lib/sudoku_reader_spec.rb | 36 ++++++++ spec/lib/sudoku_validator_spec.rb | 108 ++++++++++++++++++++++++ spec/spec_helper.rb | 10 +++ spec/support/fixture_path.rb | 9 ++ sudoku-validator | 18 ++++ 16 files changed, 375 insertions(+) create mode 100644 .gitignore create mode 100644 .rspec create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Guardfile create mode 100644 lib/sudoku_reader.rb create mode 100644 lib/sudoku_validator.rb create mode 100644 spec/fixtures/invalid_complete.sudoku create mode 100644 spec/fixtures/invalid_incomplete.sudoku create mode 100644 spec/fixtures/valid_complete.sudoku create mode 100644 spec/fixtures/valid_incomplete.sudoku create mode 100644 spec/lib/sudoku_reader_spec.rb create mode 100644 spec/lib/sudoku_validator_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/support/fixture_path.rb create mode 100755 sudoku-validator diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cad2309 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/tmp \ No newline at end of file diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..5052887 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..20effee --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ + +gem 'rspec' +gem 'guard-rspec' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..60f9b9a --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,48 @@ +GEM + specs: + celluloid (0.15.2) + timers (~> 1.1.0) + coderay (1.0.9) + diff-lcs (1.2.4) + ffi (1.9.0) + formatador (0.2.4) + guard (2.0.3) + formatador (>= 0.2.4) + listen (~> 2.0) + lumberjack (~> 1.0) + pry (>= 0.9.12) + thor (>= 0.18.1) + guard-rspec (3.1.0) + guard (>= 1.8) + rspec (~> 2.13) + listen (2.0.1) + celluloid (>= 0.15.2) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + lumberjack (1.0.4) + method_source (0.8.2) + pry (0.9.12.2) + coderay (~> 1.0.5) + method_source (~> 0.8) + slop (~> 3.4) + rb-fsevent (0.9.3) + rb-inotify (0.9.2) + ffi (>= 0.5.0) + rspec (2.14.1) + rspec-core (~> 2.14.0) + rspec-expectations (~> 2.14.0) + rspec-mocks (~> 2.14.0) + rspec-core (2.14.5) + rspec-expectations (2.14.3) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.14.3) + slop (3.4.6) + thor (0.18.1) + timers (1.1.0) + +PLATFORMS + ruby + +DEPENDENCIES + guard-rspec + rspec diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..b70bc58 --- /dev/null +++ b/Guardfile @@ -0,0 +1,7 @@ + +guard :rspec, cli: "--tag ~@external" do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } + watch(%r{^spec/support/.+\.rb$}) { "spec" } +end diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb new file mode 100644 index 0000000..e775f44 --- /dev/null +++ b/lib/sudoku_reader.rb @@ -0,0 +1,21 @@ + +class SudokuReader + + attr_reader :grid + + def self.parse_line(line) + # sample: "8 5 9 |6 1 2 |4 3 7 " + line.split("|").map { |segment| segment.split(" ") }.flatten unless line =~ /^-+/ + end + + def initialize + @grid = [] + end + + def read(file_path) + open(file_path).each do |line| + parsed_line = SudokuReader.parse_line line + @grid << parsed_line if parsed_line + end + end +end \ No newline at end of file diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb new file mode 100644 index 0000000..2cb779c --- /dev/null +++ b/lib/sudoku_validator.rb @@ -0,0 +1,69 @@ +class SudokuValidator + + def self.valid_array?(array) + array_with_numbers_only = array.reject { |el| el == "." } + array_with_numbers_only.uniq.length == array_with_numbers_only.length + end + + def self.complete_array?(array) + array_with_numbers_only = array.reject { |el| el == "." } + array_with_numbers_only.length == 9 + end + + attr_reader :grid + + def initialize(grid_or_filepath) + if grid_or_filepath.instance_of? String + reader = SudokuReader.new + reader.read grid_or_filepath + @grid = reader.grid + else + @grid = grid_or_filepath + end + end + + def row(i) + grid[i-1] + end + + def column(i) + grid.map { |row| row[i-1] } + end + + def subgrid(i) + # subgrid as laid out below + # 1 2 3 + # 4 5 6 + # 7 8 9 + + row_index = (i - 1) / 3 + 1 + + column_index = ( i - 1) % 3 + 1 + + row_begin = (row_index - 1) * 3 + 1 + row_end = row_index * 3 + + column_begin = (column_index - 1) * 3 + 1 + column_end = column_index * 3 + + subgrid_array = [] + (row_begin..row_end).each do |ri| + (column_begin..column_end).each do |ci| + subgrid_array << grid[ri-1][ci-1] + end + end + subgrid_array + end + + def valid? + (1..9).all? { |i| SudokuValidator.valid_array?(row(i)) } and + (1..9).all? { |i| SudokuValidator.valid_array?(column(i)) } and + (1..9).all? { |i| SudokuValidator.valid_array?(subgrid(i)) } + end + + def complete? + (1..9).all? { |i| SudokuValidator.complete_array?(row(i)) } and + (1..9).all? { |i| SudokuValidator.complete_array?(column(i)) } and + (1..9).all? { |i| SudokuValidator.complete_array?(subgrid(i)) } + end +end \ No newline at end of file diff --git a/spec/fixtures/invalid_complete.sudoku b/spec/fixtures/invalid_complete.sudoku new file mode 100644 index 0000000..ba5fb31 --- /dev/null +++ b/spec/fixtures/invalid_complete.sudoku @@ -0,0 +1,11 @@ +8 5 9 |6 1 2 |4 3 7 +7 2 3 |8 5 4 |1 6 9 +1 6 4 |3 7 9 |5 2 8 +------+------+------ +9 8 6 |1 4 7 |3 5 2 +3 7 5 |8 6 2 |9 1 4 +2 4 1 |5 9 3 |7 8 6 +------+------+------ +4 3 2 |9 8 1 |6 7 5 +6 1 7 |4 2 5 |8 9 3 +5 9 8 |7 3 6 |2 4 1 diff --git a/spec/fixtures/invalid_incomplete.sudoku b/spec/fixtures/invalid_incomplete.sudoku new file mode 100644 index 0000000..7e5b7f4 --- /dev/null +++ b/spec/fixtures/invalid_incomplete.sudoku @@ -0,0 +1,11 @@ +8 5 . |. . 2 |4 . . +7 2 . |. 8 . |. . 9 +. . 4 |. . . |. . . +------+------+------ +. . . |1 . 7 |. . 2 +3 . 5 |. . . |9 . . +. 4 . |. . . |. . . +------+------+------ +. 5 . |. 8 . |. 7 . +. 1 7 |. . . |. . . +. . . |. 3 6 |. 4 . diff --git a/spec/fixtures/valid_complete.sudoku b/spec/fixtures/valid_complete.sudoku new file mode 100644 index 0000000..ec5075c --- /dev/null +++ b/spec/fixtures/valid_complete.sudoku @@ -0,0 +1,11 @@ +8 5 9 |6 1 2 |4 3 7 +7 2 3 |8 5 4 |1 6 9 +1 6 4 |3 7 9 |5 2 8 +------+------+------ +9 8 6 |1 4 7 |3 5 2 +3 7 5 |2 6 8 |9 1 4 +2 4 1 |5 9 3 |7 8 6 +------+------+------ +4 3 2 |9 8 1 |6 7 5 +6 1 7 |4 2 5 |8 9 3 +5 9 8 |7 3 6 |2 4 1 diff --git a/spec/fixtures/valid_incomplete.sudoku b/spec/fixtures/valid_incomplete.sudoku new file mode 100644 index 0000000..bba06a1 --- /dev/null +++ b/spec/fixtures/valid_incomplete.sudoku @@ -0,0 +1,11 @@ +8 5 . |. . 2 |4 . . +7 2 . |. . . |. . 9 +. . 4 |. . . |. . . +------+------+------ +. . . |1 . 7 |. . 2 +3 . 5 |. . . |9 . . +. 4 . |. . . |. . . +------+------+------ +. . . |. 8 . |. 7 . +. 1 7 |. . . |. . . +. . . |. 3 6 |. 4 . diff --git a/spec/lib/sudoku_reader_spec.rb b/spec/lib/sudoku_reader_spec.rb new file mode 100644 index 0000000..8efc1ee --- /dev/null +++ b/spec/lib/sudoku_reader_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe SudokuReader do + + describe '.parse_line' do + it 'returns an array' do + parsed_line = SudokuReader.parse_line "8 5 9 |6 1 2 |4 3 7 " + + expect(parsed_line).to eq ["8", "5", "9", "6", "1", "2", "4", "3", "7"] + + parsed_line = SudokuReader.parse_line ". . . |. 8 . |. 7 . " + + expect(parsed_line).to eq [".", ".", ".", ".", "8", ".", ".", "7", "."] + + parsed_line = SudokuReader.parse_line "------+------+------" + + expect(parsed_line).to be_nil + end + end + + describe '#read' do + it 'reads and stores the file into an array' do + reader = SudokuReader.new + reader.read fixture_path('valid_incomplete.sudoku') + + expect(reader.grid.length).to eq 9 # rows + reader.grid.each do |row| + expect(row.length).to eq 9 # columns + end + expect(reader.grid[0][4]).to eq "." + expect(reader.grid[2][2]).to eq "4" + end + + end + +end \ No newline at end of file diff --git a/spec/lib/sudoku_validator_spec.rb b/spec/lib/sudoku_validator_spec.rb new file mode 100644 index 0000000..a912abc --- /dev/null +++ b/spec/lib/sudoku_validator_spec.rb @@ -0,0 +1,108 @@ +require 'spec_helper' + +describe SudokuValidator do + + describe '.valid_array?' do + it 'returns false if there are repeats excluding "."' do + expect(SudokuValidator.valid_array?(["1", "2", "3"])).to be_true + expect(SudokuValidator.valid_array?(["1", "2", "3", "3"])).to be_false + expect(SudokuValidator.valid_array?(["1", "2", ".", "."])).to be_true + end + end + + describe '.complete_array?' do + it 'returns false if the number elements have count of 9 excluding "."' do + expect(SudokuValidator.complete_array?(["1", "2", ".", "."])).to be_false + expect(SudokuValidator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "."])).to be_false + expect(SudokuValidator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "8"])).to be_true + end + end + + describe '#initialize' do + it 'stores the grid' do + reader = SudokuReader.new + reader.read(fixture_path('valid_incomplete.sudoku')) + validator = SudokuValidator.new reader.grid + + expect(validator.grid).to eq reader.grid + end + + it 'optionally takes a filepath' do + reader = SudokuReader.new + reader.read(fixture_path('valid_incomplete.sudoku')) + + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + + expect(validator.grid).to eq reader.grid + end + end + + describe '#row' do + it 'retrieves a row as an array' do + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + + expect(validator.row(1)).to eq ["8", "5", ".", ".", ".", "2", "4", ".", "."] + expect(validator.row(5)).to eq ["3", ".", "5", ".", ".", ".", "9", ".", "."] + end + end + + describe '#column' do + it 'retrieves a row as an array' do + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + + expect(validator.column(2)).to eq ["5", "2", ".", ".", ".", "4", ".", "1", "."] + expect(validator.column(4)).to eq [".", ".", ".", "1", ".", ".", ".", ".", "."] + end + end + + describe '#subgrid' do + # subgrid indexed as below + # 1 2 3 + # - - - + # 1 - 1 2 3 + # 2 - 4 5 6 + # 3 - 7 8 9 + + it 'retrieves a row as an array' do + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + + # expect(validator.subgrid(3)).to eq ["4", ".", ".", ".", ".", "9", ".", ".", "."] + expect(validator.subgrid(7)).to eq [".", ".", ".", ".", "1", "7", ".", ".", "."] + end + end + + describe '#valid?' do + + it 'validates all 3 array checks' do + validator = SudokuValidator.new fixture_path('valid_complete.sudoku') + expect(validator.valid?).to be_true + + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + expect(validator.valid?).to be_true + + validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + expect(validator.valid?).to be_false + + validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + expect(validator.valid?).to be_false + end + end + + describe '#complete?' do + + it 'validates all 3 array checks' do + validator = SudokuValidator.new fixture_path('valid_complete.sudoku') + expect(validator.complete?).to be_true + + validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + expect(validator.complete?).to be_true + + validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + expect(validator.complete?).to be_false + + validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + expect(validator.complete?).to be_false + end + end + +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..8ed0794 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,10 @@ +require_relative '../lib/sudoku_reader' +require_relative '../lib/sudoku_validator' +require 'support/fixture_path' + + +RSpec.configure do |config| + config.treat_symbols_as_metadata_keys_with_true_values = true + config.filter_run focus: true + config.run_all_when_everything_filtered = true +end \ No newline at end of file diff --git a/spec/support/fixture_path.rb b/spec/support/fixture_path.rb new file mode 100644 index 0000000..83afb62 --- /dev/null +++ b/spec/support/fixture_path.rb @@ -0,0 +1,9 @@ +module FixturePath + def fixture_path(file_name) + File.join("spec/fixtures", file_name) + end +end + +RSpec.configure do |config| + config.include FixturePath +end \ No newline at end of file diff --git a/sudoku-validator b/sudoku-validator new file mode 100755 index 0000000..3031454 --- /dev/null +++ b/sudoku-validator @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +require_relative 'lib/sudoku_reader' +require_relative 'lib/sudoku_validator' + +path = ARGV[0] + +validator = SudokuValidator.new path + +if validator.valid? + if validator.complete? + puts "This sudoku is valid." + else + puts "This sudoku is valid, but incomplete." + end +else + puts 'This sudoku is invalid.' +end \ No newline at end of file From cd7b3f211ddeef6e59d6065e368482372bb430d1 Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Fri, 18 Oct 2013 16:40:22 -0700 Subject: [PATCH 2/6] correct a few words and added some "pictures" for clarity --- lib/sudoku_validator.rb | 36 +++++++++++++++++++++---------- spec/lib/sudoku_validator_spec.rb | 32 ++++++++++++++++++--------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 2cb779c..93d0170 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -30,21 +30,35 @@ def column(i) grid.map { |row| row[i-1] } end + # subgrid is laid out as below + # 1 2 3 <- grid_column_index + # 1 - 3 4 - 6 7 - 9 + # 1 . . . | . . . | . . . + # 1 | . 1 . | . 2 . | . 3 . + # 3 . . . | . . . | . . . + # +-----+-------+-----+ + # 4 . . . | . . . | . . . + # 2 | . 4 . | . 5 . | . 6 . + # 6 . . . | . . . | . . . + # +-----+-------+-----+ + # 7 . . . | . . . | . . . + # 3 | . 7 . | . 8 . | . 9 . + # 9 . . . | . . . | . . . + # + # ^ + # grid_row_index + # def subgrid(i) - # subgrid as laid out below - # 1 2 3 - # 4 5 6 - # 7 8 9 + + grid_row_index = (i - 1) / 3 + 1 - row_index = (i - 1) / 3 + 1 + grid_column_index = ( i - 1) % 3 + 1 - column_index = ( i - 1) % 3 + 1 + row_begin = (grid_row_index - 1) * 3 + 1 + row_end = grid_row_index * 3 - row_begin = (row_index - 1) * 3 + 1 - row_end = row_index * 3 - - column_begin = (column_index - 1) * 3 + 1 - column_end = column_index * 3 + column_begin = (grid_column_index - 1) * 3 + 1 + column_end = grid_column_index * 3 subgrid_array = [] (row_begin..row_end).each do |ri| diff --git a/spec/lib/sudoku_validator_spec.rb b/spec/lib/sudoku_validator_spec.rb index a912abc..53b2ff4 100644 --- a/spec/lib/sudoku_validator_spec.rb +++ b/spec/lib/sudoku_validator_spec.rb @@ -47,7 +47,7 @@ end describe '#column' do - it 'retrieves a row as an array' do + it 'retrieves a column as an array' do validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') expect(validator.column(2)).to eq ["5", "2", ".", ".", ".", "4", ".", "1", "."] @@ -56,17 +56,29 @@ end describe '#subgrid' do - # subgrid indexed as below - # 1 2 3 - # - - - - # 1 - 1 2 3 - # 2 - 4 5 6 - # 3 - 7 8 9 - - it 'retrieves a row as an array' do + # subgrid is laid out as below + # 1 2 3 <- grid_column_index + # 1 - 3 4 - 6 7 - 9 + # 1 . . . | . . . | . . . + # 1 | . 1 . | . 2 . | . 3 . + # 3 . . . | . . . | . . . + # +-----+-------+-----+ + # 4 . . . | . . . | . . . + # 2 | . 4 . | . 5 . | . 6 . + # 6 . . . | . . . | . . . + # +-----+-------+-----+ + # 7 . . . | . . . | . . . + # 3 | . 7 . | . 8 . | . 9 . + # 9 . . . | . . . | . . . + # + # ^ + # grid_row_index + # + + it 'retrieves a subgrid as an array' do validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') - # expect(validator.subgrid(3)).to eq ["4", ".", ".", ".", ".", "9", ".", ".", "."] + expect(validator.subgrid(3)).to eq ["4", ".", ".", ".", ".", "9", ".", ".", "."] expect(validator.subgrid(7)).to eq [".", ".", ".", ".", "1", "7", ".", ".", "."] end end From a1332c947684e376b9885130713d1b9fcc7f0c2b Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Fri, 18 Oct 2013 18:04:29 -0700 Subject: [PATCH 3/6] added errors --- lib/sudoku_validator.rb | 49 +++++++++++++++++++++++++---- spec/lib/sudoku_validator_spec.rb | 29 ++++++++++++++++-- sudoku-validator | 51 +++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 9 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 93d0170..f1146d6 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -11,6 +11,7 @@ def self.complete_array?(array) end attr_reader :grid + attr_reader :errors def initialize(grid_or_filepath) if grid_or_filepath.instance_of? String @@ -20,6 +21,18 @@ def initialize(grid_or_filepath) else @grid = grid_or_filepath end + @errors = { + invalid: { + column: [], + row: [], + subgrid: [] + }, + incomplete: { + column: [], + row: [], + subgrid: [] + } + } end def row(i) @@ -69,15 +82,39 @@ def subgrid(i) subgrid_array end + def validate! + [:invalid, :incomplete].each do |error_type| + reset_errors(error_type) + [:row, :column, :subgrid].each do |row_or_column_or_subgrid| + (1..9).each do |i| + row_or_column_or_subgrid_array = send(row_or_column_or_subgrid, i) + + validation_method = (error_type.to_s.gsub(/in/, '')+'_array?').to_sym # :invalid -> :valid_array? + + unless SudokuValidator.send validation_method, row_or_column_or_subgrid_array + @errors[error_type][row_or_column_or_subgrid] << i + end + end + end + end + end + def valid? - (1..9).all? { |i| SudokuValidator.valid_array?(row(i)) } and - (1..9).all? { |i| SudokuValidator.valid_array?(column(i)) } and - (1..9).all? { |i| SudokuValidator.valid_array?(subgrid(i)) } + errors[:invalid][:row].length == 0 and + errors[:invalid][:column].length == 0 and + errors[:invalid][:subgrid].length == 0 end def complete? - (1..9).all? { |i| SudokuValidator.complete_array?(row(i)) } and - (1..9).all? { |i| SudokuValidator.complete_array?(column(i)) } and - (1..9).all? { |i| SudokuValidator.complete_array?(subgrid(i)) } + errors[:incomplete][:row].length == 0 and + errors[:incomplete][:column].length == 0 and + errors[:incomplete][:subgrid].length == 0 + end + + def reset_errors(type) + @errors[type][:row].clear + @errors[type][:column].clear + @errors[type][:subgrid].clear end + end \ No newline at end of file diff --git a/spec/lib/sudoku_validator_spec.rb b/spec/lib/sudoku_validator_spec.rb index 53b2ff4..d106f40 100644 --- a/spec/lib/sudoku_validator_spec.rb +++ b/spec/lib/sudoku_validator_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'yaml' describe SudokuValidator do @@ -83,19 +84,36 @@ end end + describe '#validate!' do + it 'runs finds and logs all the errors' do + validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator.validate! + expect(validator.errors[:invalid][:row]).to eq [] + expect(validator.errors[:invalid][:column]).to eq [2, 5] + expect(validator.errors[:invalid][:subgrid]).to eq [] + expect(validator.errors[:incomplete][:row]).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9] + expect(validator.errors[:incomplete][:column]).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9] + expect(validator.errors[:incomplete][:subgrid]).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9] + end + end + describe '#valid?' do it 'validates all 3 array checks' do validator = SudokuValidator.new fixture_path('valid_complete.sudoku') + validator.validate! expect(validator.valid?).to be_true validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + validator.validate! expect(validator.valid?).to be_true validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + validator.validate! expect(validator.valid?).to be_false validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator.validate! expect(validator.valid?).to be_false end end @@ -104,17 +122,22 @@ it 'validates all 3 array checks' do validator = SudokuValidator.new fixture_path('valid_complete.sudoku') - expect(validator.complete?).to be_true - - validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + validator.validate! expect(validator.complete?).to be_true validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + validator.validate! expect(validator.complete?).to be_false validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator.validate! expect(validator.complete?).to be_false + + validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + validator.validate! + expect(validator.complete?).to be_true end end + end \ No newline at end of file diff --git a/sudoku-validator b/sudoku-validator index 3031454..5ad9796 100755 --- a/sudoku-validator +++ b/sudoku-validator @@ -2,17 +2,68 @@ require_relative 'lib/sudoku_reader' require_relative 'lib/sudoku_validator' +require 'json' path = ARGV[0] validator = SudokuValidator.new path +validator.validate! + +GRID_LOCATION = < subgrid + 6 . . . | . . . | . . . | + +-----+-------+-----+ + 7 . . . | . . . | . . . + 8 . 7 . | . 8 . | . 9 . + 9 . . . | . . . | . . . + + +********************************** +TEXT if validator.valid? if validator.complete? puts "This sudoku is valid." else puts "This sudoku is valid, but incomplete." + puts "\n** Errors *************************\n" + puts "" + validator.errors[:incomplete].each do |key, vals| + if vals.any? + puts "incomplete #{key}s: #{vals.join(", ")}" + end + end + puts GRID_LOCATION end else puts 'This sudoku is invalid.' + puts "\n** Errors *************************" + puts "" + unless validator.valid? + validator.errors[:invalid].each do |key, vals| + if vals.any? + puts "invalid #{key}s: #{vals.join(", ")}" + end + end + end + validator.errors[:incomplete].each do |key, vals| + if vals.any? + puts "incomplete #{key}s: #{vals.join(", ")}" + end + end + puts GRID_LOCATION end \ No newline at end of file From aa0e950a0228ca9e9e566593a242f846e91c3a74 Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Tue, 22 Oct 2013 17:52:36 -0700 Subject: [PATCH 4/6] refactored and clarified the code a bit more --- lib/sudoku_reader.rb | 7 ++- lib/sudoku_validator.rb | 85 ++++++++++++++++--------------- spec/lib/sudoku_reader_spec.rb | 16 ++++++ spec/lib/sudoku_validator_spec.rb | 44 +++++++++++++++- sudoku-validator | 20 ++------ 5 files changed, 110 insertions(+), 62 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index e775f44..acd5173 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -4,8 +4,11 @@ class SudokuReader attr_reader :grid def self.parse_line(line) - # sample: "8 5 9 |6 1 2 |4 3 7 " - line.split("|").map { |segment| segment.split(" ") }.flatten unless line =~ /^-+/ + line.split(/[^\d\.]+/) unless separator_line? line + end + + def self.separator_line?(line) + line =~/^-+/ end def initialize diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index f1146d6..5906180 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -10,6 +10,14 @@ def self.complete_array?(array) array_with_numbers_only.length == 9 end + def self.array_is?(validation_type, array) + if validation_type == :invalid + not valid_array? array + else + not complete_array? array + end + end + attr_reader :grid attr_reader :errors @@ -44,39 +52,37 @@ def column(i) end # subgrid is laid out as below - # 1 2 3 <- grid_column_index - # 1 - 3 4 - 6 7 - 9 - # 1 . . . | . . . | . . . - # 1 | . 1 . | . 2 . | . 3 . - # 3 . . . | . . . | . . . - # +-----+-------+-----+ - # 4 . . . | . . . | . . . - # 2 | . 4 . | . 5 . | . 6 . - # 6 . . . | . . . | . . . - # +-----+-------+-----+ - # 7 . . . | . . . | . . . - # 3 | . 7 . | . 8 . | . 9 . - # 9 . . . | . . . | . . . + # 1-based 0-based + # 1 2 3 0 1 2 <- grid_column_index + # 1 - 3 4 - 6 7 - 9 0 - 2 3 - 5 6 - 8 + # 1 . . . | . . . | . . . 0 . . . | . . . | . . . + # 1 | . 1 . | . 2 . | . 3 . 0 | . 0 . | . 1 . | . 2 . + # 3 . . . | . . . | . . . 2 . . . | . . . | . . . + # +-----+-------+-----+ +-----+-------+-----+ + # 4 . . . | . . . | . . . 3 . . . | . . . | . . . + # 2 | . 4 . | . 5 . | . 6 . 1 | . 3 . | . 4 . | . 5 . + # 6 . . . | . . . | . . . 5 . . . | . . . | . . . + # +-----+-------+-----+ +-----+-------+-----+ + # 7 . . . | . . . | . . . 6 . . . | . . . | . . . + # 3 | . 7 . | . 8 . | . 9 . 2 | . 6 . | . 7 . | . 8 . + # 9 . . . | . . . | . . . 8 . . . | . . . | . . . # - # ^ - # grid_row_index + # ^ + # grid_row_index # def subgrid(i) - - grid_row_index = (i - 1) / 3 + 1 + i = i - 1 # convert to 0-based - grid_column_index = ( i - 1) % 3 + 1 + grid_row_index = i / 3 + grid_column_index = i % 3 - row_begin = (grid_row_index - 1) * 3 + 1 - row_end = grid_row_index * 3 - - column_begin = (grid_column_index - 1) * 3 + 1 - column_end = grid_column_index * 3 + row_range = grid_row_index * 3 ... grid_row_index.next * 3 + column_range = grid_column_index * 3 ... grid_column_index.next * 3 subgrid_array = [] - (row_begin..row_end).each do |ri| - (column_begin..column_end).each do |ci| - subgrid_array << grid[ri-1][ci-1] + row_range.each do |ri| + column_range.each do |ci| + subgrid_array << grid[ri][ci] end end subgrid_array @@ -85,14 +91,10 @@ def subgrid(i) def validate! [:invalid, :incomplete].each do |error_type| reset_errors(error_type) - [:row, :column, :subgrid].each do |row_or_column_or_subgrid| + [:row, :column, :subgrid].each do |array_type| (1..9).each do |i| - row_or_column_or_subgrid_array = send(row_or_column_or_subgrid, i) - - validation_method = (error_type.to_s.gsub(/in/, '')+'_array?').to_sym # :invalid -> :valid_array? - - unless SudokuValidator.send validation_method, row_or_column_or_subgrid_array - @errors[error_type][row_or_column_or_subgrid] << i + if SudokuValidator.array_is? error_type, send(array_type, i) + errors[error_type][array_type] << i end end end @@ -100,21 +102,20 @@ def validate! end def valid? - errors[:invalid][:row].length == 0 and - errors[:invalid][:column].length == 0 and - errors[:invalid][:subgrid].length == 0 + [:row, :column, :subgrid].all? { |array_type| errors[:invalid][array_type].none? } end def complete? - errors[:incomplete][:row].length == 0 and - errors[:incomplete][:column].length == 0 and - errors[:incomplete][:subgrid].length == 0 + [:row, :column, :subgrid].all? { |array_type| errors[:incomplete][array_type].none? } end def reset_errors(type) - @errors[type][:row].clear - @errors[type][:column].clear - @errors[type][:subgrid].clear + [:row, :column, :subgrid].each { |array_type| errors[type][array_type].clear } end + def error_messages(type) + errors[type].map do |key, vals| + "#{type} #{key}s: #{vals.join(", ")}" if vals.any? + end.compact.sort + end end \ No newline at end of file diff --git a/spec/lib/sudoku_reader_spec.rb b/spec/lib/sudoku_reader_spec.rb index 8efc1ee..c48b5ff 100644 --- a/spec/lib/sudoku_reader_spec.rb +++ b/spec/lib/sudoku_reader_spec.rb @@ -18,6 +18,22 @@ end end + describe '.separator_line?' do + it 'returns true if the line is -----' do + line = "------+------+------" + + expect(SudokuReader.separator_line?(line)).to be_true + + line = "8 5 9 |6 1 2 |4 3 7 " + + expect(SudokuReader.separator_line?(line)).to be_false + + line = ". . . |. 8 . |. 7 . " + + expect(SudokuReader.separator_line?(line)).to be_false + end + end + describe '#read' do it 'reads and stores the file into an array' do reader = SudokuReader.new diff --git a/spec/lib/sudoku_validator_spec.rb b/spec/lib/sudoku_validator_spec.rb index d106f40..6c4e7e8 100644 --- a/spec/lib/sudoku_validator_spec.rb +++ b/spec/lib/sudoku_validator_spec.rb @@ -19,6 +19,32 @@ end end + describe '.array_ok?' do + it 'calls valid_array? if :invalid is given and returns the opposite' do + some_array = [1,2,3] + + expect(SudokuValidator).to receive(:valid_array?).with(some_array).once.and_return(false) + + expect(SudokuValidator.array_is?(:invalid, some_array)).to be_true + + expect(SudokuValidator).to receive(:valid_array?).with(some_array).once.and_return(true) + + expect(SudokuValidator.array_is?(:invalid, some_array)).to be_false + end + + it 'calls complete_array? if :incomplete is given and returns the opposite' do + some_array = [1,2,3] + + expect(SudokuValidator).to receive(:complete_array?).with(some_array).once.and_return(false) + + expect(SudokuValidator.array_is?(:incomplete, some_array)).to be_true + + expect(SudokuValidator).to receive(:complete_array?).with(some_array).once.and_return(true) + + expect(SudokuValidator.array_is?(:incomplete, some_array)).to be_false + end + end + describe '#initialize' do it 'stores the grid' do reader = SudokuReader.new @@ -95,7 +121,23 @@ expect(validator.errors[:incomplete][:column]).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9] expect(validator.errors[:incomplete][:subgrid]).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9] end - end + end + + describe '#error_messages' do + it 'ouputs the correct error messages' do + validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator.validate! + + expect(validator.error_messages(:invalid)).to eq [ + "invalid columns: 2, 5" + ] + expect(validator.error_messages(:incomplete)).to eq [ + "incomplete columns: 1, 2, 3, 4, 5, 6, 7, 8, 9", + "incomplete rows: 1, 2, 3, 4, 5, 6, 7, 8, 9", + "incomplete subgrids: 1, 2, 3, 4, 5, 6, 7, 8, 9" + ] + end + end describe '#valid?' do diff --git a/sudoku-validator b/sudoku-validator index 5ad9796..f612866 100755 --- a/sudoku-validator +++ b/sudoku-validator @@ -42,28 +42,14 @@ if validator.valid? puts "This sudoku is valid, but incomplete." puts "\n** Errors *************************\n" puts "" - validator.errors[:incomplete].each do |key, vals| - if vals.any? - puts "incomplete #{key}s: #{vals.join(", ")}" - end - end + validator.error_messages(:incomplete).each { |msg| puts msg } puts GRID_LOCATION end else puts 'This sudoku is invalid.' puts "\n** Errors *************************" puts "" - unless validator.valid? - validator.errors[:invalid].each do |key, vals| - if vals.any? - puts "invalid #{key}s: #{vals.join(", ")}" - end - end - end - validator.errors[:incomplete].each do |key, vals| - if vals.any? - puts "incomplete #{key}s: #{vals.join(", ")}" - end - end + validator.error_messages(:invalid).each { |msg| puts msg } + validator.error_messages(:incomplete).each { |msg| puts msg } puts GRID_LOCATION end \ No newline at end of file From c896ad1f60eb88e2655cb65ed039bf5683341bd9 Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Tue, 22 Oct 2013 18:20:57 -0700 Subject: [PATCH 5/6] renamed and changed reset_errors --- lib/sudoku_validator.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5906180..36d30a3 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -89,8 +89,9 @@ def subgrid(i) end def validate! + reset_errors! + [:invalid, :incomplete].each do |error_type| - reset_errors(error_type) [:row, :column, :subgrid].each do |array_type| (1..9).each do |i| if SudokuValidator.array_is? error_type, send(array_type, i) @@ -109,8 +110,12 @@ def complete? [:row, :column, :subgrid].all? { |array_type| errors[:incomplete][array_type].none? } end - def reset_errors(type) - [:row, :column, :subgrid].each { |array_type| errors[type][array_type].clear } + def reset_errors! + [:invalid, :incomplete].each do |error_type| + [:row, :column, :subgrid].each do |array_type| + errors[error_type][array_type].clear + end + end end def error_messages(type) From 304b8cf0d92975141c10c20470a7915cd4d4111a Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Wed, 23 Oct 2013 11:34:45 -0700 Subject: [PATCH 6/6] moved class methods to instance and made some methods clearer --- lib/sudoku_reader.rb | 22 +++++--- lib/sudoku_validator.rb | 83 ++++++++++++++---------------- spec/lib/sudoku_reader_spec.rb | 29 +++++++---- spec/lib/sudoku_validator_spec.rb | 85 ++++++++++++++----------------- sudoku-validator | 2 - 5 files changed, 109 insertions(+), 112 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index acd5173..af0cb9d 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -1,15 +1,13 @@ class SudokuReader - attr_reader :grid - - def self.parse_line(line) - line.split(/[^\d\.]+/) unless separator_line? line + def self.reader_from_file(file_path) + reader = SudokuReader.new + reader.read(file_path) + reader end - def self.separator_line?(line) - line =~/^-+/ - end + attr_reader :grid def initialize @grid = [] @@ -17,8 +15,16 @@ def initialize def read(file_path) open(file_path).each do |line| - parsed_line = SudokuReader.parse_line line + parsed_line = parse_line line @grid << parsed_line if parsed_line end end + + def parse_line(line) + line.split(/[^\d\.]+/) unless separator_line? line + end + + def separator_line?(line) + line =~/^-+/ + end end \ No newline at end of file diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 36d30a3..1b1ace3 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -1,34 +1,10 @@ class SudokuValidator - def self.valid_array?(array) - array_with_numbers_only = array.reject { |el| el == "." } - array_with_numbers_only.uniq.length == array_with_numbers_only.length - end - - def self.complete_array?(array) - array_with_numbers_only = array.reject { |el| el == "." } - array_with_numbers_only.length == 9 - end - - def self.array_is?(validation_type, array) - if validation_type == :invalid - not valid_array? array - else - not complete_array? array - end - end - attr_reader :grid attr_reader :errors - def initialize(grid_or_filepath) - if grid_or_filepath.instance_of? String - reader = SudokuReader.new - reader.read grid_or_filepath - @grid = reader.grid - else - @grid = grid_or_filepath - end + def initialize(file_path) + @grid = SudokuReader.reader_from_file(file_path).grid @errors = { invalid: { column: [], @@ -43,6 +19,26 @@ def initialize(grid_or_filepath) } end + def valid_array?(array) + numbers_only(array).uniq.length == numbers_only(array).length + end + + def complete_array?(array) + numbers_only(array).length == 9 + end + + def numbers_only(array) + array.reject { |el| el == "." } + end + + def array_is?(validation_type, array) + if validation_type == :invalid + not valid_array? array + else + not complete_array? array + end + end + def row(i) grid[i-1] end @@ -53,7 +49,7 @@ def column(i) # subgrid is laid out as below # 1-based 0-based - # 1 2 3 0 1 2 <- grid_column_index + # 1 2 3 0 1 2 <- grid_index for column # 1 - 3 4 - 6 7 - 9 0 - 2 3 - 5 6 - 8 # 1 . . . | . . . | . . . 0 . . . | . . . | . . . # 1 | . 1 . | . 2 . | . 3 . 0 | . 0 . | . 1 . | . 2 . @@ -68,35 +64,32 @@ def column(i) # 9 . . . | . . . | . . . 8 . . . | . . . | . . . # # ^ - # grid_row_index + # grid_index for row # def subgrid(i) - i = i - 1 # convert to 0-based + grid[row_starts_for_grid(i), 3].map do |row| + row[column_starts_for_grid(i), 3] + end.flatten + end - grid_row_index = i / 3 - grid_column_index = i % 3 + def row_starts_for_grid(i) + zero_based(i) / 3 * 3 + end - row_range = grid_row_index * 3 ... grid_row_index.next * 3 - column_range = grid_column_index * 3 ... grid_column_index.next * 3 + def column_starts_for_grid(i) + zero_based(i) % 3 * 3 + end - subgrid_array = [] - row_range.each do |ri| - column_range.each do |ci| - subgrid_array << grid[ri][ci] - end - end - subgrid_array + def zero_based(i) + i - 1 end def validate! reset_errors! - [:invalid, :incomplete].each do |error_type| [:row, :column, :subgrid].each do |array_type| - (1..9).each do |i| - if SudokuValidator.array_is? error_type, send(array_type, i) - errors[error_type][array_type] << i - end + (1..9).each do |i| + errors[error_type][array_type] << i if array_is? error_type, send(array_type, i) end end end diff --git a/spec/lib/sudoku_reader_spec.rb b/spec/lib/sudoku_reader_spec.rb index c48b5ff..7e68945 100644 --- a/spec/lib/sudoku_reader_spec.rb +++ b/spec/lib/sudoku_reader_spec.rb @@ -2,41 +2,42 @@ describe SudokuReader do - describe '.parse_line' do + let(:reader) { SudokuReader.new } + + describe '#parse_line' do it 'returns an array' do - parsed_line = SudokuReader.parse_line "8 5 9 |6 1 2 |4 3 7 " + parsed_line = reader.parse_line "8 5 9 |6 1 2 |4 3 7 " expect(parsed_line).to eq ["8", "5", "9", "6", "1", "2", "4", "3", "7"] - parsed_line = SudokuReader.parse_line ". . . |. 8 . |. 7 . " + parsed_line = reader.parse_line ". . . |. 8 . |. 7 . " expect(parsed_line).to eq [".", ".", ".", ".", "8", ".", ".", "7", "."] - parsed_line = SudokuReader.parse_line "------+------+------" + parsed_line = reader.parse_line "------+------+------" expect(parsed_line).to be_nil end end - describe '.separator_line?' do + describe '#separator_line?' do it 'returns true if the line is -----' do line = "------+------+------" - expect(SudokuReader.separator_line?(line)).to be_true + expect(reader.separator_line?(line)).to be_true line = "8 5 9 |6 1 2 |4 3 7 " - expect(SudokuReader.separator_line?(line)).to be_false + expect(reader.separator_line?(line)).to be_false line = ". . . |. 8 . |. 7 . " - expect(SudokuReader.separator_line?(line)).to be_false + expect(reader.separator_line?(line)).to be_false end end describe '#read' do it 'reads and stores the file into an array' do - reader = SudokuReader.new reader.read fixture_path('valid_incomplete.sudoku') expect(reader.grid.length).to eq 9 # rows @@ -46,7 +47,15 @@ expect(reader.grid[0][4]).to eq "." expect(reader.grid[2][2]).to eq "4" end - end + describe '#reader_from_file' do + it 'creates an instance of reader with a grid generated from file' do + reader = SudokuReader.reader_from_file(fixture_path('valid_incomplete.sudoku')) + + expect(reader.grid.length).to eq 9 + expect(reader.grid[0][4]).to eq "." + expect(reader.grid[2][2]).to eq "4" + end + end end \ No newline at end of file diff --git a/spec/lib/sudoku_validator_spec.rb b/spec/lib/sudoku_validator_spec.rb index 6c4e7e8..e45b5d8 100644 --- a/spec/lib/sudoku_validator_spec.rb +++ b/spec/lib/sudoku_validator_spec.rb @@ -3,61 +3,54 @@ describe SudokuValidator do - describe '.valid_array?' do + def create_validator(file_path=fixture_path('valid_complete.sudoku')) + SudokuValidator.new(file_path) + end + + describe '#valid_array?' do it 'returns false if there are repeats excluding "."' do - expect(SudokuValidator.valid_array?(["1", "2", "3"])).to be_true - expect(SudokuValidator.valid_array?(["1", "2", "3", "3"])).to be_false - expect(SudokuValidator.valid_array?(["1", "2", ".", "."])).to be_true + validator = create_validator + expect(validator.valid_array?(["1", "2", "3"])).to be_true + expect(validator.valid_array?(["1", "2", "3", "3"])).to be_false + expect(validator.valid_array?(["1", "2", ".", "."])).to be_true end end - describe '.complete_array?' do + describe '#complete_array?' do it 'returns false if the number elements have count of 9 excluding "."' do - expect(SudokuValidator.complete_array?(["1", "2", ".", "."])).to be_false - expect(SudokuValidator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "."])).to be_false - expect(SudokuValidator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "8"])).to be_true + validator = create_validator + expect(validator.complete_array?(["1", "2", ".", "."])).to be_false + expect(validator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "."])).to be_false + expect(validator.complete_array?(["1", "2", "3", "4", "5", "6", "7", "8", "8"])).to be_true end end - describe '.array_ok?' do + describe '#array_ok?' do it 'calls valid_array? if :invalid is given and returns the opposite' do + validator = create_validator some_array = [1,2,3] - expect(SudokuValidator).to receive(:valid_array?).with(some_array).once.and_return(false) - - expect(SudokuValidator.array_is?(:invalid, some_array)).to be_true - - expect(SudokuValidator).to receive(:valid_array?).with(some_array).once.and_return(true) - - expect(SudokuValidator.array_is?(:invalid, some_array)).to be_false + expect(validator).to receive(:valid_array?).with(some_array).once.and_return(false) + expect(validator.array_is?(:invalid, some_array)).to be_true + expect(validator).to receive(:valid_array?).with(some_array).once.and_return(true) + expect(validator.array_is?(:invalid, some_array)).to be_false end it 'calls complete_array? if :incomplete is given and returns the opposite' do + validator = create_validator some_array = [1,2,3] - expect(SudokuValidator).to receive(:complete_array?).with(some_array).once.and_return(false) - - expect(SudokuValidator.array_is?(:incomplete, some_array)).to be_true - - expect(SudokuValidator).to receive(:complete_array?).with(some_array).once.and_return(true) - - expect(SudokuValidator.array_is?(:incomplete, some_array)).to be_false + expect(validator).to receive(:complete_array?).with(some_array).once.and_return(false) + expect(validator.array_is?(:incomplete, some_array)).to be_true + expect(validator).to receive(:complete_array?).with(some_array).once.and_return(true) + expect(validator.array_is?(:incomplete, some_array)).to be_false end end describe '#initialize' do - it 'stores the grid' do - reader = SudokuReader.new - reader.read(fixture_path('valid_incomplete.sudoku')) - validator = SudokuValidator.new reader.grid - - expect(validator.grid).to eq reader.grid - end - - it 'optionally takes a filepath' do + it 'takes a filepath and stores the grid' do reader = SudokuReader.new reader.read(fixture_path('valid_incomplete.sudoku')) - validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') expect(validator.grid).to eq reader.grid @@ -103,8 +96,8 @@ # it 'retrieves a subgrid as an array' do - validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') - + validator = create_validator('valid_incomplete.sudoku') + expect(validator.subgrid(3)).to eq ["4", ".", ".", ".", ".", "9", ".", ".", "."] expect(validator.subgrid(7)).to eq [".", ".", ".", ".", "1", "7", ".", ".", "."] end @@ -112,7 +105,7 @@ describe '#validate!' do it 'runs finds and logs all the errors' do - validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator = create_validator('invalid_incomplete.sudoku') validator.validate! expect(validator.errors[:invalid][:row]).to eq [] expect(validator.errors[:invalid][:column]).to eq [2, 5] @@ -125,7 +118,7 @@ describe '#error_messages' do it 'ouputs the correct error messages' do - validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator = create_validator('invalid_incomplete.sudoku') validator.validate! expect(validator.error_messages(:invalid)).to eq [ @@ -140,42 +133,40 @@ end describe '#valid?' do - it 'validates all 3 array checks' do - validator = SudokuValidator.new fixture_path('valid_complete.sudoku') + validator = create_validator('valid_complete.sudoku') validator.validate! expect(validator.valid?).to be_true - validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + validator = create_validator('valid_incomplete.sudoku') validator.validate! expect(validator.valid?).to be_true - validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + validator = create_validator('invalid_complete.sudoku') validator.validate! expect(validator.valid?).to be_false - validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator = create_validator('invalid_incomplete.sudoku') validator.validate! expect(validator.valid?).to be_false end end describe '#complete?' do - it 'validates all 3 array checks' do - validator = SudokuValidator.new fixture_path('valid_complete.sudoku') + validator = create_validator('valid_complete.sudoku') validator.validate! expect(validator.complete?).to be_true - validator = SudokuValidator.new fixture_path('valid_incomplete.sudoku') + validator = create_validator('valid_incomplete.sudoku') validator.validate! expect(validator.complete?).to be_false - validator = SudokuValidator.new fixture_path('invalid_incomplete.sudoku') + validator = create_validator('invalid_incomplete.sudoku') validator.validate! expect(validator.complete?).to be_false - validator = SudokuValidator.new fixture_path('invalid_complete.sudoku') + validator = create_validator('invalid_complete.sudoku') validator.validate! expect(validator.complete?).to be_true end diff --git a/sudoku-validator b/sudoku-validator index f612866..2598f7d 100755 --- a/sudoku-validator +++ b/sudoku-validator @@ -40,14 +40,12 @@ if validator.valid? puts "This sudoku is valid." else puts "This sudoku is valid, but incomplete." - puts "\n** Errors *************************\n" puts "" validator.error_messages(:incomplete).each { |msg| puts msg } puts GRID_LOCATION end else puts 'This sudoku is invalid.' - puts "\n** Errors *************************" puts "" validator.error_messages(:invalid).each { |msg| puts msg } validator.error_messages(:incomplete).each { |msg| puts msg }