From fc6fe8a4f97f0d9869b8c0ae046e7f89fc9cdab9 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 17:49:11 -0400 Subject: [PATCH 01/25] read lines for complete grids --- lib/sudoku_reader.rb | 22 ++++++++++++++++++++++ spec/sudoku_reader_spec.rb | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 lib/sudoku_reader.rb create mode 100644 spec/sudoku_reader_spec.rb diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb new file mode 100644 index 0000000..e924ae2 --- /dev/null +++ b/lib/sudoku_reader.rb @@ -0,0 +1,22 @@ +class SudokuReader + attr_accessor :lines + + def initialize(path) + @lines = [] + File.read(path).each_line do |line| + unless separator?(line) + lines << line.split(' ').map { |value| cleaned_value(value) } + end + end + end + + private + + def separator?(line) + line == "------+------+------\n" + end + + def cleaned_value(value) + value.gsub('|','').to_i + end +end diff --git a/spec/sudoku_reader_spec.rb b/spec/sudoku_reader_spec.rb new file mode 100644 index 0000000..766fe83 --- /dev/null +++ b/spec/sudoku_reader_spec.rb @@ -0,0 +1,35 @@ +require_relative '../lib/sudoku_reader' + +describe SudokuReader do + context "with the valid grid" do + it "give lines" do + reader = SudokuReader.new('valid_complete.sudoku') + grid = [[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]] + expect(reader.lines).to eq grid + end + end + + context "with the invalid complete grid" do + it "give lines" do + reader = SudokuReader.new('invalid_complete.sudoku') + grid = [[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]] + expect(reader.lines).to eq grid + end + end +end From 34cfe77b37df8d47dd45d7e175c41e071ea2e49a Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 17:49:23 -0400 Subject: [PATCH 02/25] add the .rspec file --- .rspec | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .rspec diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..35f4d74 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format Fuubar From 6d7f65180bf63e8f564d482ddaa0e0225b06ba8f Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 17:56:21 -0400 Subject: [PATCH 03/25] add test for last files --- spec/sudoku_reader_spec.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/sudoku_reader_spec.rb b/spec/sudoku_reader_spec.rb index 766fe83..bb3495c 100644 --- a/spec/sudoku_reader_spec.rb +++ b/spec/sudoku_reader_spec.rb @@ -32,4 +32,36 @@ expect(reader.lines).to eq grid end end + + context "with the valid incomplete grid" do + it "give lines" do + reader = SudokuReader.new('valid_incomplete.sudoku') + grid= [[8,5,0,0,0,2,4,0,0], + [7,2,0,0,0,0,0,0,9], + [0,0,4,0,0,0,0,0,0], + [0,0,0,1,0,7,0,0,2], + [3,0,5,0,0,0,9,0,0], + [0,4,0,0,0,0,0,0,0], + [0,0,0,0,8,0,0,7,0], + [0,1,7,0,0,0,0,0,0], + [0,0,0,0,3,6,0,4,0]] + expect(reader.lines).to eq grid + end + end + + context "with the invalid incomplete grid" do + it "give lines" do + reader = SudokuReader.new('invalid_incomplete.sudoku') + grid= [[8,5,0,0,0,2,4,0,0], + [7,2,0,0,8,0,0,0,9], + [0,0,4,0,0,0,0,0,0], + [0,0,0,1,0,7,0,0,2], + [3,0,5,0,0,0,9,0,0], + [0,4,0,0,0,0,0,0,0], + [0,5,0,0,8,0,0,7,0], + [0,1,7,0,0,0,0,0,0], + [0,0,0,0,3,6,0,4,0]] + expect(reader.lines).to eq grid + end + end end From 3c32a28967aa1eaf4c4a890c63da0c8428ece32a Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 18:15:56 -0400 Subject: [PATCH 04/25] refactoring --- lib/sudoku_reader.rb | 24 +++++--- spec/sudoku_reader_spec.rb | 120 ++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 55 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index e924ae2..7862a75 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -1,16 +1,26 @@ class SudokuReader - attr_accessor :lines + attr_reader :path def initialize(path) - @lines = [] - File.read(path).each_line do |line| - unless separator?(line) - lines << line.split(' ').map { |value| cleaned_value(value) } - end - end + @path = path + end + + def grid + fill_grid_from_file unless @grid + @grid end private + def fill_grid_from_file + @grid = [] + File.read(path).each_line {|line| convert_line_to_values(line)} + end + + def convert_line_to_values(line) + unless separator?(line) + @grid << line.split.map { |value| cleaned_value(value) } + end + end def separator?(line) line == "------+------+------\n" diff --git a/spec/sudoku_reader_spec.rb b/spec/sudoku_reader_spec.rb index bb3495c..bfdb3af 100644 --- a/spec/sudoku_reader_spec.rb +++ b/spec/sudoku_reader_spec.rb @@ -2,66 +2,90 @@ describe SudokuReader do context "with the valid grid" do - it "give lines" do - reader = SudokuReader.new('valid_complete.sudoku') - grid = [[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]] - expect(reader.lines).to eq grid + it "give grid" do + expect(reader.grid).to eq grid + end + + def reader + SudokuReader.new('valid_complete.sudoku') + end + + def grid + [[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]] end end context "with the invalid complete grid" do - it "give lines" do - reader = SudokuReader.new('invalid_complete.sudoku') - grid = [[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]] - expect(reader.lines).to eq grid + it "give grid" do + expect(reader.grid).to eq grid + end + + def reader + SudokuReader.new('invalid_complete.sudoku') + end + + def grid + [[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]] end end context "with the valid incomplete grid" do - it "give lines" do - reader = SudokuReader.new('valid_incomplete.sudoku') - grid= [[8,5,0,0,0,2,4,0,0], - [7,2,0,0,0,0,0,0,9], - [0,0,4,0,0,0,0,0,0], - [0,0,0,1,0,7,0,0,2], - [3,0,5,0,0,0,9,0,0], - [0,4,0,0,0,0,0,0,0], - [0,0,0,0,8,0,0,7,0], - [0,1,7,0,0,0,0,0,0], - [0,0,0,0,3,6,0,4,0]] - expect(reader.lines).to eq grid + it "give grid" do + expect(reader.grid).to eq grid + end + + def reader + SudokuReader.new('valid_incomplete.sudoku') + end + + def grid + [[8,5,0,0,0,2,4,0,0], + [7,2,0,0,0,0,0,0,9], + [0,0,4,0,0,0,0,0,0], + [0,0,0,1,0,7,0,0,2], + [3,0,5,0,0,0,9,0,0], + [0,4,0,0,0,0,0,0,0], + [0,0,0,0,8,0,0,7,0], + [0,1,7,0,0,0,0,0,0], + [0,0,0,0,3,6,0,4,0]] end end context "with the invalid incomplete grid" do - it "give lines" do - reader = SudokuReader.new('invalid_incomplete.sudoku') - grid= [[8,5,0,0,0,2,4,0,0], - [7,2,0,0,8,0,0,0,9], - [0,0,4,0,0,0,0,0,0], - [0,0,0,1,0,7,0,0,2], - [3,0,5,0,0,0,9,0,0], - [0,4,0,0,0,0,0,0,0], - [0,5,0,0,8,0,0,7,0], - [0,1,7,0,0,0,0,0,0], - [0,0,0,0,3,6,0,4,0]] - expect(reader.lines).to eq grid + it "give grid" do + expect(reader.grid).to eq grid + end + + def reader + SudokuReader.new('invalid_incomplete.sudoku') + end + + def grid + [[8,5,0,0,0,2,4,0,0], + [7,2,0,0,8,0,0,0,9], + [0,0,4,0,0,0,0,0,0], + [0,0,0,1,0,7,0,0,2], + [3,0,5,0,0,0,9,0,0], + [0,4,0,0,0,0,0,0,0], + [0,5,0,0,8,0,0,7,0], + [0,1,7,0,0,0,0,0,0], + [0,0,0,0,3,6,0,4,0]] end end end From 3c9be03e4adca129dd9890a3690c80ff6b767564 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 18:24:49 -0400 Subject: [PATCH 05/25] add the incomplete spec --- lib/sudoku_validator.rb | 12 ++++++++++++ spec/sudoku_validator_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 lib/sudoku_validator.rb create mode 100644 spec/sudoku_validator_spec.rb diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb new file mode 100644 index 0000000..5fe6bb7 --- /dev/null +++ b/lib/sudoku_validator.rb @@ -0,0 +1,12 @@ +class SudokuValidator + def initialize(reader) + @reader = reader + end + + def complete? + @reader.grid.each do |line| + return false if line.include?(0) + end + return true + end +end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb new file mode 100644 index 0000000..71492f6 --- /dev/null +++ b/spec/sudoku_validator_spec.rb @@ -0,0 +1,22 @@ +require_relative '../lib/sudoku_validator' +require_relative '../lib/sudoku_reader.rb' + +describe SudokuValidator do + describe "#complete?" do + context "when the sudoku is complete" do + it "is true" do + reader = SudokuReader.new('valid_complete.sudoku') + validator = SudokuValidator.new(reader) + expect(validator).to be_complete + end + end + + context "when the sudoku is complete" do + it "is true" do + reader = SudokuReader.new('valid_incomplete.sudoku') + validator = SudokuValidator.new(reader) + expect(validator).to_not be_complete + end + end + end +end From 36e377d55bd2b4abfc841858486d140af1374c57 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 18:49:41 -0400 Subject: [PATCH 06/25] check validity of lines --- lib/sudoku_reader.rb | 8 ++++++++ lib/sudoku_validator.rb | 9 ++++++--- spec/sudoku_validator_spec.rb | 38 +++++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 7862a75..17cdda3 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -10,6 +10,14 @@ def grid @grid end + def each_line + grid.each {|line| yield(line)} + end + + def each_value + each_line {|line| line.each{|value| yield(line, value)}} + end + private def fill_grid_from_file @grid = [] diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5fe6bb7..5fcc24f 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -4,9 +4,12 @@ def initialize(reader) end def complete? - @reader.grid.each do |line| - return false if line.include?(0) - end + @reader.each_line {|line| return false if line.include?(0)} + return true + end + + def valid? + @reader.each_value {|line, value| return false if line.count(value) > 1} return true end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 71492f6..660c2bc 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -5,18 +5,48 @@ describe "#complete?" do context "when the sudoku is complete" do it "is true" do - reader = SudokuReader.new('valid_complete.sudoku') - validator = SudokuValidator.new(reader) expect(validator).to be_complete end + + def reader + SudokuReader.new('valid_complete.sudoku') + end end context "when the sudoku is complete" do it "is true" do - reader = SudokuReader.new('valid_incomplete.sudoku') - validator = SudokuValidator.new(reader) expect(validator).to_not be_complete end + + def reader + SudokuReader.new('valid_incomplete.sudoku') + end + end + end + + describe "#valid?" do + context "when the sudoku is valid" do + it "is true" do + expect(validator).to be_valid + end + + def reader + SudokuReader.new('valid_complete.sudoku') + end + end + + context "when the sudoku is complete" do + it "is true" do + expect(validator).to_not be_valid + end + + def reader + SudokuReader.new('invalid_incomplete.sudoku') + end end end + + def validator + SudokuValidator.new(reader) + end end From 284896718bee3d655c7355a33a3983e673fc60ff Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 19:26:22 -0400 Subject: [PATCH 07/25] check line validity --- lib/sudoku_validator.rb | 4 +- spec/sudoku_validator_spec.rb | 110 +++++++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 28 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5fcc24f..9261f7e 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -9,7 +9,9 @@ def complete? end def valid? - @reader.each_value {|line, value| return false if line.count(value) > 1} + @reader.each_value do |line, value| + return false if line.count(value) > 1 && value != 0 + end return true end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 660c2bc..c46a314 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -2,51 +2,107 @@ require_relative '../lib/sudoku_reader.rb' describe SudokuValidator do - describe "#complete?" do - context "when the sudoku is complete" do - it "is true" do - expect(validator).to be_complete + shared_examples "a complete sudoku" do + describe "#complete?" do + context "when the sudoku is complete" do + it "is compete" do + expect(validator).to be_complete + end end + end + end - def reader - SudokuReader.new('valid_complete.sudoku') + shared_examples "a incomplete sudoku" do + describe "#complete?" do + context "when the sudoku is incomplete" do + it "is not complete" do + expect(validator).to_not be_complete + end end end + end - context "when the sudoku is complete" do - it "is true" do - expect(validator).to_not be_complete + shared_examples "a valid sudoku" do + describe "#valid?" do + context "when the sudoku is valid" do + it "is valid" do + expect(validator).to be_valid + end end + end + end - def reader - SudokuReader.new('valid_incomplete.sudoku') + shared_examples "a invalid sudoku" do + describe "#valid?" do + context "when the sudoku is invalid" do + it "is not valid" do + expect(validator).to_not be_valid + end end end end - describe "#valid?" do - context "when the sudoku is valid" do - it "is true" do - expect(validator).to be_valid - end + describe "valid and complete sudoku" do + it_behaves_like "a complete sudoku" + it_behaves_like "a valid sudoku" - def reader - SudokuReader.new('valid_complete.sudoku') - end + before do + grid = [[1,2], + [2,1]] + allow(reader).to receive(:grid).and_return(grid) end - context "when the sudoku is complete" do - it "is true" do - expect(validator).to_not be_valid - end + def reader + @reader ||= SudokuReader.new('valid_complete.sudoku') + end + end - def reader - SudokuReader.new('invalid_incomplete.sudoku') - end + describe "valid an incomplete sudoku" do + it_behaves_like "a incomplete sudoku" + it_behaves_like "a valid sudoku" + + before do + grid = [[1,2], + [2,0]] + allow(reader).to receive(:grid).and_return(grid) + end + + def reader + @reader ||= SudokuReader.new('valid_incomplete.sudoku') + end + end + + describe "invalid lines and complete" do + it_behaves_like "a complete sudoku" + it_behaves_like "a invalid sudoku" + + before do + grid = [[1,1], + [2,3]] + allow(reader).to receive(:grid).and_return(grid) + end + + def reader + @reader ||= SudokuReader.new('invalid_incomplete.sudoku') + end + end + + describe "invalid lines and incomplete" do + it_behaves_like "a incomplete sudoku" + it_behaves_like "a invalid sudoku" + + before do + grid = [[1,1], + [2,0]] + allow(reader).to receive(:grid).and_return(grid) + end + + def reader + @reader ||= SudokuReader.new('invalid_incomplete.sudoku') end end def validator - SudokuValidator.new(reader) + @validator ||= SudokuValidator.new(reader) end end From 3b1f21b6240cc1a9db0ea1ff0084c346c910b394 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 19:30:02 -0400 Subject: [PATCH 08/25] refactor --- spec/sudoku_validator_spec.rb | 52 ++++++++++++++--------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index c46a314..4801e6f 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -2,6 +2,10 @@ require_relative '../lib/sudoku_reader.rb' describe SudokuValidator do + before do + allow(reader).to receive(:grid).and_return(grid) + end + shared_examples "a complete sudoku" do describe "#complete?" do context "when the sudoku is complete" do @@ -46,14 +50,9 @@ it_behaves_like "a complete sudoku" it_behaves_like "a valid sudoku" - before do - grid = [[1,2], - [2,1]] - allow(reader).to receive(:grid).and_return(grid) - end - - def reader - @reader ||= SudokuReader.new('valid_complete.sudoku') + def grid + [[1,2], + [2,1]] end end @@ -61,14 +60,9 @@ def reader it_behaves_like "a incomplete sudoku" it_behaves_like "a valid sudoku" - before do - grid = [[1,2], - [2,0]] - allow(reader).to receive(:grid).and_return(grid) - end - - def reader - @reader ||= SudokuReader.new('valid_incomplete.sudoku') + def grid + [[1,2], + [2,0]] end end @@ -76,14 +70,9 @@ def reader it_behaves_like "a complete sudoku" it_behaves_like "a invalid sudoku" - before do - grid = [[1,1], - [2,3]] - allow(reader).to receive(:grid).and_return(grid) - end - - def reader - @reader ||= SudokuReader.new('invalid_incomplete.sudoku') + def grid + [[1,1], + [2,3]] end end @@ -91,18 +80,17 @@ def reader it_behaves_like "a incomplete sudoku" it_behaves_like "a invalid sudoku" - before do - grid = [[1,1], - [2,0]] - allow(reader).to receive(:grid).and_return(grid) - end - - def reader - @reader ||= SudokuReader.new('invalid_incomplete.sudoku') + def grid + [[1,1], + [2,0]] end end def validator @validator ||= SudokuValidator.new(reader) end + + def reader + @reader ||= SudokuReader.new('a_path') + end end From 30df7a677d713f3c7850e8fd51434c30722d3d27 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 19:47:49 -0400 Subject: [PATCH 09/25] check validity for columns --- lib/sudoku_reader.rb | 24 +++++++++++++++++++++++- lib/sudoku_validator.rb | 6 +++++- spec/sudoku_validator_spec.rb | 10 ++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 17cdda3..8697b4d 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -14,11 +14,33 @@ def each_line grid.each {|line| yield(line)} end - def each_value + def each_value_by_line each_line {|line| line.each{|value| yield(line, value)}} end + def each_value_by_column + columns.each {|column| column.each{|value| yield(column, value)}} + end + private + def columns + return @columns if @columns + init_grid + each_line {|line| grid_size.times.each {|i| @columns[i] << line[i]}} + @columns + end + + def init_grid + @columns = [] + grid_size.times do + @columns << [] + end + end + + def grid_size + grid.first.count + end + def fill_grid_from_file @grid = [] File.read(path).each_line {|line| convert_line_to_values(line)} diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 9261f7e..5799faf 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -9,9 +9,13 @@ def complete? end def valid? - @reader.each_value do |line, value| + @reader.each_value_by_line do |line, value| return false if line.count(value) > 1 && value != 0 end + + @reader.each_value_by_column do |column, value| + return false if column.count(value) > 1 && value != 0 + end return true end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 4801e6f..d379e62 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -86,6 +86,16 @@ def grid end end + describe "invalid columns and complete" do + it_behaves_like "a complete sudoku" + it_behaves_like "a invalid sudoku" + + def grid + [[1,3], + [1,2]] + end + end + def validator @validator ||= SudokuValidator.new(reader) end From 9c111d279792afb70db193c0b0aeb0af350925d2 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 15 Oct 2013 22:48:55 -0400 Subject: [PATCH 10/25] refactor (again) --- invalid_block_incomplete.sudoku | 11 ++++++ invalid_column_complete.sudoku | 11 ++++++ invalid_line_complete.sudoku | 11 ++++++ lib/sudoku_reader.rb | 61 +++++++++++++++++++++++---------- lib/sudoku_validator.rb | 27 +++++++++++---- spec/sudoku_reader_spec.rb | 16 ++++----- spec/sudoku_validator_spec.rb | 53 ++++++++++++++++------------ valid_complete.sudoku | 18 +++++----- 8 files changed, 145 insertions(+), 63 deletions(-) create mode 100644 invalid_block_incomplete.sudoku create mode 100644 invalid_column_complete.sudoku create mode 100644 invalid_line_complete.sudoku diff --git a/invalid_block_incomplete.sudoku b/invalid_block_incomplete.sudoku new file mode 100644 index 0000000..8ed3bd8 --- /dev/null +++ b/invalid_block_incomplete.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 . |2 6 8 |9 1 4 +2 4 1 |5 9 3 |7 8 6 +------+------+------ +4 3 5 |9 8 1 |6 7 . +6 1 7 |4 2 5 |8 9 3 +5 9 8 |7 3 6 |2 4 1 diff --git a/invalid_column_complete.sudoku b/invalid_column_complete.sudoku new file mode 100644 index 0000000..ba5fb31 --- /dev/null +++ b/invalid_column_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/invalid_line_complete.sudoku b/invalid_line_complete.sudoku new file mode 100644 index 0000000..0eab989 --- /dev/null +++ b/invalid_line_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/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 8697b4d..45f6eb2 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -3,15 +3,19 @@ class SudokuReader def initialize(path) @path = path + @lines = [] + @columns = [] + @blocks = [] end - def grid - fill_grid_from_file unless @grid - @grid + def lines + return @lines if @lines.any? + File.read(path).each_line {|line| convert_line_to_values(line)} + @lines end def each_line - grid.each {|line| yield(line)} + lines.each {|line| yield(line)} end def each_value_by_line @@ -22,33 +26,54 @@ def each_value_by_column columns.each {|column| column.each{|value| yield(column, value)}} end + def each_value_by_block + blocks.each {|block| block.each{|value| yield(block, value)}} + end + private + def blocks + return @blocks if @blocks.any? + init_blocks + fill_blocks + @blocks + end + + def fill_blocks + block_vertical_number = block_horizontal_number = 0 + grid_size.times do |i| + block_vertical_number += 3 if i%3 == 0 + columns[i].each_with_index do |value, j| + block_horizontal_number += 1 if j%3 == 0 + block_number = (block_horizontal_number - 1 + block_vertical_number - 3) + @blocks[block_number] << value + end + + block_horizontal_number = 0 + end + end + + def init_blocks + grid_size.times { @blocks << [] } + end + def columns - return @columns if @columns - init_grid + return @columns if @columns.any? + init_columns each_line {|line| grid_size.times.each {|i| @columns[i] << line[i]}} @columns end - def init_grid - @columns = [] - grid_size.times do - @columns << [] - end + def init_columns + grid_size.times { @columns << [] } end def grid_size - grid.first.count - end - - def fill_grid_from_file - @grid = [] - File.read(path).each_line {|line| convert_line_to_values(line)} + lines.first.count end def convert_line_to_values(line) unless separator?(line) - @grid << line.split.map { |value| cleaned_value(value) } + @lines << line.split.map { |value| cleaned_value(value) } end end diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5799faf..e195f9e 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -1,20 +1,35 @@ class SudokuValidator + attr_accessor :reader + def initialize(reader) @reader = reader end def complete? - @reader.each_line {|line| return false if line.include?(0)} + reader.each_line {|line| return false if line.include?(0)} return true end def valid? - @reader.each_value_by_line do |line, value| - return false if line.count(value) > 1 && value != 0 - end + lines_valid? && columns_valid? && blocks_valid? + end + + private + def lines_valid? + check_validity_for(:line) + end + + def columns_valid? + check_validity_for(:column) + end + + def blocks_valid? + check_validity_for(:block) + end - @reader.each_value_by_column do |column, value| - return false if column.count(value) > 1 && value != 0 + def check_validity_for(type) + reader.send("each_value_by_#{type}") do |row, value| + return false if row.count(value) > 1 && value != 0 end return true end diff --git a/spec/sudoku_reader_spec.rb b/spec/sudoku_reader_spec.rb index bfdb3af..21a6b01 100644 --- a/spec/sudoku_reader_spec.rb +++ b/spec/sudoku_reader_spec.rb @@ -3,14 +3,14 @@ describe SudokuReader do context "with the valid grid" do it "give grid" do - expect(reader.grid).to eq grid + expect(reader.lines).to eq lines end def reader SudokuReader.new('valid_complete.sudoku') end - def grid + def lines [[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], @@ -25,14 +25,14 @@ def grid context "with the invalid complete grid" do it "give grid" do - expect(reader.grid).to eq grid + expect(reader.lines).to eq lines end def reader SudokuReader.new('invalid_complete.sudoku') end - def grid + def lines [[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], @@ -47,14 +47,14 @@ def grid context "with the valid incomplete grid" do it "give grid" do - expect(reader.grid).to eq grid + expect(reader.lines).to eq lines end def reader SudokuReader.new('valid_incomplete.sudoku') end - def grid + def lines [[8,5,0,0,0,2,4,0,0], [7,2,0,0,0,0,0,0,9], [0,0,4,0,0,0,0,0,0], @@ -69,14 +69,14 @@ def grid context "with the invalid incomplete grid" do it "give grid" do - expect(reader.grid).to eq grid + expect(reader.lines).to eq lines end def reader SudokuReader.new('invalid_incomplete.sudoku') end - def grid + def lines [[8,5,0,0,0,2,4,0,0], [7,2,0,0,8,0,0,0,9], [0,0,4,0,0,0,0,0,0], diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index d379e62..c954dff 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -3,7 +3,7 @@ describe SudokuValidator do before do - allow(reader).to receive(:grid).and_return(grid) + allow(reader).to receive(:reader).and_return(reader) end shared_examples "a complete sudoku" do @@ -50,9 +50,8 @@ it_behaves_like "a complete sudoku" it_behaves_like "a valid sudoku" - def grid - [[1,2], - [2,1]] + def reader + SudokuReader.new('valid_complete.sudoku') end end @@ -60,29 +59,35 @@ def grid it_behaves_like "a incomplete sudoku" it_behaves_like "a valid sudoku" - def grid - [[1,2], - [2,0]] + def reader + SudokuReader.new('valid_incomplete.sudoku') end end - describe "invalid lines and complete" do + describe "invalid an complete sudoku" do it_behaves_like "a complete sudoku" it_behaves_like "a invalid sudoku" - def grid - [[1,1], - [2,3]] + def reader + SudokuReader.new('invalid_complete.sudoku') end end - describe "invalid lines and incomplete" do + describe "invalid an incomplete sudoku" do it_behaves_like "a incomplete sudoku" it_behaves_like "a invalid sudoku" - def grid - [[1,1], - [2,0]] + def reader + SudokuReader.new('invalid_incomplete.sudoku') + end + end + + describe "invalid lines and complete" do + it_behaves_like "a complete sudoku" + it_behaves_like "a invalid sudoku" + + def reader + SudokuReader.new('invalid_complete.sudoku') end end @@ -90,17 +95,21 @@ def grid it_behaves_like "a complete sudoku" it_behaves_like "a invalid sudoku" - def grid - [[1,3], - [1,2]] + def reader + SudokuReader.new('invalid_column_complete.sudoku') end end - def validator - @validator ||= SudokuValidator.new(reader) + describe "invalid subblock and incomplete" do + it_behaves_like "a incomplete sudoku" + it_behaves_like "a invalid sudoku" + + def reader + SudokuReader.new('invalid_block_incomplete.sudoku') + end end - def reader - @reader ||= SudokuReader.new('a_path') + def validator + @validator ||= SudokuValidator.new(reader) end end diff --git a/valid_complete.sudoku b/valid_complete.sudoku index ec5075c..0eab989 100644 --- a/valid_complete.sudoku +++ b/valid_complete.sudoku @@ -1,11 +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 +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 +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 +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 From 1be9083537798ac35e689c0eedd33e1e12a7e620 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 17:24:40 -0400 Subject: [PATCH 11/25] change the reader specs has they should be --- lib/sudoku_reader.rb | 19 ++++---- spec/sudoku_reader_spec.rb | 94 +++++++++----------------------------- 2 files changed, 30 insertions(+), 83 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 45f6eb2..eb94f07 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -30,7 +30,13 @@ def each_value_by_block blocks.each {|block| block.each{|value| yield(block, value)}} end - private + def columns + return @columns if @columns.any? + init_columns + each_line {|line| grid_size.times.each {|i| @columns[i] << line[i]}} + @columns + end + def blocks return @blocks if @blocks.any? init_blocks @@ -42,27 +48,20 @@ def fill_blocks block_vertical_number = block_horizontal_number = 0 grid_size.times do |i| block_vertical_number += 3 if i%3 == 0 - columns[i].each_with_index do |value, j| + lines[i].each_with_index do |value, j| block_horizontal_number += 1 if j%3 == 0 block_number = (block_horizontal_number - 1 + block_vertical_number - 3) @blocks[block_number] << value end - block_horizontal_number = 0 end end + private def init_blocks grid_size.times { @blocks << [] } end - def columns - return @columns if @columns.any? - init_columns - each_line {|line| grid_size.times.each {|i| @columns[i] << line[i]}} - @columns - end - def init_columns grid_size.times { @columns << [] } end diff --git a/spec/sudoku_reader_spec.rb b/spec/sudoku_reader_spec.rb index 21a6b01..f0ec06d 100644 --- a/spec/sudoku_reader_spec.rb +++ b/spec/sudoku_reader_spec.rb @@ -1,91 +1,39 @@ require_relative '../lib/sudoku_reader' describe SudokuReader do - context "with the valid grid" do - it "give grid" do - expect(reader.lines).to eq lines + describe "#lines" do + it "give lines" do + reader = SudokuReader.new('valid_complete.sudoku') + expect(reader.lines[0]).to eq [8,5,9,6,1,2,4,3,7] end - def reader - SudokuReader.new('valid_complete.sudoku') - end - - def lines - [[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]] + it "convert invalid values by 0" do + reader = SudokuReader.new('valid_incomplete.sudoku') + expect(reader.lines[0]).to eq [8,5,0,0,0,2,4,0,0] end end - context "with the invalid complete grid" do - it "give grid" do - expect(reader.lines).to eq lines - end - - def reader - SudokuReader.new('invalid_complete.sudoku') + describe "#columns" do + it "give columns" do + reader = SudokuReader.new('valid_complete.sudoku') + expect(reader.columns[0]).to eq [8,7,1,9,3,2,4,6,5] end - def lines - [[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]] + it "convert invalid values by 0" do + reader = SudokuReader.new('valid_incomplete.sudoku') + expect(reader.columns[0]).to eq [8,7,0,0,3,0,0,0,0] end end - context "with the valid incomplete grid" do - it "give grid" do - expect(reader.lines).to eq lines - end - - def reader - SudokuReader.new('valid_incomplete.sudoku') - end - - def lines - [[8,5,0,0,0,2,4,0,0], - [7,2,0,0,0,0,0,0,9], - [0,0,4,0,0,0,0,0,0], - [0,0,0,1,0,7,0,0,2], - [3,0,5,0,0,0,9,0,0], - [0,4,0,0,0,0,0,0,0], - [0,0,0,0,8,0,0,7,0], - [0,1,7,0,0,0,0,0,0], - [0,0,0,0,3,6,0,4,0]] - end - end - - context "with the invalid incomplete grid" do - it "give grid" do - expect(reader.lines).to eq lines - end - - def reader - SudokuReader.new('invalid_incomplete.sudoku') + describe "#blocks" do + it "give blocks" do + reader = SudokuReader.new('valid_complete.sudoku') + expect(reader.blocks[0]).to eq [8,5,9,7,2,3,1,6,4] end - def lines - [[8,5,0,0,0,2,4,0,0], - [7,2,0,0,8,0,0,0,9], - [0,0,4,0,0,0,0,0,0], - [0,0,0,1,0,7,0,0,2], - [3,0,5,0,0,0,9,0,0], - [0,4,0,0,0,0,0,0,0], - [0,5,0,0,8,0,0,7,0], - [0,1,7,0,0,0,0,0,0], - [0,0,0,0,3,6,0,4,0]] + it "convert invalid values by 0" do + reader = SudokuReader.new('valid_incomplete.sudoku') + expect(reader.blocks[0]).to eq [8,5,0,7,2,0,0,0,4] end end end From faa94ddc3ead76170538b6d4bc9fc0428912b6bd Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 17:54:28 -0400 Subject: [PATCH 12/25] reafactor the method to find grids --- lib/sudoku_reader.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index eb94f07..6e82bdc 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -45,15 +45,10 @@ def blocks end def fill_blocks - block_vertical_number = block_horizontal_number = 0 - grid_size.times do |i| - block_vertical_number += 3 if i%3 == 0 - lines[i].each_with_index do |value, j| - block_horizontal_number += 1 if j%3 == 0 - block_number = (block_horizontal_number - 1 + block_vertical_number - 3) - @blocks[block_number] << value + 0.step(6,3) do |k| + 3.times do |i| + 3.times {|j| @blocks[k+i] += lines[i*3+j][k..k+2]} end - block_horizontal_number = 0 end end From 3f32462ef2ee6f3d600e46993f6bdc67073fd1a8 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 17:57:48 -0400 Subject: [PATCH 13/25] use transpose --- lib/sudoku_reader.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 6e82bdc..02d962e 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -4,7 +4,6 @@ class SudokuReader def initialize(path) @path = path @lines = [] - @columns = [] @blocks = [] end @@ -31,10 +30,7 @@ def each_value_by_block end def columns - return @columns if @columns.any? - init_columns - each_line {|line| grid_size.times.each {|i| @columns[i] << line[i]}} - @columns + @columns ||= lines.transpose end def blocks @@ -57,10 +53,6 @@ def init_blocks grid_size.times { @blocks << [] } end - def init_columns - grid_size.times { @columns << [] } - end - def grid_size lines.first.count end From 0bc08d324d659a8cd766b3d987e0bac424e0d18c Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 18:01:14 -0400 Subject: [PATCH 14/25] refactor the block initialization --- lib/sudoku_reader.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 02d962e..c842c8b 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -35,7 +35,7 @@ def columns def blocks return @blocks if @blocks.any? - init_blocks + init_empty_blocks fill_blocks @blocks end @@ -49,12 +49,8 @@ def fill_blocks end private - def init_blocks - grid_size.times { @blocks << [] } - end - - def grid_size - lines.first.count + def init_empty_blocks + 9.times { @blocks << [] } end def convert_line_to_values(line) From 545c7551f87830f03388ef008fbcadca90d135ca Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 18:02:49 -0400 Subject: [PATCH 15/25] rename a method --- lib/sudoku_reader.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index c842c8b..4fc120d 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -55,7 +55,7 @@ def init_empty_blocks def convert_line_to_values(line) unless separator?(line) - @lines << line.split.map { |value| cleaned_value(value) } + @lines << line.split.map { |value| sanitize(value) } end end @@ -63,7 +63,7 @@ def separator?(line) line == "------+------+------\n" end - def cleaned_value(value) + def sanitize(value) value.gsub('|','').to_i end end From bb4dd63d749b4c280b83f143c0e0ba29e2620b8d Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 18:07:04 -0400 Subject: [PATCH 16/25] remove 2 lines --- lib/sudoku_reader.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 4fc120d..efae8a2 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -40,6 +40,7 @@ def blocks @blocks end + private def fill_blocks 0.step(6,3) do |k| 3.times do |i| @@ -48,15 +49,12 @@ def fill_blocks end end - private def init_empty_blocks 9.times { @blocks << [] } end def convert_line_to_values(line) - unless separator?(line) - @lines << line.split.map { |value| sanitize(value) } - end + @lines << line.split.map { |value| sanitize(value) } unless separator?(line) end def separator?(line) From a03603c89763434f07ea8aa8c6ae38892f0211ae Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 18:36:22 -0400 Subject: [PATCH 17/25] add messages for each case --- lib/sudoku_validator.rb | 12 ++++++++++++ spec/sudoku_validator_spec.rb | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index e195f9e..8312911 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -14,7 +14,19 @@ def valid? lines_valid? && columns_valid? && blocks_valid? end + def message + if valid? + "This sudoku is valid#{complete_message}." + else + "This sudoku is invalid." + end + end + private + def complete_message + ", but incomplete" unless complete? + end + def lines_valid? check_validity_for(:line) end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index c954dff..af94343 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -44,12 +44,24 @@ end end end + + describe "#message" do + it "say than the sudoku is valid" do + expect(validator.message).to eq "This sudoku is invalid." + end + end end describe "valid and complete sudoku" do it_behaves_like "a complete sudoku" it_behaves_like "a valid sudoku" + describe "#message" do + it "say than the sudoku is valid" do + expect(validator.message).to eq "This sudoku is valid." + end + end + def reader SudokuReader.new('valid_complete.sudoku') end @@ -59,6 +71,12 @@ def reader it_behaves_like "a incomplete sudoku" it_behaves_like "a valid sudoku" + describe "#message" do + it "say than the sudoku is valid" do + expect(validator.message).to eq "This sudoku is valid, but incomplete." + end + end + def reader SudokuReader.new('valid_incomplete.sudoku') end From 71e56fa5d607415c79f03904e766081f2a5283a9 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Wed, 16 Oct 2013 18:37:10 -0400 Subject: [PATCH 18/25] add the bin file --- bin/sudoku-validator | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 bin/sudoku-validator diff --git a/bin/sudoku-validator b/bin/sudoku-validator new file mode 100755 index 0000000..9e245f5 --- /dev/null +++ b/bin/sudoku-validator @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby + +require './lib/sudoku_reader' +require './lib/sudoku_validator' + +reader = SudokuReader.new(ARGV.first) +validator = SudokuValidator.new(reader) + +puts validator.message From 76dddb7b1b33c7828477330821401958a4d94180 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 17:58:32 -0400 Subject: [PATCH 19/25] make the validator spec dryer --- invalid_line_complete.sudoku | 4 +- spec/sudoku_validator_spec.rb | 143 ++++++++++------------------------ 2 files changed, 44 insertions(+), 103 deletions(-) diff --git a/invalid_line_complete.sudoku b/invalid_line_complete.sudoku index 0eab989..6500ea7 100644 --- a/invalid_line_complete.sudoku +++ b/invalid_line_complete.sudoku @@ -1,5 +1,5 @@ -8 5 9 |6 1 2 |4 3 7 -7 2 3 |8 5 4 |1 6 9 +8 5 9 |6 5 2 |4 3 7 +7 2 3 |8 1 4 |1 6 9 1 6 4 |3 7 9 |5 2 8 ------+------+------ 9 8 6 |1 4 7 |3 5 2 diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index af94343..5dff6b6 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -2,132 +2,73 @@ require_relative '../lib/sudoku_reader.rb' describe SudokuValidator do - before do - allow(reader).to receive(:reader).and_return(reader) - end - - shared_examples "a complete sudoku" do - describe "#complete?" do - context "when the sudoku is complete" do - it "is compete" do - expect(validator).to be_complete + describe "#complete?" do + context "with complete sudokus" do + it "give true" do + ['valid_complete.sudoku', 'invalid_complete.sudoku'].each do |file| + expect(validator_for(file)).to be_complete end end end - end - shared_examples "a incomplete sudoku" do - describe "#complete?" do - context "when the sudoku is incomplete" do - it "is not complete" do - expect(validator).to_not be_complete + context "with incomplete sudokus" do + it "give false" do + ['valid_incomplete.sudoku', 'invalid_incomplete.sudoku'].each do |file| + expect(validator_for(file)).to_not be_complete end end end end - shared_examples "a valid sudoku" do - describe "#valid?" do - context "when the sudoku is valid" do - it "is valid" do - expect(validator).to be_valid + describe "#valid?" do + context "with valid sudokus" do + it "give true" do + ['valid_complete.sudoku', 'valid_incomplete.sudoku'].each do |file| + expect(validator_for(file)).to be_valid end end end - end - shared_examples "a invalid sudoku" do - describe "#valid?" do - context "when the sudoku is invalid" do - it "is not valid" do - expect(validator).to_not be_valid + context "with invalid sudokus" do + it "give true" do + ['invalid_complete.sudoku', + 'invalid_incomplete.sudoku', + 'invalid_column_complete.sudoku', + 'invalid_block_incomplete.sudoku', + 'invalid_line_complete.sudoku'].each do |file| + expect(validator_for(file)).to_not be_valid end end end - - describe "#message" do - it "say than the sudoku is valid" do - expect(validator.message).to eq "This sudoku is invalid." - end - end end - describe "valid and complete sudoku" do - it_behaves_like "a complete sudoku" - it_behaves_like "a valid sudoku" - - describe "#message" do - it "say than the sudoku is valid" do - expect(validator.message).to eq "This sudoku is valid." + describe "#message" do + context "when the sudoku is valid" do + context "when the sudoku is complete" do + it "say than the sudoku is valid" do + file = 'valid_complete.sudoku' + expect(validator_for(file).message).to eq "This sudoku is valid." + end end - end - - def reader - SudokuReader.new('valid_complete.sudoku') - end - end - describe "valid an incomplete sudoku" do - it_behaves_like "a incomplete sudoku" - it_behaves_like "a valid sudoku" - - describe "#message" do - it "say than the sudoku is valid" do - expect(validator.message).to eq "This sudoku is valid, but incomplete." + context "when the sudoku is incomplete" do + it "say than the sudoku is valid" do + file = 'valid_incomplete.sudoku' + expect(validator_for(file).message).to eq "This sudoku is valid, but incomplete." + end end end - def reader - SudokuReader.new('valid_incomplete.sudoku') - end - end - - describe "invalid an complete sudoku" do - it_behaves_like "a complete sudoku" - it_behaves_like "a invalid sudoku" - - def reader - SudokuReader.new('invalid_complete.sudoku') - end - end - - describe "invalid an incomplete sudoku" do - it_behaves_like "a incomplete sudoku" - it_behaves_like "a invalid sudoku" - - def reader - SudokuReader.new('invalid_incomplete.sudoku') - end - end - - describe "invalid lines and complete" do - it_behaves_like "a complete sudoku" - it_behaves_like "a invalid sudoku" - - def reader - SudokuReader.new('invalid_complete.sudoku') - end - end - - describe "invalid columns and complete" do - it_behaves_like "a complete sudoku" - it_behaves_like "a invalid sudoku" - - def reader - SudokuReader.new('invalid_column_complete.sudoku') - end - end - - describe "invalid subblock and incomplete" do - it_behaves_like "a incomplete sudoku" - it_behaves_like "a invalid sudoku" - - def reader - SudokuReader.new('invalid_block_incomplete.sudoku') + context "when the sudoku is invalid" do + it "say than the sudoku is invalid" do + ['invalid_complete.sudoku', 'invalid_incomplete.sudoku'].each do |file| + expect(validator_for(file).message).to eq "This sudoku is invalid." + end + end end end - def validator - @validator ||= SudokuValidator.new(reader) + def validator_for(file) + SudokuValidator.new(SudokuReader.new(file)) end end From 36b5a67058e610c2d032aeb87ad2b00dfa8f3aa7 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 18:00:02 -0400 Subject: [PATCH 20/25] its not important if the sudoku is complete for special validations --- invalid_block.sudoku | 11 +++++++++++ invalid_column.sudoku | 11 +++++++++++ invalid_line.sudoku | 11 +++++++++++ spec/sudoku_validator_spec.rb | 6 +++--- 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 invalid_block.sudoku create mode 100644 invalid_column.sudoku create mode 100644 invalid_line.sudoku diff --git a/invalid_block.sudoku b/invalid_block.sudoku new file mode 100644 index 0000000..8ed3bd8 --- /dev/null +++ b/invalid_block.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 . |2 6 8 |9 1 4 +2 4 1 |5 9 3 |7 8 6 +------+------+------ +4 3 5 |9 8 1 |6 7 . +6 1 7 |4 2 5 |8 9 3 +5 9 8 |7 3 6 |2 4 1 diff --git a/invalid_column.sudoku b/invalid_column.sudoku new file mode 100644 index 0000000..fb651a7 --- /dev/null +++ b/invalid_column.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/invalid_line.sudoku b/invalid_line.sudoku new file mode 100644 index 0000000..6500ea7 --- /dev/null +++ b/invalid_line.sudoku @@ -0,0 +1,11 @@ +8 5 9 |6 5 2 |4 3 7 +7 2 3 |8 1 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/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 5dff6b6..f375a9f 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -33,9 +33,9 @@ it "give true" do ['invalid_complete.sudoku', 'invalid_incomplete.sudoku', - 'invalid_column_complete.sudoku', - 'invalid_block_incomplete.sudoku', - 'invalid_line_complete.sudoku'].each do |file| + 'invalid_column.sudoku', + 'invalid_block.sudoku', + 'invalid_line.sudoku'].each do |file| expect(validator_for(file)).to_not be_valid end end From 905ef839464e0229dacd26f210e2d0b1df60cbef Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 19:16:53 -0400 Subject: [PATCH 21/25] make the code to fill block clearer --- lib/sudoku_reader.rb | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index efae8a2..05aead7 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -42,13 +42,34 @@ def blocks private def fill_blocks - 0.step(6,3) do |k| - 3.times do |i| - 3.times {|j| @blocks[k+i] += lines[i*3+j][k..k+2]} + each_vertical_start_of_block do |i| + each_horizontal_start_of_block do |j| + each_line_in_block {|k| get_line_of_block(i, j, k)} end end end + def get_line_of_block(vertical_start, horizontal_start, line_block) + line = lines[horizontal_start * 3 + line_block] + line_in_block = line.drop(vertical_start).first(3) + index_of_block = vertical_start + horizontal_start + @blocks[index_of_block] += line_in_block + end + + def each_vertical_start_of_block + 0.step(6,3) do |index_of_subblock| + yield(index_of_subblock) + end + end + + def loop_in_subblock + 3.times do |index_line_of_block| + yield(index_line_of_block) + end + end + alias :each_horizontal_start_of_block :loop_in_subblock + alias :each_line_in_block :loop_in_subblock + def init_empty_blocks 9.times { @blocks << [] } end From 64a820b3e918f33f0dc77926da0202ef542cda50 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 19:17:32 -0400 Subject: [PATCH 22/25] make it shorter --- lib/sudoku_reader.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 05aead7..73d98c7 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -57,15 +57,11 @@ def get_line_of_block(vertical_start, horizontal_start, line_block) end def each_vertical_start_of_block - 0.step(6,3) do |index_of_subblock| - yield(index_of_subblock) - end + 0.step(6,3) {|index_of_subblock| yield(index_of_subblock)} end def loop_in_subblock - 3.times do |index_line_of_block| - yield(index_line_of_block) - end + 3.times {|index_line_of_block| yield(index_line_of_block)} end alias :each_horizontal_start_of_block :loop_in_subblock alias :each_line_in_block :loop_in_subblock From 111103efc7b473fb6e883ae030ea836eaef0802a Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 19:18:24 -0400 Subject: [PATCH 23/25] remove old files --- invalid_block_incomplete.sudoku | 11 ----------- invalid_column_complete.sudoku | 11 ----------- invalid_line_complete.sudoku | 11 ----------- 3 files changed, 33 deletions(-) delete mode 100644 invalid_block_incomplete.sudoku delete mode 100644 invalid_column_complete.sudoku delete mode 100644 invalid_line_complete.sudoku diff --git a/invalid_block_incomplete.sudoku b/invalid_block_incomplete.sudoku deleted file mode 100644 index 8ed3bd8..0000000 --- a/invalid_block_incomplete.sudoku +++ /dev/null @@ -1,11 +0,0 @@ -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 . |2 6 8 |9 1 4 -2 4 1 |5 9 3 |7 8 6 -------+------+------ -4 3 5 |9 8 1 |6 7 . -6 1 7 |4 2 5 |8 9 3 -5 9 8 |7 3 6 |2 4 1 diff --git a/invalid_column_complete.sudoku b/invalid_column_complete.sudoku deleted file mode 100644 index ba5fb31..0000000 --- a/invalid_column_complete.sudoku +++ /dev/null @@ -1,11 +0,0 @@ -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/invalid_line_complete.sudoku b/invalid_line_complete.sudoku deleted file mode 100644 index 6500ea7..0000000 --- a/invalid_line_complete.sudoku +++ /dev/null @@ -1,11 +0,0 @@ -8 5 9 |6 5 2 |4 3 7 -7 2 3 |8 1 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 From fb49b90d793723c32f459b79f2f3488642dd657a Mon Sep 17 00:00:00 2001 From: GCorbel Date: Thu, 17 Oct 2013 19:47:07 -0400 Subject: [PATCH 24/25] add details about errors --- lib/sudoku_reader.rb | 12 ++++++++---- lib/sudoku_validator.rb | 11 +++++++---- spec/sudoku_validator_spec.rb | 9 ++++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index 73d98c7..c82e962 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -14,19 +14,23 @@ def lines end def each_line - lines.each {|line| yield(line)} + lines.each_with_index {|line, index| yield(line, index)} end def each_value_by_line - each_line {|line| line.each{|value| yield(line, value)}} + each_line {|line, index| line.each{|value| yield(line, value, index)}} end def each_value_by_column - columns.each {|column| column.each{|value| yield(column, value)}} + columns.each_with_index do |column, index| + column.each{|value| yield(column, value, index)} + end end def each_value_by_block - blocks.each {|block| block.each{|value| yield(block, value)}} + blocks.each_with_index do |block, index| + block.each{|value| yield(block, value, index)} + end end def columns diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 8312911..cbb92b2 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -3,6 +3,7 @@ class SudokuValidator def initialize(reader) @reader = reader + @errors = [] end def complete? @@ -18,7 +19,7 @@ def message if valid? "This sudoku is valid#{complete_message}." else - "This sudoku is invalid." + "This sudoku is invalid." + @errors.join end end @@ -40,9 +41,11 @@ def blocks_valid? end def check_validity_for(type) - reader.send("each_value_by_#{type}") do |row, value| - return false if row.count(value) > 1 && value != 0 + reader.send("each_value_by_#{type}") do |row, value, index| + if row.count(value) > 1 && value != 0 + @errors << "\n - There is multiple #{value} in #{type} #{index + 1}." + end end - return true + @errors.empty? end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index f375a9f..2d8333a 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -62,7 +62,14 @@ context "when the sudoku is invalid" do it "say than the sudoku is invalid" do ['invalid_complete.sudoku', 'invalid_incomplete.sudoku'].each do |file| - expect(validator_for(file).message).to eq "This sudoku is invalid." + expect(validator_for(file).message).to match "This sudoku is invalid." + end + end + + context "when the sudoku is invalid du to lines" do + it "say than there is an error in line" do + file = 'invalid_line.sudoku' + expect(validator_for(file).message).to match "There is multiple 5 in line 1." end end end From b46afb7e3234d2b01302e0f74c6223b54e7c4625 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Fri, 18 Oct 2013 15:22:29 -0400 Subject: [PATCH 25/25] use a calculation instead of loop --- lib/sudoku_reader.rb | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/sudoku_reader.rb b/lib/sudoku_reader.rb index c82e962..f2d980b 100644 --- a/lib/sudoku_reader.rb +++ b/lib/sudoku_reader.rb @@ -46,29 +46,32 @@ def blocks private def fill_blocks - each_vertical_start_of_block do |i| - each_horizontal_start_of_block do |j| - each_line_in_block {|k| get_line_of_block(i, j, k)} - end + each_block do |block_number| + line, column = block_start(block_number) + each_line_in_block {|k| get_line_of_block(line, column, k)} end end + def block_start(block_number) + row = ((block_number) / 3) * 3 + col = ((block_number) % 3) * 3 + [row,col] + end + def get_line_of_block(vertical_start, horizontal_start, line_block) - line = lines[horizontal_start * 3 + line_block] + line = lines[horizontal_start + line_block] line_in_block = line.drop(vertical_start).first(3) - index_of_block = vertical_start + horizontal_start + index_of_block = vertical_start + horizontal_start/3 @blocks[index_of_block] += line_in_block end - def each_vertical_start_of_block - 0.step(6,3) {|index_of_subblock| yield(index_of_subblock)} + def each_block + 9.times {|block_number| yield(block_number)} end - def loop_in_subblock + def each_line_in_block 3.times {|index_line_of_block| yield(index_line_of_block)} end - alias :each_horizontal_start_of_block :loop_in_subblock - alias :each_line_in_block :loop_in_subblock def init_empty_blocks 9.times { @blocks << [] }