From 19af7a11a80db5e3279d14c1ac1243c79f4ea40a Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sat, 12 Oct 2013 08:47:46 -0700 Subject: [PATCH 01/28] Initial configuration / setup... Basic spec file working with no tests. --- lib/.sudoku_validator.rb.swp | Bin 0 -> 12288 bytes lib/sudoku_validator.rb | 2 ++ spec/.sudoku_validator_spec.rb.swp | Bin 0 -> 12288 bytes spec/sudoku_validator_spec.rb | 8 ++++++++ 4 files changed, 10 insertions(+) create mode 100644 lib/.sudoku_validator.rb.swp create mode 100644 lib/sudoku_validator.rb create mode 100644 spec/.sudoku_validator_spec.rb.swp create mode 100644 spec/sudoku_validator_spec.rb diff --git a/lib/.sudoku_validator.rb.swp b/lib/.sudoku_validator.rb.swp new file mode 100644 index 0000000000000000000000000000000000000000..074ed898fda4c55adb9a9e537647c1f4e30461c1 GIT binary patch literal 12288 zcmeI&KTg9i7>D7now`(1?FCYpoAeJ-dw?=9AfX~EF(D@oDAY=-Cg}#;jT70bRK{r0tmPT%Hmt3m6zWk(3q*9-s^iNC-qF7D5tVks*qU^RWRh!T=Ks55Q|6 zk@w*ewF^}Wjv7)b4qPvWZ=A@o!jpN~2 z|G-OZ9Jbd!O&9csT>7!qCcX8uLfiWyD8t0)Ft^UnCLGU=2KA`tqSkF-5&{rdBv9nz zy`wc6^!Iyp$?nd!+S6KmY;|fB*y_009U<;2#R)lMX%0xmKoUlWTtyonP&= ziv|J^fB*y_009U<00Izz00bZafh80OHPOvF(TimL|9^J>ucZGi`6>A!`7Ze;`6}7e zF5y|RWe7k30uX=z1Rwwb2tWV=5P-m66yQ`Y=StO$l8{ftW9wLHOPaITnTXXz^MHOd edp}>#k>iKLI1U^qVQxxRUC;9q6V1J=@6r#tS5-g& literal 0 HcmV?d00001 diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb new file mode 100644 index 0000000..8ce5acd --- /dev/null +++ b/spec/sudoku_validator_spec.rb @@ -0,0 +1,8 @@ +require_relative '../lib/sudoku_validator' + +describe SudokuValidator do + before do + + end + +end From e6974ebdfb53a4ed7c1c62015f904eb660db31db Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sat, 12 Oct 2013 09:24:32 -0700 Subject: [PATCH 02/28] SudokuBoard returns a single element... Add .gitignore and get rid of swap files Add SudokuBoard class and implement access to a single element. --- .gitignore | 1 + lib/sudoku_board.rb | 8 ++++++++ spec/.sudoku_validator_spec.rb.swp | Bin 12288 -> 0 bytes spec/sudoku_validator_spec.rb | 12 ++++++++++++ 4 files changed, 21 insertions(+) create mode 100644 .gitignore create mode 100644 lib/sudoku_board.rb delete mode 100644 spec/.sudoku_validator_spec.rb.swp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbec55f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.sw[op] diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb new file mode 100644 index 0000000..424b170 --- /dev/null +++ b/lib/sudoku_board.rb @@ -0,0 +1,8 @@ +class SudokuBoard + def initialize(game_file) + @board = [[8]] + end + def [] (row, col) + @board[row-1][col-1] + end +end diff --git a/spec/.sudoku_validator_spec.rb.swp b/spec/.sudoku_validator_spec.rb.swp deleted file mode 100644 index b5ca3522679b99ad976ca42b51377e7deba69447..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&y-ve05C`xp6AJ>t3m6zWk(3q*9-s^iNC-qF7D5tVks*qU^RWRh!T=Ks55Q|6 zk@w*ewF^}Wjv7)b4qPvWZ=A@o!jpN~2 z|G-OZ9Jbd!O&9csT>7!qCcX8uLfiWyD8t0)Ft^UnCLGU=2KA`tqSkF-5&{rdBv9nz zy`wc6^!Iyp$?nd!+S6KmY;|fB*y_009U<;2#R)lMX%0xmKoUlWTtyonP&= ziv|J^fB*y_009U<00Izz00bZafh80OHPOvF(TimL|9^J>ucZGi`6>A!`7Ze;`6}7e zF5y|RWe7k30uX=z1Rwwb2tWV=5P-m66yQ`Y=StO$l8{ftW9wLHOPaITnTXXz^MHOd edp}>#k>iKLI1U^qVQxxRUC;9q6V1J=@6r#tS5-g& diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 8ce5acd..5ae0835 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -1,8 +1,20 @@ require_relative '../lib/sudoku_validator' +require_relative '../lib/sudoku_board' describe SudokuValidator do before do end + describe SudokuBoard do + + before do + + end + it "reads the first character of the sudoku file" do + board = SudokuBoard.new ("../valid_complete.sudoku") + expect(board[1,1]).to eql 8 + end + + end end From 741dee444c488e5fa7dd62e064fb238272dbf293 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sat, 12 Oct 2013 20:48:59 -0700 Subject: [PATCH 03/28] Create Sudoku board class & test... New class reads input file and creates game board; Methods to return a specific element, row, or column. --- lib/sudoku_board.rb | 28 +++++++++++++++++++++++++++- spec/sudoku_validator_spec.rb | 11 ++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 424b170..440d2a9 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -1,8 +1,34 @@ class SudokuBoard + #attr_accessor :row + #attr_reader :col, [] + def initialize(game_file) - @board = [[8]] + @board = [] + File.readlines(game_file).each do |line| + row = convert_line_to_row(line) + @board << row unless row.nil? + end + @board end def [] (row, col) @board[row-1][col-1] end + def row(row) + @board[row-1] + end + def row= (row) + end + def col(col) + column = [] + @board.each { |row| column << row[col-1] } + column + end + def convert_line_to_row(line) + row = [] + line.chomp!.delete!('-+| ') + return nil if line.empty? + line.tr!('[1-9].','[1-9]0') + line.each_char.map { |c| row << c.to_i } + row + end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 5ae0835..05a381a 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -8,11 +8,16 @@ describe SudokuBoard do before do - + @game = SudokuBoard.new("valid_complete.sudoku") end it "reads the first character of the sudoku file" do - board = SudokuBoard.new ("../valid_complete.sudoku") - expect(board[1,1]).to eql 8 + expect(@game[1,1]).to eql 8 + end + it "reads the first row of the sudoku file" do + expect(@game.row(1)).to eql [8,5,9,6,1,2,4,3,7] + end + it "reads the first column of the sudoku file" do + expect(@game.col(1)).to eql [8,7,1,9,3,2,4,6,5] end end From fbe316d3da8304f2f81fbc8cc794a9fa89acee5f Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sat, 12 Oct 2013 21:44:52 -0700 Subject: [PATCH 04/28] Added sub-grid retrieval by number position --- lib/sudoku_board.rb | 38 ++++++++++++++++++++++++++++++----- spec/sudoku_validator_spec.rb | 16 +++++++++++---- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 440d2a9..8c2e471 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -5,8 +5,8 @@ class SudokuBoard def initialize(game_file) @board = [] File.readlines(game_file).each do |line| - row = convert_line_to_row(line) - @board << row unless row.nil? + row = convert_line_to_row(line) + @board << row unless row.nil? end @board end @@ -16,19 +16,47 @@ def [] (row, col) def row(row) @board[row-1] end - def row= (row) - end def col(col) column = [] @board.each { |row| column << row[col-1] } column end + def sub_grid(number) + # SubGrids are numbered 1-9 like this: + # 1,2,3 + # 4,5,6 + # 7,8.9 + row, col = sub_grid_start(number) + s_grid = [] + 3.times do + 3.times do + s_grid << self[row,col] + col += 1 + end + row += 1 + col -= 3 + end + s_grid + end def convert_line_to_row(line) row = [] line.chomp!.delete!('-+| ') return nil if line.empty? - line.tr!('[1-9].','[1-9]0') + line.tr!('.','0') line.each_char.map { |c| row << c.to_i } row end + def sub_grid_start(number) + row = case + when number <=3 then 1 + when number <=6 then 4 + when number <=9 then 7 + end + col = case + when number %3 == 1 then 1 + when number %3 == 2 then 4 + when number %3 == 3 then 7 + end + [row,col] + end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 05a381a..d3f364e 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -10,16 +10,24 @@ before do @game = SudokuBoard.new("valid_complete.sudoku") end - it "reads the first character of the sudoku file" do + it "returns the first character of the sudoku file" do expect(@game[1,1]).to eql 8 end - it "reads the first row of the sudoku file" do + it "returns an arbitrary element from the board" do + expect(@game[4,5]).to eql 4 + end + it "returns the first row of the sudoku file" do expect(@game.row(1)).to eql [8,5,9,6,1,2,4,3,7] end - it "reads the first column of the sudoku file" do + it "returns the first column of the sudoku file" do expect(@game.col(1)).to eql [8,7,1,9,3,2,4,6,5] end - + it "returns a 3x3 sub-grid as an array" do + expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] + end + it "returns a middle 3x3 sub-grid" do + expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] + end end end From 26eb987b22cb3f467a11586641b33f70ec5c3d1e Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sat, 12 Oct 2013 21:56:25 -0700 Subject: [PATCH 05/28] Added tests for incomplete games --- spec/sudoku_validator_spec.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index d3f364e..1b06a49 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -3,7 +3,7 @@ describe SudokuValidator do before do - + end describe SudokuBoard do @@ -28,6 +28,22 @@ it "returns a middle 3x3 sub-grid" do expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] end + describe "SudokuBoard for incomplete games" do + before do + @game = SudokuBoard.new("invalid_incomplete.sudoku") + end + it "returns zero for an empty position" do + expect(@game[2,4]).to eql 0 + end + it "returns the expected row" do + expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] + end + it "returns the expected column" do + expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] + end + it "returns the expected sub-grid" do + expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] + end + end end - end From 72cb7a4e84607376a6a6df383846c2a3fec39234 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sun, 13 Oct 2013 08:50:26 -0700 Subject: [PATCH 06/28] Minor example code re-oganization for clarity --- lib/sudoku_board.rb | 3 +-- spec/sudoku_validator_spec.rb | 37 ++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 8c2e471..66f8978 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -33,8 +33,7 @@ def sub_grid(number) s_grid << self[row,col] col += 1 end - row += 1 - col -= 3 + row += 1; col -= 3 end s_grid end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 1b06a49..361f3d4 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -5,8 +5,9 @@ before do end - describe SudokuBoard do - +end +describe SudokuBoard do + describe "complete games" do before do @game = SudokuBoard.new("valid_complete.sudoku") end @@ -28,22 +29,22 @@ it "returns a middle 3x3 sub-grid" do expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] end - describe "SudokuBoard for incomplete games" do - before do - @game = SudokuBoard.new("invalid_incomplete.sudoku") - end - it "returns zero for an empty position" do - expect(@game[2,4]).to eql 0 - end - it "returns the expected row" do - expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] - end - it "returns the expected column" do - expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] - end - it "returns the expected sub-grid" do - expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] - end + end + describe "incomplete games" do + before do + @game = SudokuBoard.new("invalid_incomplete.sudoku") + end + it "returns zero for an empty position" do + expect(@game[2,4]).to eql 0 + end + it "returns the expected row" do + expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] + end + it "returns the expected column" do + expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] + end + it "returns the expected sub-grid" do + expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] end end end From 2bfb0d623a146169967ea73208589b7fbd01824b Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sun, 13 Oct 2013 09:04:14 -0700 Subject: [PATCH 07/28] Specs recognize the CLI program with dummy output --- spec/sudoku_validator_spec.rb | 6 ++++++ sudoku_validator | 3 +++ 2 files changed, 9 insertions(+) create mode 100755 sudoku_validator diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 361f3d4..a8af2ce 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -5,6 +5,12 @@ before do end + describe "valid games" do + it "correctly recognizes a valid, complete game" do + result = %x{"./sudoku_validator" "./valid_complete.sudoku"} + expect(result).to eq "This sudoku is valid.\n" + end + end end describe SudokuBoard do describe "complete games" do diff --git a/sudoku_validator b/sudoku_validator new file mode 100755 index 0000000..9b20113 --- /dev/null +++ b/sudoku_validator @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +puts "This sudoku is valid." From aa56284597714e0e53f4b722b6b278aa7c44d834 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sun, 13 Oct 2013 09:47:06 -0700 Subject: [PATCH 08/28] Validator correctly recognizes complete/incomplete games... Expose game board for analysis; test for missing elements (zeros); Set up initial structure for testing validity. --- lib/.sudoku_validator.rb.swp | Bin 12288 -> 0 bytes lib/sudoku_board.rb | 1 + lib/sudoku_validator.rb | 20 ++++++++++++++++++++ spec/sudoku_validator_spec.rb | 4 ++++ sudoku_validator | 9 ++++++++- 5 files changed, 33 insertions(+), 1 deletion(-) delete mode 100644 lib/.sudoku_validator.rb.swp diff --git a/lib/.sudoku_validator.rb.swp b/lib/.sudoku_validator.rb.swp deleted file mode 100644 index 074ed898fda4c55adb9a9e537647c1f4e30461c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&KTg9i7>D7now`(1?FCYpoAeJ-dw?=9AfX~EF(D@oDAY=-Cg}#;jT70bRK{r0tmPT%Hm Date: Sun, 13 Oct 2013 09:51:27 -0700 Subject: [PATCH 09/28] Validator correctly recognizes complete games with proper completion status --- lib/sudoku_validator.rb | 12 +++++++----- sudoku_validator | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 2f0346a..3963ba6 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -8,11 +8,13 @@ def initialize(game_file) def analyze @game = SudokuBoard.new @game_file - if self.missing_data? - status = 'incomplete' - else - status = 'complete' - end + status = check_game_status + validity = 'valid' + [validity, status] + end + + def check_game_status + self.missing_data? ? 'incomplete' : 'complete' end def missing_data? diff --git a/sudoku_validator b/sudoku_validator index 225d96f..220ae9a 100755 --- a/sudoku_validator +++ b/sudoku_validator @@ -4,7 +4,7 @@ require_relative 'lib/sudoku_validator' @validator = SudokuValidator.new(ARGV[0]) validity, status = @validator.analyze output = "" -output = "This game is #{validity}" +output = "This sudoku is #{validity}" output += ", but incomplete" if status == 'incomplete' output += "." puts output From b52f59515ab4bf4541f95b2bd0de766a026b2fab Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sun, 13 Oct 2013 09:53:33 -0700 Subject: [PATCH 10/28] Minor refactoring to extract check_game_validity method --- lib/sudoku_validator.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 3963ba6..5f21a05 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -9,7 +9,7 @@ def initialize(game_file) def analyze @game = SudokuBoard.new @game_file status = check_game_status - validity = 'valid' + validity = check_game_validity [validity, status] end @@ -17,6 +17,10 @@ def check_game_status self.missing_data? ? 'incomplete' : 'complete' end + def check_game_validity + 'valid' + end + def missing_data? !(game.board.flatten.index( 0 )).nil? end From 9ef05da045a9a09c3534c56718d435d03ce0c7a5 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Sun, 13 Oct 2013 22:02:55 -0700 Subject: [PATCH 11/28] Validator correctly identifies status and validity... Now need to display error information. Refactored the sub_grid_start computation of row/col. --- lib/sudoku_board.rb | 19 +++++++------------ lib/sudoku_validator.rb | 33 ++++++++++++++++++++++++++++++++- spec/sudoku_validator_spec.rb | 13 +++++++++++-- sudoku_validator | 2 +- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index be74b13..326b82b 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -9,19 +9,22 @@ def initialize(game_file) row = convert_line_to_row(line) @board << row unless row.nil? end - @board end + def [] (row, col) @board[row-1][col-1] end + def row(row) @board[row-1] end + def col(col) column = [] @board.each { |row| column << row[col-1] } column end + def sub_grid(number) # SubGrids are numbered 1-9 like this: # 1,2,3 @@ -46,17 +49,9 @@ def convert_line_to_row(line) line.each_char.map { |c| row << c.to_i } row end - def sub_grid_start(number) - row = case - when number <=3 then 1 - when number <=6 then 4 - when number <=9 then 7 - end - col = case - when number %3 == 1 then 1 - when number %3 == 2 then 4 - when number %3 == 3 then 7 - end + def sub_grid_start(sub_grid) + row = ((sub_grid-1)/3)*3 + 1 + col = ((sub_grid-1)%3)*3 + 1 [row,col] end end diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5f21a05..5d93dea 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -18,11 +18,42 @@ def check_game_status end def check_game_validity - 'valid' + rows_valid = check_row_validity + cols_valid = check_col_validity + subgrids_valid = check_subgrid_validity + (rows_valid && cols_valid && subgrids_valid) ? 'valid' : 'invalid' end def missing_data? !(game.board.flatten.index( 0 )).nil? end + def check_row_validity + rows_valid = true + (1..9).each do |row| + rows_valid &&= valid?(@game.row(row)) + end + rows_valid + end + + def check_col_validity + cols_valid = true + (1..9).each do |col| + cols_valid &&= valid?(@game.col(col)) + end + cols_valid + end + + def check_subgrid_validity + subgrids_valid = true + (1..9).each do |subgrid| + subgrids_valid &&= valid?(@game.sub_grid(subgrid)) + end + subgrids_valid + end + + def valid?(ary) + tmp = ary.map { |e| e if e !=0}.compact + tmp.uniq.size == tmp.size + end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index b412755..0ef8e38 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -8,11 +8,17 @@ describe "valid games" do it "correctly recognizes a valid, complete game" do result = %x{"./sudoku_validator" "./valid_complete.sudoku"} - expect(result).to eq "This sudoku is valid.\n" + expect(result).to eq "This sudoku is valid, and complete.\n" end it "recognizes a valid, incomplete game" do result = `./sudoku_validator ./valid_incomplete.sudoku` - expect(result).to eq "This sudoku is valid, but incomplete.\n" + expect(result).to eq "This sudoku is valid, and incomplete.\n" + end + end + describe "invalid games" do + it "recognizes an invalid, complete game" do + result = `./sudoku_validator ./invalid_complete.sudoku` + expect(result).to eq "This sudoku is invalid, and complete.\n" end end end @@ -39,6 +45,9 @@ it "returns a middle 3x3 sub-grid" do expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] end + it "successfully returns the last sub-grid" do + expect(@game.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] + end end describe "incomplete games" do before do diff --git a/sudoku_validator b/sudoku_validator index 220ae9a..07e1c13 100755 --- a/sudoku_validator +++ b/sudoku_validator @@ -5,6 +5,6 @@ require_relative 'lib/sudoku_validator' validity, status = @validator.analyze output = "" output = "This sudoku is #{validity}" -output += ", but incomplete" if status == 'incomplete' +output += ", and #{status}" output += "." puts output From 91dd60049bcaac0c4a74811f77bcfa0bfe3165f6 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 06:13:10 -0700 Subject: [PATCH 12/28] First specs for error reports working... Modified SudokuValidator methods to return error values and convert to strings for reporting CLI program not printing those results yet have some duplication to be taken care of before that step. --- lib/sudoku_board.rb | 4 +++- lib/sudoku_validator.rb | 35 ++++++++++++++++++++++++++++------- spec/sudoku_validator_spec.rb | 20 ++++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 326b82b..6b89255 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -41,14 +41,16 @@ def sub_grid(number) end s_grid end + def convert_line_to_row(line) - row = [] line.chomp!.delete!('-+| ') return nil if line.empty? line.tr!('.','0') + row = [] line.each_char.map { |c| row << c.to_i } row end + def sub_grid_start(sub_grid) row = ((sub_grid-1)/3)*3 + 1 col = ((sub_grid-1)%3)*3 + 1 diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5d93dea..7ef30e5 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -1,13 +1,15 @@ require_relative './sudoku_board' class SudokuValidator - attr_reader :game + attr_reader :game, :errors + def initialize(game_file) @game_file = game_file + @game = SudokuBoard.new @game_file + @errors = [] end def analyze - @game = SudokuBoard.new @game_file status = check_game_status validity = check_game_validity [validity, status] @@ -25,13 +27,15 @@ def check_game_validity end def missing_data? - !(game.board.flatten.index( 0 )).nil? + !(@game.board.flatten.index( 0 )).nil? end def check_row_validity rows_valid = true (1..9).each do |row| - rows_valid &&= valid?(@game.row(row)) + valid,error = valid?(@game.row(row)) + rows_valid &&= valid + error.each { |e| @errors << "#{e} is repeated in row #{row}" } end rows_valid end @@ -39,7 +43,9 @@ def check_row_validity def check_col_validity cols_valid = true (1..9).each do |col| - cols_valid &&= valid?(@game.col(col)) + valid,error = valid?(@game.col(col)) + cols_valid &&= valid + error.each { |e| @errors << "#{e} is repeated in col #{col}" } end cols_valid end @@ -47,13 +53,28 @@ def check_col_validity def check_subgrid_validity subgrids_valid = true (1..9).each do |subgrid| - subgrids_valid &&= valid?(@game.sub_grid(subgrid)) + valid,error = valid?(@game.sub_grid(subgrid)) + subgrids_valid &&= valid + error.each { |e| @errors << "#{e} is repeated is subgrid #{subgrid}" } end subgrids_valid end def valid?(ary) tmp = ary.map { |e| e if e !=0}.compact - tmp.uniq.size == tmp.size + valid = tmp.uniq.size == tmp.size + error = [] + error = report_errors(ary) if !valid + [valid,error] + end + + def report_errors (ary) + tmp = ary + error = [] + while tmp.size > 0 do + item = tmp.shift + error << item if tmp.include? item + end + error end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 0ef8e38..20415f7 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -21,6 +21,26 @@ expect(result).to eq "This sudoku is invalid, and complete.\n" end end + describe "error handling" do + before do + @game = SudokuValidator.new "./invalid_complete.sudoku" + @element = [1,2,3,2,5,6,7,8,9] + end + it "identifies correct element in #report_errors" do + expect(@game.report_errors @element).to eql [2] + end + it "returns errors in #valid?" do + expect(@game.valid?(@element)).to eq [false, [2]] + end + it "returns empty error array in #vaid? if no errors" do + @element[3]=4 + expect(@game.valid?(@element)).to eq [true, []] + end + it "returns the descriptive error string" do + @game.analyze + @game.errors.should include "2 is repeated in col 6" + end + end end describe SudokuBoard do describe "complete games" do From 6b45e1b0d8dc8193e7dc318af750efd10633b25a Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 06:15:58 -0700 Subject: [PATCH 13/28] Refactor: rename report_errors to identify_errors --- lib/sudoku_validator.rb | 4 ++-- spec/sudoku_validator_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 7ef30e5..74508ff 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -64,11 +64,11 @@ def valid?(ary) tmp = ary.map { |e| e if e !=0}.compact valid = tmp.uniq.size == tmp.size error = [] - error = report_errors(ary) if !valid + error = identify_errors(ary) if !valid [valid,error] end - def report_errors (ary) + def identify_errors (ary) tmp = ary error = [] while tmp.size > 0 do diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 20415f7..2ac114d 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -26,8 +26,8 @@ @game = SudokuValidator.new "./invalid_complete.sudoku" @element = [1,2,3,2,5,6,7,8,9] end - it "identifies correct element in #report_errors" do - expect(@game.report_errors @element).to eql [2] + it "identifies correct element in #identify_errors" do + expect(@game.identify_errors @element).to eql [2] end it "returns errors in #valid?" do expect(@game.valid?(@element)).to eq [false, [2]] From 13f5728acf1c6fe08ed26a69e059a497402cb1c3 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 07:49:48 -0700 Subject: [PATCH 14/28] Refactor validity-checking to remove duplication... report_errors now a separate method to generate error strings. --- lib/sudoku_validator.rb | 12 +++++++++--- spec/sudoku_validator_spec.rb | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 74508ff..19de016 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -45,7 +45,8 @@ def check_col_validity (1..9).each do |col| valid,error = valid?(@game.col(col)) cols_valid &&= valid - error.each { |e| @errors << "#{e} is repeated in col #{col}" } + #error.each { |e| @errors << "#{e} is repeated in col #{col}" } + report_errors(error,'col',col) end cols_valid end @@ -55,7 +56,8 @@ def check_subgrid_validity (1..9).each do |subgrid| valid,error = valid?(@game.sub_grid(subgrid)) subgrids_valid &&= valid - error.each { |e| @errors << "#{e} is repeated is subgrid #{subgrid}" } + report_errors(error,'sub-grid',subgrid) + #error.each { |e| @errors << "#{e} is repeated in sub-grid #{subgrid}" } end subgrids_valid end @@ -69,7 +71,7 @@ def valid?(ary) end def identify_errors (ary) - tmp = ary + tmp = ary.clone error = [] while tmp.size > 0 do item = tmp.shift @@ -77,4 +79,8 @@ def identify_errors (ary) end error end + + def report_errors (ary,where,item) + ary.each { |e| @errors << "#{e} is repeated in #{where} #{item}" } + end end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 2ac114d..7d972ed 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -36,10 +36,20 @@ @element[3]=4 expect(@game.valid?(@element)).to eq [true, []] end - it "returns the descriptive error string" do + it "returns the descriptive error string for col errors" do @game.analyze @game.errors.should include "2 is repeated in col 6" end + it "returns the descriptive error string for row errors" do + @game.game.board[0][0] = 7 + @game.analyze + @game.errors.should include "7 is repeated in row 1" + end + it "returns the descrptive error string for sub-grid errors" do + @game.game.board[0][0] = 7 + @game.analyze + @game.errors.should include "7 is repeated in sub-grid 1" + end end end describe SudokuBoard do @@ -68,6 +78,9 @@ it "successfully returns the last sub-grid" do expect(@game.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] end + it "successfully returns the first sub-grid" do + expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] + end end describe "incomplete games" do before do From 3cc1a0faeb40728ac798cb40afdb1ae6e70bb173 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 07:51:55 -0700 Subject: [PATCH 15/28] Refactor: clean up report_errors usage --- lib/sudoku_validator.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 19de016..5f95099 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -35,7 +35,7 @@ def check_row_validity (1..9).each do |row| valid,error = valid?(@game.row(row)) rows_valid &&= valid - error.each { |e| @errors << "#{e} is repeated in row #{row}" } + report_errors(error, 'row',row) end rows_valid end @@ -45,7 +45,6 @@ def check_col_validity (1..9).each do |col| valid,error = valid?(@game.col(col)) cols_valid &&= valid - #error.each { |e| @errors << "#{e} is repeated in col #{col}" } report_errors(error,'col',col) end cols_valid @@ -57,7 +56,6 @@ def check_subgrid_validity valid,error = valid?(@game.sub_grid(subgrid)) subgrids_valid &&= valid report_errors(error,'sub-grid',subgrid) - #error.each { |e| @errors << "#{e} is repeated in sub-grid #{subgrid}" } end subgrids_valid end From 236592108908ad69de9eb7d3879087c82091f02f Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 08:01:46 -0700 Subject: [PATCH 16/28] Complete refactoring... Duplication removed from check__validity methods. --- lib/sudoku_validator.rb | 32 ++++++++++++-------------------- spec/sudoku_validator_spec.rb | 2 +- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 5f95099..b93743c 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -31,33 +31,25 @@ def missing_data? end def check_row_validity - rows_valid = true - (1..9).each do |row| - valid,error = valid?(@game.row(row)) - rows_valid &&= valid - report_errors(error, 'row',row) - end - rows_valid + valid_element?('row') end def check_col_validity - cols_valid = true - (1..9).each do |col| - valid,error = valid?(@game.col(col)) - cols_valid &&= valid - report_errors(error,'col',col) - end - cols_valid + valid_element?('col') end def check_subgrid_validity - subgrids_valid = true - (1..9).each do |subgrid| - valid,error = valid?(@game.sub_grid(subgrid)) - subgrids_valid &&= valid - report_errors(error,'sub-grid',subgrid) + valid_element?('sub_grid') + end + + def valid_element?(element) + item_valid = true + (1..9).each do |item| + valid, error = valid?(@game.__send__(element.to_sym,item)) + item_valid &&= valid + report_errors(error, element.to_s, item) end - subgrids_valid + item_valid end def valid?(ary) diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 7d972ed..0768698 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -48,7 +48,7 @@ it "returns the descrptive error string for sub-grid errors" do @game.game.board[0][0] = 7 @game.analyze - @game.errors.should include "7 is repeated in sub-grid 1" + @game.errors.should include "7 is repeated in sub_grid 1" end end end From 5371e29cea6dccb2a9e367c9dac15fc682bba7e7 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 08:04:32 -0700 Subject: [PATCH 17/28] Minor refactoring... 1. Remove unnecessary to_s conversion in valid_element? method 2. Change invalid sudoku result spec to test for include, not eq, so that we can add error descriptions. --- lib/sudoku_validator.rb | 2 +- spec/sudoku_validator_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index b93743c..c691023 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -47,7 +47,7 @@ def valid_element?(element) (1..9).each do |item| valid, error = valid?(@game.__send__(element.to_sym,item)) item_valid &&= valid - report_errors(error, element.to_s, item) + report_errors(error, element, item) end item_valid end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 0768698..ef98dd9 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -18,7 +18,7 @@ describe "invalid games" do it "recognizes an invalid, complete game" do result = `./sudoku_validator ./invalid_complete.sudoku` - expect(result).to eq "This sudoku is invalid, and complete.\n" + expect(result).to include "This sudoku is invalid, and complete.\n" end end describe "error handling" do From e5625b032a6200af29565aa348ce931af29c4459 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 08:08:24 -0700 Subject: [PATCH 18/28] Added error output... Works for invalid/complete sudokus; next is incomplete sudokus. --- spec/sudoku_validator_spec.rb | 1 + sudoku_validator | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index ef98dd9..46c6bdf 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -19,6 +19,7 @@ it "recognizes an invalid, complete game" do result = `./sudoku_validator ./invalid_complete.sudoku` expect(result).to include "This sudoku is invalid, and complete.\n" + expect(result).to include "2 is repeated in col 6" end end describe "error handling" do diff --git a/sudoku_validator b/sudoku_validator index 07e1c13..0749a7f 100755 --- a/sudoku_validator +++ b/sudoku_validator @@ -8,3 +8,4 @@ output = "This sudoku is #{validity}" output += ", and #{status}" output += "." puts output +@validator.errors.each { |err| puts err } From 6d7bca33a385a3a9e8c99d2209a67f7583c88f8e Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Mon, 14 Oct 2013 08:26:00 -0700 Subject: [PATCH 19/28] Properly report errors for incomplete sudoku... Ignore missing (zero) elements in board. --- lib/sudoku_validator.rb | 2 +- spec/sudoku_validator_spec.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index c691023..542da06 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -56,7 +56,7 @@ def valid?(ary) tmp = ary.map { |e| e if e !=0}.compact valid = tmp.uniq.size == tmp.size error = [] - error = identify_errors(ary) if !valid + error = identify_errors(tmp) if !valid [valid,error] end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 46c6bdf..28a0e29 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -51,6 +51,12 @@ @game.analyze @game.errors.should include "7 is repeated in sub_grid 1" end + it "ignores missing (zero) elements for incomplete sudokus" do + @game.game.board[0][0] = 0 ; @game.game.board[0][6] = 0 + @game.game.board[0][3] = 0 + @game.analyze + @game.errors.should_not include "0 is repeated in row 1" + end end end describe SudokuBoard do From 6b0b03e5f831981a943ddb10638213a2868dfddb Mon Sep 17 00:00:00 2001 From: JESii Date: Wed, 16 Oct 2013 17:53:48 -0700 Subject: [PATCH 20/28] Refactor spec/examples... Remove empty before block Add spacing between describe/it blocks Split specs for SudokuBoard and SudokuValidator into two files. --- spec/sudoku_board_spec.rb | 63 +++++++++++++++++++++++++++++++++++ spec/sudoku_validator_spec.rb | 63 +++++++---------------------------- 2 files changed, 75 insertions(+), 51 deletions(-) create mode 100644 spec/sudoku_board_spec.rb diff --git a/spec/sudoku_board_spec.rb b/spec/sudoku_board_spec.rb new file mode 100644 index 0000000..1745b59 --- /dev/null +++ b/spec/sudoku_board_spec.rb @@ -0,0 +1,63 @@ +require_relative '../lib/sudoku_validator' +require_relative '../lib/sudoku_board' + +describe SudokuBoard do + describe "complete games" do + before do + @game = SudokuBoard.new("valid_complete.sudoku") + end + + it "returns the first character of the sudoku file" do + expect(@game[1,1]).to eql 8 + end + + it "returns an arbitrary element from the board" do + expect(@game[4,5]).to eql 4 + end + + it "returns the first row of the sudoku file" do + expect(@game.row(1)).to eql [8,5,9,6,1,2,4,3,7] + end + + it "returns the first column of the sudoku file" do + expect(@game.col(1)).to eql [8,7,1,9,3,2,4,6,5] + end + + it "returns a 3x3 sub-grid as an array" do + expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] + end + + it "returns a middle 3x3 sub-grid" do + expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] + end + + it "successfully returns the last sub-grid" do + expect(@game.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] + end + + it "successfully returns the first sub-grid" do + expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] + end + end + describe "incomplete games" do + before do + @game = SudokuBoard.new("invalid_incomplete.sudoku") + end + + it "returns zero for an empty position" do + expect(@game[2,4]).to eql 0 + end + + it "returns the expected row" do + expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] + end + + it "returns the expected column" do + expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] + end + + it "returns the expected sub-grid" do + expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] + end + end +end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 28a0e29..df77bd7 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -2,19 +2,19 @@ require_relative '../lib/sudoku_board' describe SudokuValidator do - before do - end describe "valid games" do it "correctly recognizes a valid, complete game" do result = %x{"./sudoku_validator" "./valid_complete.sudoku"} expect(result).to eq "This sudoku is valid, and complete.\n" end + it "recognizes a valid, incomplete game" do result = `./sudoku_validator ./valid_incomplete.sudoku` expect(result).to eq "This sudoku is valid, and incomplete.\n" end end + describe "invalid games" do it "recognizes an invalid, complete game" do result = `./sudoku_validator ./invalid_complete.sudoku` @@ -22,88 +22,49 @@ expect(result).to include "2 is repeated in col 6" end end + describe "error handling" do before do @game = SudokuValidator.new "./invalid_complete.sudoku" @element = [1,2,3,2,5,6,7,8,9] end + it "identifies correct element in #identify_errors" do expect(@game.identify_errors @element).to eql [2] end + it "returns errors in #valid?" do expect(@game.valid?(@element)).to eq [false, [2]] end + it "returns empty error array in #vaid? if no errors" do @element[3]=4 expect(@game.valid?(@element)).to eq [true, []] end + it "returns the descriptive error string for col errors" do @game.analyze @game.errors.should include "2 is repeated in col 6" end + it "returns the descriptive error string for row errors" do @game.game.board[0][0] = 7 @game.analyze @game.errors.should include "7 is repeated in row 1" end + it "returns the descrptive error string for sub-grid errors" do @game.game.board[0][0] = 7 @game.analyze @game.errors.should include "7 is repeated in sub_grid 1" end + it "ignores missing (zero) elements for incomplete sudokus" do - @game.game.board[0][0] = 0 ; @game.game.board[0][6] = 0 + @game.game.board[0][0] = 0 + @game.game.board[0][6] = 0 @game.game.board[0][3] = 0 @game.analyze @game.errors.should_not include "0 is repeated in row 1" end end end -describe SudokuBoard do - describe "complete games" do - before do - @game = SudokuBoard.new("valid_complete.sudoku") - end - it "returns the first character of the sudoku file" do - expect(@game[1,1]).to eql 8 - end - it "returns an arbitrary element from the board" do - expect(@game[4,5]).to eql 4 - end - it "returns the first row of the sudoku file" do - expect(@game.row(1)).to eql [8,5,9,6,1,2,4,3,7] - end - it "returns the first column of the sudoku file" do - expect(@game.col(1)).to eql [8,7,1,9,3,2,4,6,5] - end - it "returns a 3x3 sub-grid as an array" do - expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] - end - it "returns a middle 3x3 sub-grid" do - expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] - end - it "successfully returns the last sub-grid" do - expect(@game.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] - end - it "successfully returns the first sub-grid" do - expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] - end - end - describe "incomplete games" do - before do - @game = SudokuBoard.new("invalid_incomplete.sudoku") - end - it "returns zero for an empty position" do - expect(@game[2,4]).to eql 0 - end - it "returns the expected row" do - expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] - end - it "returns the expected column" do - expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] - end - it "returns the expected sub-grid" do - expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] - end - end -end From d9c66c1d4fe7e871a2c88e4d4502d0eb026edfdf Mon Sep 17 00:00:00 2001 From: JESii Date: Thu, 17 Oct 2013 03:52:26 -0700 Subject: [PATCH 21/28] Rename 'analyze' => 'validate' method --- lib/sudoku_validator.rb | 2 +- spec/sudoku_validator_spec.rb | 8 ++++---- sudoku_validator | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index 542da06..d63d871 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -9,7 +9,7 @@ def initialize(game_file) @errors = [] end - def analyze + def validate status = check_game_status validity = check_game_validity [validity, status] diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index df77bd7..8c4ced9 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -43,19 +43,19 @@ end it "returns the descriptive error string for col errors" do - @game.analyze + @game.validate @game.errors.should include "2 is repeated in col 6" end it "returns the descriptive error string for row errors" do @game.game.board[0][0] = 7 - @game.analyze + @game.validate @game.errors.should include "7 is repeated in row 1" end it "returns the descrptive error string for sub-grid errors" do @game.game.board[0][0] = 7 - @game.analyze + @game.validate @game.errors.should include "7 is repeated in sub_grid 1" end @@ -63,7 +63,7 @@ @game.game.board[0][0] = 0 @game.game.board[0][6] = 0 @game.game.board[0][3] = 0 - @game.analyze + @game.validate @game.errors.should_not include "0 is repeated in row 1" end end diff --git a/sudoku_validator b/sudoku_validator index 0749a7f..9424d83 100755 --- a/sudoku_validator +++ b/sudoku_validator @@ -2,7 +2,7 @@ require_relative 'lib/sudoku_validator' @validator = SudokuValidator.new(ARGV[0]) -validity, status = @validator.analyze +validity, status = @validator.validate output = "" output = "This sudoku is #{validity}" output += ", and #{status}" From dd8815e3c28676c805a10165e53bb6adc68a3ce3 Mon Sep 17 00:00:00 2001 From: JESii Date: Thu, 17 Oct 2013 04:05:21 -0700 Subject: [PATCH 22/28] Refactoring (part 1)... First part of eliminating Law of Demeter violation (@game.game.board[0][0] constructs). First, reference the SudokuBoard instance as 'board', not 'game'. --- lib/sudoku_validator.rb | 8 ++++---- spec/sudoku_validator_spec.rb | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index d63d871..da00994 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -1,11 +1,11 @@ require_relative './sudoku_board' class SudokuValidator - attr_reader :game, :errors + attr_reader :board, :errors def initialize(game_file) @game_file = game_file - @game = SudokuBoard.new @game_file + @board = SudokuBoard.new @game_file @errors = [] end @@ -27,7 +27,7 @@ def check_game_validity end def missing_data? - !(@game.board.flatten.index( 0 )).nil? + !(@board.board.flatten.index( 0 )).nil? end def check_row_validity @@ -45,7 +45,7 @@ def check_subgrid_validity def valid_element?(element) item_valid = true (1..9).each do |item| - valid, error = valid?(@game.__send__(element.to_sym,item)) + valid, error = valid?(@board.__send__(element.to_sym,item)) item_valid &&= valid report_errors(error, element, item) end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 8c4ced9..1a9a46c 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -48,21 +48,21 @@ end it "returns the descriptive error string for row errors" do - @game.game.board[0][0] = 7 + @game.board.board[0][0] = 7 @game.validate @game.errors.should include "7 is repeated in row 1" end it "returns the descrptive error string for sub-grid errors" do - @game.game.board[0][0] = 7 + @game.board.board[0][0] = 7 @game.validate @game.errors.should include "7 is repeated in sub_grid 1" end it "ignores missing (zero) elements for incomplete sudokus" do - @game.game.board[0][0] = 0 - @game.game.board[0][6] = 0 - @game.game.board[0][3] = 0 + @game.board.board[0][0] = 0 + @game.board.board[0][6] = 0 + @game.board.board[0][3] = 0 @game.validate @game.errors.should_not include "0 is repeated in row 1" end From 209c60e3cd6010520e79ed2e13cffabebaa1aa73 Mon Sep 17 00:00:00 2001 From: JESii Date: Thu, 17 Oct 2013 04:14:56 -0700 Subject: [PATCH 23/28] Refactoring: use symbols in call valid_element() method --- lib/sudoku_board.rb | 4 ++++ lib/sudoku_validator.rb | 14 +++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 6b89255..e3f05ed 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -56,4 +56,8 @@ def sub_grid_start(sub_grid) col = ((sub_grid-1)%3)*3 + 1 [row,col] end + + def missing_data? + !(self.board.flatten.index( 0 )).nil? + end end diff --git a/lib/sudoku_validator.rb b/lib/sudoku_validator.rb index da00994..69b400a 100644 --- a/lib/sudoku_validator.rb +++ b/lib/sudoku_validator.rb @@ -16,7 +16,7 @@ def validate end def check_game_status - self.missing_data? ? 'incomplete' : 'complete' + @board.missing_data? ? 'incomplete' : 'complete' end def check_game_validity @@ -26,26 +26,22 @@ def check_game_validity (rows_valid && cols_valid && subgrids_valid) ? 'valid' : 'invalid' end - def missing_data? - !(@board.board.flatten.index( 0 )).nil? - end - def check_row_validity - valid_element?('row') + valid_element?(:row) end def check_col_validity - valid_element?('col') + valid_element?(:col) end def check_subgrid_validity - valid_element?('sub_grid') + valid_element?(:sub_grid) end def valid_element?(element) item_valid = true (1..9).each do |item| - valid, error = valid?(@board.__send__(element.to_sym,item)) + valid, error = valid?(@board.__send__(element,item)) item_valid &&= valid report_errors(error, element, item) end From 5abb52e6d0fdccdc36486686c9cbeaa267d36ef6 Mon Sep 17 00:00:00 2001 From: JESii Date: Thu, 17 Oct 2013 04:27:05 -0700 Subject: [PATCH 24/28] Refactoring for board access... Add []= method to SudokuBoard for cleaner access to board array, then use that in the specs for modifying the board for tests. This finishes the cleanup of the old @game.board.board[0][0] code. --- lib/sudoku_board.rb | 4 ++++ spec/sudoku_validator_spec.rb | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index e3f05ed..9d479d6 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -15,6 +15,10 @@ def [] (row, col) @board[row-1][col-1] end + def []= (row, col, value) + @board[row-1][col-1] = value + end + def row(row) @board[row-1] end diff --git a/spec/sudoku_validator_spec.rb b/spec/sudoku_validator_spec.rb index 1a9a46c..5faff15 100644 --- a/spec/sudoku_validator_spec.rb +++ b/spec/sudoku_validator_spec.rb @@ -48,21 +48,21 @@ end it "returns the descriptive error string for row errors" do - @game.board.board[0][0] = 7 + @game.board[1,1] = 7 @game.validate @game.errors.should include "7 is repeated in row 1" end it "returns the descrptive error string for sub-grid errors" do - @game.board.board[0][0] = 7 + @game.board[1,1] = 7 @game.validate @game.errors.should include "7 is repeated in sub_grid 1" end it "ignores missing (zero) elements for incomplete sudokus" do - @game.board.board[0][0] = 0 - @game.board.board[0][6] = 0 - @game.board.board[0][3] = 0 + @game.board[1,1] = 0 + @game.board[1,7] = 0 + @game.board[1,4] = 0 @game.validate @game.errors.should_not include "0 is repeated in row 1" end From e51d13e3055dc9a14539970dfda4f95e5ba0a832 Mon Sep 17 00:00:00 2001 From: JESii Date: Fri, 18 Oct 2013 12:54:24 -0700 Subject: [PATCH 25/28] Remove commented-out lines. --- lib/sudoku_board.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 9d479d6..06912a4 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -1,6 +1,4 @@ class SudokuBoard - #attr_accessor :row - #attr_reader :col, [] attr_reader :board def initialize(game_file) From 9207dd6dbd83a5c9deb9b97a01d13cac0606ae2f Mon Sep 17 00:00:00 2001 From: JESii Date: Sat, 19 Oct 2013 05:49:18 -0700 Subject: [PATCH 26/28] Clean up output code --- sudoku_validator | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sudoku_validator b/sudoku_validator index 9424d83..e42d569 100755 --- a/sudoku_validator +++ b/sudoku_validator @@ -3,9 +3,5 @@ require_relative 'lib/sudoku_validator' @validator = SudokuValidator.new(ARGV[0]) validity, status = @validator.validate -output = "" -output = "This sudoku is #{validity}" -output += ", and #{status}" -output += "." -puts output +puts "This sudoku is #{validity}, and #{status}." @validator.errors.each { |err| puts err } From f4448ea936da636e5463df3d118e9ad944951e06 Mon Sep 17 00:00:00 2001 From: JESii Date: Sat, 19 Oct 2013 06:19:46 -0700 Subject: [PATCH 27/28] Refactor/extract method... Clean up SudokuBoard#sub_grid method by extracting code to get a sub_grid row. --- lib/sudoku_board.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/sudoku_board.rb b/lib/sudoku_board.rb index 06912a4..b597f77 100644 --- a/lib/sudoku_board.rb +++ b/lib/sudoku_board.rb @@ -35,15 +35,16 @@ def sub_grid(number) row, col = sub_grid_start(number) s_grid = [] 3.times do - 3.times do - s_grid << self[row,col] - col += 1 - end - row += 1; col -= 3 + s_grid += sub_grid_row(row,col) + row += 1 end s_grid end + def sub_grid_row(row,col) + [self[row,col],self[row,col+1],self[row,col+2]] + end + def convert_line_to_row(line) line.chomp!.delete!('-+| ') return nil if line.empty? From 6a6957d24e98d96a4e2daa2f4189568ba50c0ba2 Mon Sep 17 00:00:00 2001 From: Jon Seidel Date: Tue, 22 Oct 2013 06:52:09 -0700 Subject: [PATCH 28/28] Refactor SudokuBoard examples... Reorganize examples by method as suggested for improved readability. --- spec/sudoku_board_spec.rb | 63 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/spec/sudoku_board_spec.rb b/spec/sudoku_board_spec.rb index 1745b59..599dafe 100644 --- a/spec/sudoku_board_spec.rb +++ b/spec/sudoku_board_spec.rb @@ -1,63 +1,64 @@ -require_relative '../lib/sudoku_validator' require_relative '../lib/sudoku_board' describe SudokuBoard do - describe "complete games" do - before do - @game = SudokuBoard.new("valid_complete.sudoku") - end + before do + @game_vc = SudokuBoard.new("valid_complete.sudoku") + @game_ii = SudokuBoard.new("invalid_incomplete.sudoku") + end + describe "#[]" do it "returns the first character of the sudoku file" do - expect(@game[1,1]).to eql 8 + expect(@game_vc[1,1]).to eql 8 end it "returns an arbitrary element from the board" do - expect(@game[4,5]).to eql 4 + expect(@game_vc[4,5]).to eql 4 + end + + it "returns zero for an empty position" do + expect(@game_ii[2,4]).to eql 0 end + end + describe "#row" do it "returns the first row of the sudoku file" do - expect(@game.row(1)).to eql [8,5,9,6,1,2,4,3,7] + expect(@game_vc.row(1)).to eql [8,5,9,6,1,2,4,3,7] end + + it "returns the expected row" do + expect(@game_ii.row(4)).to eql [0,0,0,1,0,7,0,0,2] + end + end + describe "#col" do it "returns the first column of the sudoku file" do - expect(@game.col(1)).to eql [8,7,1,9,3,2,4,6,5] + expect(@game_vc.col(1)).to eql [8,7,1,9,3,2,4,6,5] end + + it "returns the expected column" do + expect(@game_ii.col(8)).to eql [0,0,0,0,0,0,7,0,4] + end + end + describe "#sub_grid" do it "returns a 3x3 sub-grid as an array" do - expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] + expect(@game_vc.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] end it "returns a middle 3x3 sub-grid" do - expect(@game.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] + expect(@game_vc.sub_grid(5)).to eql [1,4,7,2,6,8,5,9,3] end it "successfully returns the last sub-grid" do - expect(@game.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] + expect(@game_vc.sub_grid(9)).to eql [6,7,5,8,9,3,2,4,1] end it "successfully returns the first sub-grid" do - expect(@game.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] - end - end - describe "incomplete games" do - before do - @game = SudokuBoard.new("invalid_incomplete.sudoku") - end - - it "returns zero for an empty position" do - expect(@game[2,4]).to eql 0 - end - - it "returns the expected row" do - expect(@game.row(4)).to eql [0,0,0,1,0,7,0,0,2] - end - - it "returns the expected column" do - expect(@game.col(8)).to eql [0,0,0,0,0,0,7,0,4] + expect(@game_vc.sub_grid(1)).to eql [8,5,9,7,2,3,1,6,4] end it "returns the expected sub-grid" do - expect(@game.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] + expect(@game_ii.sub_grid(8)).to eql [0,8,0,0,0,0,0,3,6] end end end