Skip to content
This repository was archived by the owner on Jun 8, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source 'https://rubygems.org'

gem 'nokogiri', '~> 1.6.0'

group :development, :test do
gem "minitest", "~> 5.0.7"
end
14 changes: 14 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
GEM
remote: https://rubygems.org/
specs:
mini_portile (0.5.1)
minitest (5.0.8)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)

PLATFORMS
ruby

DEPENDENCIES
minitest (~> 5.0.7)
nokogiri (~> 1.6.0)
7 changes: 7 additions & 0 deletions SudokuValidator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require_relative 'lib/board_reader'
require_relative 'lib/board_validator'

raise 'Missing input file - SudokuValidator <filename>' if ARGV.length != 1
board = Sudoku::BoardValidator.new(Sudoku::BoardReader.new(ARGV[0]).read)
puts board.valid_board?

23 changes: 23 additions & 0 deletions lib/board_reader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Sudoku
class BoardReader

def initialize(file)
@file = file
end

def read
board = []
open(@file).each_with_index do |l,index|
board << l.chomp!
# could get more involved checking specific lines here like ---+---+---
raise "Invalid board string [#{board[index]}]" if board[index].match(valid_chars) == nil
end
board
end

private
def valid_chars
/^[1-9|+.\-\s]+$/
end
end
end
68 changes: 68 additions & 0 deletions lib/board_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module Sudoku
class BoardValidator

def initialize( board_string )
raise 'Invalid number of rows in board' if board_string.count != 11

row_index = 0 # can't use _with_index because of line rows
board_string.each do |one_row|
one_row_number_array = one_row.gsub('|','').gsub('+','').gsub('-','').split
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using this?

line.split(/[^\d\.]+/)

if one_row_number_array.count == 9
init_one_row( row_index, one_row_number_array )
row_index += 1
else
raise 'Invalid Board' if one_row_number_array.count != 0
end
end
end

def valid_board?
@rows.each {|row| return false if !array_unique?(row)}
@cols.each {|col| return false if !array_unique?(col)}
@grids.each {|grid| return false if !array_unique?(grid)}
true
end





private

def init_one_row( row_id, row_string )
# store the row as a row
rows[row_id].concat(row_string)
# store each element of the array into the cols arrays
row_string.each_with_index {|x,i| cols[i] << x}
# pull off 3 at a top and store in the grids array
in_groups_of(row_string,3).each_with_index do |triplet,i|
grids[((row_id/3)*3)+i].concat(triplet)
end
end

def array_unique?(arr)
# clone the tested array because delete is destructive
_arr = arr.clone
_arr.delete('.')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider arr.reject { |a| a == '.' } ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think that's cleaner than delete?

_arr.uniq.count == _arr.count
end

def rows
@rows ||= [[],[],[],[],[],[],[],[],[]]
end

def cols
@cols ||= [[],[],[],[],[],[],[],[],[]]
end

def grids
@grids ||= [[],[],[],[],[],[],[],[],[]]
end

def in_groups_of(array,number)
groups = []
array.each_slice(number) {|group| groups << group}
groups
end
end
end
11 changes: 11 additions & 0 deletions specs/invalid_error_board.sudoku
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
A B C |D E F |G H I
7 2 3 |8 5 4 |1 6 9
1 6 4 |3 7 9 |5 2 8
------+------+------
. . . |. . . |. . .
. . . |. . . |. . .
. . . |. . . |. . .
------+------+------
. . . |. . . |. . .
. . . |. . . |. . .
. . . |. . . |. . .
24 changes: 24 additions & 0 deletions specs/sudoku_reader_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'minitest'
require 'minitest/autorun'
require_relative '../lib/board_reader'


class TestMacbethAnalyzer < MiniTest::Test

describe '#read' do
def test_read_valid_board_returns_11_rows
array = Sudoku::BoardReader.new('./specs/valid_test_board.sudoku').read
assert_equal( array.count, 11 )
end
def test_read_valid_board_returns_correct_row
array = Sudoku::BoardReader.new('./specs/valid_test_board.sudoku').read
assert_equal( "8 5 9 |6 1 2 |4 3 7", array[0] )
end
def test_read_error_board
board_reader = Sudoku::BoardReader.new('./specs/invalid_error_board.sudoku')
#puts board_reader.read
assert_raises(RuntimeError) { board_reader.read }
end
end
end

182 changes: 182 additions & 0 deletions specs/sudoku_validator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
require 'minitest'
require 'minitest/autorun'
require_relative '../lib/board_validator'
require 'minitest/autorun'

module MiniTest::Assertions
def assert_contains(string, substring)
assert string.include?(substring), "Expected #{string} to contain #{substring}"
end
end
String.infect_an_assertion :assert_contains, :must_contain, :only_one_argument



class TestMacbethAnalyzer < MiniTest::Test

describe '#initialize' do
def setup
@test_board = [
"1 1 1 |1 1 1 |1 1 1",
"2 2 2 |2 2 2 |2 2 2",
"3 3 3 |3 3 3 |3 3 3",
"------+------+------",
"4 4 4 |4 4 4 |4 4 4",
"5 5 5 |5 5 5 |5 5 5",
"6 6 6 |6 6 6 |6 6 6",
"------+------+------",
"7 7 7 |7 7 7 |7 7 7",
"8 8 8 |8 8 8 |8 8 8",
"9 9 9 |9 9 9 |9 9 9"
]
@exception_board = [
" |1 1 1 |1 1 1",
"2 2 2 |2 2 2 |2 2 2",
"3 3 3 |3 3 3 |3 3 3",
"------+------+------",
"4 4 4 |4 4 4 |4 4 4",
"5 5 5 |5 5 5 |5 5 5",
"6 6 6 |6 6 6 |6 6 6",
"------+------+------",
"7 7 7 |7 7 7 |7 7 7",
"8 8 8 |8 8 8 |8 8 8",
"9 9 9 |9 9 9 |9 9 9"
]
@board_not_complete = [
"1 1 1 |1 1 1 |1 1 1",
"2 2 2 |2 2 2 |2 2 2",
"3 3 3 |3 3 3 |3 3 3",
"------+------+------",
]

end
def test_valid_validator_input
board = Sudoku::BoardValidator.new @test_board
board.inspect.to_s.must_contain(
'rows=[["1", "1", "1", "1", "1", "1", "1", "1", "1"], '+
'["2", "2", "2", "2", "2", "2", "2", "2", "2"], '+
'["3", "3", "3", "3", "3", "3", "3", "3", "3"], '+
'["4", "4", "4", "4", "4", "4", "4", "4", "4"], '+
'["5", "5", "5", "5", "5", "5", "5", "5", "5"], '+
'["6", "6", "6", "6", "6", "6", "6", "6", "6"], '+
'["7", "7", "7", "7", "7", "7", "7", "7", "7"], '+
'["8", "8", "8", "8", "8", "8", "8", "8", "8"], '+
'["9", "9", "9", "9", "9", "9", "9", "9", "9"]]'
)

board.inspect.to_s.must_contain(
'cols=[["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"], '+
'["1", "2", "3", "4", "5", "6", "7", "8", "9"]]'
)
board.inspect.to_s.must_contain(
'grids=[["1", "1", "1", "2", "2", "2", "3", "3", "3"], '+
'["1", "1", "1", "2", "2", "2", "3", "3", "3"], '+
'["1", "1", "1", "2", "2", "2", "3", "3", "3"], '+
'["4", "4", "4", "5", "5", "5", "6", "6", "6"], '+
'["4", "4", "4", "5", "5", "5", "6", "6", "6"], '+
'["4", "4", "4", "5", "5", "5", "6", "6", "6"], '+
'["7", "7", "7", "8", "8", "8", "9", "9", "9"], '+
'["7", "7", "7", "8", "8", "8", "9", "9", "9"], '+
'["7", "7", "7", "8", "8", "8", "9", "9", "9"]]'
)
end
def test_incomplete_board
assert_raises(RuntimeError) { Sudoku::BoardValidator.new @board_not_complete }
end
def test_invalid_entries_board
assert_raises(RuntimeError) { Sudoku::BoardValidator.new @exception_board }
end
end
describe '#valid_board?' do
def setup
@valid_board = [
"4 5 2 |6 1 8 |9 7 3",
"3 1 8 |2 7 9 |5 4 6",
"7 9 6 |4 5 3 |8 1 2",
"------+------+------",
"2 4 7 |8 9 6 |1 3 5",
"9 3 1 |5 4 7 |2 6 8",
"8 6 5 |1 3 2 |7 9 4",
"------+------+------",
"5 2 9 |7 6 4 |3 8 1",
"6 8 3 |9 2 1 |4 5 7",
"1 7 4 |3 8 5 |6 2 9",
]
@blank_board = [
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
]
@invalid_row = [
"1 . . |1 . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
]
@invalid_col = [
"1 . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
"1 . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
]
@invalid_grid = [
"1 . . |. . . |. . .",
". . . |. . . |. . .",
". . 1 |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
"------+------+------",
". . . |. . . |. . .",
". . . |. . . |. . .",
". . . |. . . |. . .",
]
end
def test_valid_board
assert_equal(Sudoku::BoardValidator.new(@valid_board).valid_board?, true )
end
def test_valid_empty_board
assert_equal(Sudoku::BoardValidator.new(@blank_board).valid_board?, true )
end
def test_invalid_row
assert_equal(Sudoku::BoardValidator.new(@invalid_row).valid_board?, false )
end
def test_invalid_col
assert_equal(Sudoku::BoardValidator.new(@invalid_col).valid_board?, false )
end
def test_invalid_grid
assert_equal(Sudoku::BoardValidator.new(@invalid_grid).valid_board?, false )
end
end
end

11 changes: 11 additions & 0 deletions specs/valid_test_board.sudoku
Original file line number Diff line number Diff line change
@@ -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
------+------+------
. . . |. . . |. . .
. . . |. . . |. . .
. . . |. . . |. . .
------+------+------
. . . |. . . |. . .
. . . |. . . |. . .
. . . |. . . |. . .
2 changes: 1 addition & 1 deletion valid_complete.sudoku
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
8 5 9 |6 1 2 |4 3 7
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
------+------+------
Expand Down