i_love_sudoku 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dd47f88a053039b5b60a920f660971138413ceba
4
+ data.tar.gz: 4fb5ff17efd4fd25fce85c7213ebc764e70e57e2
5
+ SHA512:
6
+ metadata.gz: 92946d5fd9c64dce7ad71e1cf49b24b2a13dc36a3fa111df7bb9e2b3425fd089c06ac0790221d582deea640af8ea6c85155f87a3f4d5faa5b249d15aa2854e77
7
+ data.tar.gz: c12aa8ae69a78ae5aa2a53b874c233f59559a94277e838259a9828fe4cedb5436041201b45d4ab517d428f360d8c8bd8b0a568eb6e95fd560bfb833e071f94ea
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in i_love_sudoku.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Dan Berger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # I Love Sudoku
2
+
3
+ I Love Sudoku is a gem for solving any sudoku puzzle.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'i_love_sudoku'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install i_love_sudoku
20
+
21
+ ## Usage
22
+
23
+ ###`ILoveSudoku.new(matrix)`
24
+
25
+ You can create a new puzzle either with or without a ready-made matrix.
26
+
27
+ If you have a 9x9 nested array already, for example if you're using the gem in the context of a web app where that formatted object comes over from the front end, you can create a new puzzle with that array. Note that empty spaces are represented by `nil`.
28
+
29
+ ```
30
+ $ matrix = [ [nil, 7, nil, nil, nil, nil, 5, nil, nil],
31
+ [nil, nil, nil, nil, 5, 1, nil, nil, nil],
32
+ [nil, nil, nil, 3, 7, 9, 2, 6, 8],
33
+ [1, 2, nil, nil, 8, nil, 4, nil, 6],
34
+ [nil, 4, nil, nil, nil, nil, nil, 9, nil],
35
+ [9, nil, 3, nil, 2, nil, nil, 8, 5],
36
+ [8, 9, 7, 2, 4, 3, nil, nil, nil],
37
+ [nil, nil, nil, 6, 1, nil, nil, nil, nil],
38
+ [nil, nil, 2, nil, nil, nil, nil, 4, nil] ]
39
+ $ puzzle = ILoveSudoku.new(matrix)
40
+ $ puts puzzle.unsolved_string
41
+ .7.|...|5..
42
+ ...|.51|...
43
+ ...|379|268
44
+ ---+---+---
45
+ 12.|.8.|4.6
46
+ .4.|...|.9.
47
+ 9.3|.2.|.85
48
+ ---+---+---
49
+ 897|243|...
50
+ ...|61.|...
51
+ ..2|...|.4.
52
+ ```
53
+
54
+ If you're playing with the gem in your terminal, it probably makes more sense to create a puzzle with no matrix and manually input the separate lines. See `#edit_row` for details.
55
+
56
+
57
+ ```
58
+ $ puzzle = ILoveSudoku.new
59
+ $ puts puzzle.unsolved_string
60
+ ...|...|...
61
+ ...|...|...
62
+ ...|...|...
63
+ ---+---+---
64
+ ...|...|...
65
+ ...|...|...
66
+ ...|...|...
67
+ ---+---+---
68
+ ...|...|...
69
+ ...|...|...
70
+ ...|...|...
71
+ ```
72
+
73
+ ###`#edit_row(row_number, string)`
74
+ This method takes the row number (indexed from 0) and a string of periods and integers and overwrites the existing row. This is a good way to manually enter a puzzle in your command line.
75
+
76
+ ```
77
+ $ puzzle = ILoveSudoku.new
78
+ $ puzzle.edit_row(1, "3..4..678")
79
+ $ puts puzzle.unsolved_string
80
+ ...|...|...
81
+ 3..|4..|678
82
+ ...|...|...
83
+ ---+---+---
84
+ ...|...|...
85
+ ...|...|...
86
+ ...|...|...
87
+ ---+---+---
88
+ ...|...|...
89
+ ...|...|...
90
+ ...|...|...
91
+ ```
92
+
93
+ ###`#unsolved_string` and `#unsolved_matrix`
94
+ Returns the current state of the puzzle input in string or matrix format.
95
+
96
+ ###`#solved_string` and `#solved_matrix`
97
+ Returns the solved puzzle in string or matrix format.
98
+
99
+
100
+ ## Contributing
101
+
102
+ Bug reports and pull requests are welcome on GitHub at https://github.com/dsberger/i_love_sudoku.
103
+
104
+
105
+ ## License
106
+
107
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
108
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "i_love_sudoku"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'i_love_sudoku/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "i_love_sudoku"
8
+ spec.version = ILoveSudoku::VERSION
9
+ spec.authors = ["Dan Berger"]
10
+ spec.email = ["dsberger@gmail.com"]
11
+
12
+ spec.summary = "A gem to solve any sudoku puzzle."
13
+ spec.homepage = "http://github.com/dsberger/i_love_sudoku"
14
+ spec.license = "MIT"
15
+
16
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
+ # delete this section to allow pushing this gem to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.required_ruby_version = ">= 2.1.0"
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.10"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec"
34
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "./matrix_tools"
2
+
3
+ module ILoveSudoku
4
+ class ArrayValidator
5
+ include MatrixTools
6
+
7
+ def initialize(matrix)
8
+ @matrix = matrix
9
+ end
10
+
11
+ def valid?
12
+ matrix.map { |row| has_duplicates?(row) }.none?
13
+ end
14
+
15
+
16
+ private
17
+
18
+ attr_reader :matrix
19
+
20
+ end
21
+ end
@@ -0,0 +1,81 @@
1
+ module ILoveSudoku
2
+ class BlockOfNine
3
+
4
+ def initialize
5
+ @cells = []
6
+ @made_progress = false
7
+ end
8
+
9
+ def self.new_from(nine_cells)
10
+ block = self.new
11
+ nine_cells.each { |cell| block.add_cell(cell) }
12
+ block
13
+ end
14
+
15
+ def add_cell(cell)
16
+ @cells << cell
17
+ end
18
+
19
+ def hit!
20
+ @made_progress = false
21
+ sweep_clean!
22
+ heat_seek!
23
+ made_progress
24
+ end
25
+
26
+
27
+ private
28
+
29
+ attr_reader :cells, :made_progress
30
+
31
+ def sweep_clean!
32
+ found_values.each { |n| remove_from_unsolved_cells(n) }
33
+ end
34
+
35
+ def remove_from_unsolved_cells(n)
36
+ removed = []
37
+ unsolved_cells.each do |cell|
38
+ removed << cell.remove!(n)
39
+ end
40
+ @made_progress = removed.any? unless made_progress
41
+ end
42
+
43
+ def heat_seek!
44
+ looking_for = unfound_values
45
+ looking_for.each { |n| try_to_solve_only_remaining(n) }
46
+ end
47
+
48
+ def try_to_solve_only_remaining(n)
49
+ solved = false
50
+ capture = cells_that_might_be(n)
51
+ if capture.length == 1
52
+ solved = capture[0].solve!(n)
53
+ end
54
+ @made_progress = solved unless made_progress
55
+ end
56
+
57
+ def found(n)
58
+ found_values.include?(n)
59
+ end
60
+
61
+ def cells_that_might_be(n)
62
+ unsolved_cells.select { |cell| cell.possibilities.include?(n) }
63
+ end
64
+
65
+ def found_values
66
+ solved_cells.map { |cell| cell.value }.sort
67
+ end
68
+
69
+ def unfound_values
70
+ (1..9).to_a - found_values
71
+ end
72
+
73
+ def unsolved_cells
74
+ cells.reject { |cell| cell.value }
75
+ end
76
+
77
+ def solved_cells
78
+ cells.select { |cell| cell.value }
79
+ end
80
+ end
81
+ end
data/lib/cell.rb ADDED
@@ -0,0 +1,49 @@
1
+ module ILoveSudoku
2
+ class Cell
3
+
4
+ def initialize(value = nil)
5
+ @state = set_state(value)
6
+ end
7
+
8
+ def value
9
+ solved? ? state[0] : nil
10
+ end
11
+
12
+ def possibilities
13
+ solved? ? nil : state
14
+ end
15
+
16
+ def remove!(n)
17
+ able_to_remove = can_take_action_on(n)
18
+ state.delete(n) if able_to_remove
19
+ able_to_remove
20
+ end
21
+
22
+ def solve!(n)
23
+ able_to_solve = can_take_action_on(n)
24
+ @state = [n] if able_to_solve
25
+ able_to_solve
26
+ end
27
+
28
+
29
+ private
30
+
31
+ attr_reader :state
32
+
33
+ def solved?
34
+ state.length == 1
35
+ end
36
+
37
+ def can_take_action_on(n)
38
+ !solved? && state.include?(n)
39
+ end
40
+
41
+ def set_state(value)
42
+ if value.nil?
43
+ (1..9).to_a
44
+ else
45
+ [value]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,25 @@
1
+ module ILoveSudoku
2
+ class CellMatrixCreator
3
+
4
+ attr_reader :cell_matrix
5
+
6
+ def initialize(matrix)
7
+ @cell_matrix = create_cell_matrix(matrix)
8
+ end
9
+
10
+ private
11
+
12
+ def create_cell_matrix(matrix)
13
+ matrix.each_with_object([]) do |row, arr|
14
+ arr << create_row_of_new_cells(row)
15
+ end
16
+ end
17
+
18
+ def create_row_of_new_cells(row)
19
+ row.each_with_object([]) do |value, arr|
20
+ arr << Cell.new(value)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ module ILoveSudoku
2
+ class GraphSearcher
3
+ include MatrixTools
4
+
5
+ attr_reader :result
6
+
7
+ def initialize(matrix)
8
+ @matrix = matrix
9
+ grid = Grid.new_from_matrix(deep_dup(matrix))
10
+ @possibilities_matrix = grid.possibilities_matrix
11
+ @values_matrix = grid.values_matrix
12
+ @result = solve
13
+ end
14
+
15
+
16
+ private
17
+
18
+ attr_reader :matrix, :values_matrix, :possibilities_matrix
19
+
20
+ # In Railsy fashion, this returns either a solved matrx or false.
21
+ def solve
22
+ if validator.solved?
23
+ values_matrix # <= solved matrix
24
+ elsif validator.valid?
25
+ process_queue_of_next_iterations # <= solved matrix or false
26
+ else
27
+ false # <= false
28
+ end
29
+ end
30
+
31
+ def process_queue_of_next_iterations
32
+ queue = valid_next_iterations
33
+ complete_solution = false
34
+
35
+ until complete_solution || queue.empty?
36
+ active_graph_search = queue.shift
37
+ complete_solution = active_graph_search.result
38
+ end
39
+
40
+ complete_solution
41
+ end
42
+
43
+ def valid_next_iterations
44
+ x, y = coords_of_first_empty_cell
45
+ possible_values = possibilities_matrix[x][y]
46
+
47
+ possible_values.each_with_object([]) do |num, queue|
48
+ temp_values_matrix = deep_dup(values_matrix)
49
+ temp_values_matrix[x][y] = num
50
+ queue << GraphSearcher.new(temp_values_matrix)
51
+ end
52
+ end
53
+
54
+ def coords_of_first_empty_cell
55
+ (0..8).each do |row|
56
+ (0..8).each do |col|
57
+ return [row, col] if values_matrix[row][col].nil?
58
+ end
59
+ end
60
+ end
61
+
62
+ def validator
63
+ SolutionValidator.new(values_matrix)
64
+ end
65
+ end
66
+ end
data/lib/grid.rb ADDED
@@ -0,0 +1,62 @@
1
+ module ILoveSudoku
2
+ class Grid
3
+
4
+ def initialize(cell_matrix:, rows:, columns:, subgroups:)
5
+ @cell_matrix = cell_matrix
6
+ @rows = rows
7
+ @columns = columns
8
+ @subgroups = subgroups
9
+ solve!
10
+ end
11
+
12
+ def self.new_from_matrix(matrix)
13
+ cell_matrix = CellMatrixCreator.new(matrix).cell_matrix
14
+ rows = StraightLineCreator.new(cell_matrix).lines
15
+ columns = StraightLineCreator.new(cell_matrix.transpose).lines
16
+ subgroups = SubgroupCreator.new(cell_matrix).subgroups
17
+
18
+ Grid.new( cell_matrix: cell_matrix,
19
+ rows: rows,
20
+ columns: columns,
21
+ subgroups: subgroups )
22
+ end
23
+
24
+ def values_matrix
25
+ cell_matrix.map do |row|
26
+ row.map { |cell| cell.value }
27
+ end
28
+ end
29
+
30
+ def possibilities_matrix
31
+ cell_matrix.map do |row|
32
+ row.map { |cell| cell.possibilities }
33
+ end
34
+ end
35
+
36
+
37
+ private
38
+
39
+ attr_reader :cell_matrix, :rows, :columns, :subgroups
40
+
41
+ def solve!
42
+ loop do
43
+
44
+ row_progress = hit_all!(:rows)
45
+ column_progress = hit_all!(:columns)
46
+ subgroup_progress = hit_all!(:subgroups)
47
+
48
+ making_progress = row_progress ||
49
+ column_progress ||
50
+ subgroup_progress
51
+
52
+ break unless making_progress
53
+ end
54
+ end
55
+
56
+ def hit_all!(sym)
57
+ send(sym).each_with_object([]) do |item, success|
58
+ success << item.hit!
59
+ end.any?
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "i_love_sudoku/version"
2
+
3
+ require 'array_validator'
4
+ require 'block_of_nine'
5
+ require 'cell'
6
+ require 'cell_matrix_creator'
7
+ require 'graph_searcher'
8
+ require 'grid'
9
+ require 'puzzle'
10
+ require 'puzzle_formatter'
11
+ require 'solution_validator'
12
+ require 'straight_line_creator'
13
+ require 'subgroup_creator'
14
+ require 'subgroup_validator'
15
+
16
+ module ILoveSudoku
17
+ def self.new(matrix=nil)
18
+ Puzzle.new(matrix)
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module ILoveSudoku
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,28 @@
1
+ module ILoveSudoku
2
+ module MatrixTools
3
+
4
+ private
5
+
6
+ SUBGROUP_TOP_LEFT_COORDINATES = [
7
+ [0,0],[0,3],[0,6],[3,0],[3,3],[3,6],[6,0],[6,3],[6,6]
8
+ ]
9
+
10
+ def subgroup_from(any_matrix, x, y)
11
+ any_matrix[x][y..y+2] +
12
+ any_matrix[x+1][y..y+2] +
13
+ any_matrix[x+2][y..y+2]
14
+ end
15
+
16
+ def deep_dup(any_matrix)
17
+ any_matrix.each_with_object([]) do |row, dupe|
18
+ dupe << row.dup
19
+ end
20
+ end
21
+
22
+ def has_duplicates?(test_array)
23
+ test_array = test_array.compact
24
+ test_array.length != test_array.uniq.length
25
+ end
26
+
27
+ end
28
+ end
data/lib/puzzle.rb ADDED
@@ -0,0 +1,41 @@
1
+ module ILoveSudoku
2
+ class Puzzle
3
+
4
+ def initialize(matrix=nil)
5
+ @matrix = matrix ||= blank_matrix
6
+ end
7
+
8
+ def unsolved_matrix
9
+ @matrix
10
+ end
11
+
12
+ def solved_matrix
13
+ GraphSearcher.new(@matrix).result
14
+ end
15
+
16
+ def unsolved_string
17
+ PuzzleFormatter.new(@matrix).to_s
18
+ end
19
+
20
+ def solved_string
21
+ PuzzleFormatter.new(solved_matrix).to_s
22
+ end
23
+
24
+ def edit_row(index, str)
25
+ arr = []
26
+ str.each_char do |char|
27
+ arr << (char == "." ? nil : char.to_i)
28
+ end
29
+ @matrix[index] = arr
30
+ end
31
+
32
+ private
33
+
34
+ def blank_matrix
35
+ arr = []
36
+ 9.times { arr << [nil] * 9 }
37
+ arr
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module ILoveSudoku
2
+ class PuzzleFormatter
3
+
4
+ def initialize(matrix)
5
+ @matrix = matrix
6
+ end
7
+
8
+ def to_s
9
+ rows = matrix_with_rows_formatted
10
+ [ rows[0..2].join("\n"),
11
+ rows[3..5].join("\n"),
12
+ rows[6..8].join("\n") ].join(divider)
13
+ end
14
+
15
+ private
16
+
17
+ def matrix_with_rows_formatted
18
+ matrix_with_nils_replaced.each_with_object([]) do |row, output|
19
+ output << format_row(row)
20
+ end
21
+ end
22
+
23
+ def matrix_with_nils_replaced
24
+ @matrix.map do |row|
25
+ row.map do |cell|
26
+ cell.nil? ? "." : cell
27
+ end
28
+ end
29
+ end
30
+
31
+ def format_row(row)
32
+ [ row[0..2].join(""),
33
+ row[3..5].join(""),
34
+ row[6..8].join("") ].join("|")
35
+ end
36
+
37
+ def divider
38
+ "\n---+---+---\n"
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module ILoveSudoku
2
+ class SolutionValidator
3
+
4
+ def initialize(matrix)
5
+ @matrix = matrix
6
+ end
7
+
8
+ def solved?
9
+ valid? && complete?
10
+ end
11
+
12
+ def valid?
13
+ valid_rows? && valid_columns? && valid_subgroups?
14
+ end
15
+
16
+ def complete?
17
+ matrix.map { |row| row.include?(nil) }.none?
18
+ end
19
+
20
+
21
+ private
22
+
23
+ attr_reader :matrix
24
+
25
+ def valid_rows?
26
+ ArrayValidator.new(matrix).valid?
27
+ end
28
+
29
+ def valid_columns?
30
+ # Same validator as for rows, but with input transposed.
31
+ ArrayValidator.new(matrix.transpose).valid?
32
+ end
33
+
34
+ def valid_subgroups?
35
+ SubgroupValidator.new(matrix).valid?
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ module ILoveSudoku
2
+ class StraightLineCreator
3
+
4
+ attr_reader :lines
5
+
6
+ def initialize(cell_matrix)
7
+ @lines = create_lines(cell_matrix)
8
+ end
9
+
10
+
11
+ private
12
+
13
+ def create_lines(cell_matrix)
14
+ cell_matrix.each_with_object([]) do |row, arr|
15
+ arr << BlockOfNine.new_from(row)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "./matrix_tools"
2
+
3
+ module ILoveSudoku
4
+ class SubgroupCreator
5
+ include MatrixTools
6
+
7
+ def initialize(cell_matrix)
8
+ @cell_matrix = cell_matrix
9
+ end
10
+
11
+ def subgroups
12
+ @subgroups ||= create_subgroups
13
+ end
14
+
15
+
16
+ private
17
+
18
+ attr_reader :cell_matrix
19
+
20
+ def create_subgroups
21
+ SUBGROUP_TOP_LEFT_COORDINATES.each_with_object([]) do |coords, arr|
22
+ x, y = coords
23
+ cells = subgroup_from(cell_matrix, x, y)
24
+ arr << BlockOfNine.new_from(cells)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module ILoveSudoku
2
+ class SubgroupValidator
3
+ include MatrixTools
4
+
5
+ def initialize(matrix)
6
+ @matrix = matrix
7
+ end
8
+
9
+ def valid?
10
+ SUBGROUP_TOP_LEFT_COORDINATES
11
+ .map do |coords|
12
+ x, y = coords
13
+ group = subgroup_from(matrix, x, y)
14
+ has_duplicates?(group)
15
+ end.none?
16
+ end
17
+
18
+
19
+ private
20
+
21
+ attr_reader :matrix
22
+
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i_love_sudoku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dan Berger
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - dsberger@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - .travis.yml
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - i_love_sudoku.gemspec
72
+ - lib/array_validator.rb
73
+ - lib/block_of_nine.rb
74
+ - lib/cell.rb
75
+ - lib/cell_matrix_creator.rb
76
+ - lib/graph_searcher.rb
77
+ - lib/grid.rb
78
+ - lib/i_love_sudoku.rb
79
+ - lib/i_love_sudoku/version.rb
80
+ - lib/matrix_tools.rb
81
+ - lib/puzzle.rb
82
+ - lib/puzzle_formatter.rb
83
+ - lib/solution_validator.rb
84
+ - lib/straight_line_creator.rb
85
+ - lib/subgroup_creator.rb
86
+ - lib/subgroup_validator.rb
87
+ homepage: http://github.com/dsberger/i_love_sudoku
88
+ licenses:
89
+ - MIT
90
+ metadata:
91
+ allowed_push_host: https://rubygems.org
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: 2.1.0
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: A gem to solve any sudoku puzzle.
112
+ test_files: []
113
+ has_rdoc: