sudoku_bad 0.0.2
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 +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/Guardfile +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +11 -0
- data/bin/sudoku +8 -0
- data/data/sudoku11496.txt +1 -0
- data/data/sudoku16576.txt +1 -0
- data/data/sudoku28276.txt +1 -0
- data/data/sudoku8134.txt +1 -0
- data/lib/sudoku/grid_factory.rb +93 -0
- data/lib/sudoku/log.rb +30 -0
- data/lib/sudoku/main_window.rb +128 -0
- data/lib/sudoku/model/cell.rb +95 -0
- data/lib/sudoku/model/cell_coordinates.rb +54 -0
- data/lib/sudoku/model/coordinate.rb +61 -0
- data/lib/sudoku/model/grid.rb +98 -0
- data/lib/sudoku/solver.rb +61 -0
- data/lib/sudoku/version.rb +4 -0
- data/lib/sudoku.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/sudoku/grid_factory_spec.rb +48 -0
- data/spec/sudoku/log_spec.rb +20 -0
- data/spec/sudoku/model/cell_coordinates_spec.rb +35 -0
- data/spec/sudoku/model/cell_spec.rb +98 -0
- data/spec/sudoku/model/coordinate_spec.rb +39 -0
- data/spec/sudoku/model/empty_grid.txt +9 -0
- data/spec/sudoku/model/grid_spec.rb +97 -0
- data/spec/sudoku/model/spec_helper.rb +3 -0
- data/spec/sudoku/solver_spec.rb +29 -0
- data/spec/sudoku/spec_helper.rb +3 -0
- data/spec/sudoku_spec.rb +12 -0
- data/sudoku.gemspec +29 -0
- metadata +203 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'sudoku/model/coordinate'
|
2
|
+
|
3
|
+
module Sudoku
|
4
|
+
# Represents the Sudoku Grid model.
|
5
|
+
class Grid
|
6
|
+
attr_reader :cells
|
7
|
+
|
8
|
+
# Will initialize this grid by given hash of cells. If no
|
9
|
+
# cells are given, the grid will have empty values and
|
10
|
+
# default cells.
|
11
|
+
def initialize(cells = {})
|
12
|
+
@cells = cells
|
13
|
+
GridFactory.new.generate_all_coordinates.each do |x|
|
14
|
+
add_cell(generate_default_cell(x))
|
15
|
+
end if cells.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Will return true, if all filled values are other than 0.
|
19
|
+
def filled?
|
20
|
+
!cells.values.collect(&:value).include?(0)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Will return true, if rules of Sudoku are violated in this
|
24
|
+
# grid. Ignores values 0.
|
25
|
+
def rules_violated?
|
26
|
+
Solver.new(self).rules_violated?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Will return cell at random position from this grid.
|
30
|
+
def random_cell
|
31
|
+
get_cell(CellCoordinates.random)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Will return particular cell based on given coordinates. If
|
35
|
+
# there is not cell on given coordinates, default cell will
|
36
|
+
# be created (not filled, editable).
|
37
|
+
# * +coordinates+ cell coordinates.
|
38
|
+
def get_cell(coordinates)
|
39
|
+
cells[coordinates]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Will reset cell on given coordinates by creating the
|
43
|
+
# default new one.
|
44
|
+
# * +coordinates+ for the newly created cell
|
45
|
+
def reset_cell(coordinates)
|
46
|
+
add_cell(generate_default_cell(coordinates))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Will generate default cell, which will have the given
|
50
|
+
# coordinates, will be ediatable (fixed = false) and will be
|
51
|
+
# empty (value = 0)
|
52
|
+
# * +coordinates+ coordinates for the new cell
|
53
|
+
def generate_default_cell(coordinates)
|
54
|
+
Cell.new(coordinates, false, 0)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Will return array of cells stored on a row with given
|
58
|
+
# coordinate.
|
59
|
+
# * +y+ coordinate of the desired row. Must be in the 0-8 interval.
|
60
|
+
def get_row(y)
|
61
|
+
fail ArgumentException,
|
62
|
+
'Invalid row access coordinate.' unless Coordinate.valid?(y)
|
63
|
+
cells.values.select { |cell| cell.coordinates.coordinate_y == y }.sort
|
64
|
+
end
|
65
|
+
|
66
|
+
# Will return array of cells stored in a given column of this
|
67
|
+
# grid.
|
68
|
+
# * +x+ coordinate of the desired column. Must be in the 0-8 interval.
|
69
|
+
def get_col(x)
|
70
|
+
fail ArgumentException,
|
71
|
+
'Invalid column access coordinate.' unless Coordinate.valid?(x)
|
72
|
+
cells.values.select { |cell| cell.coordinates.coordinate_x == x }.sort
|
73
|
+
end
|
74
|
+
|
75
|
+
# Will add new cell to the grid. If there is already a cell
|
76
|
+
# with the same coordintates, it will be replaced by the new
|
77
|
+
# one and the old one will be returned.
|
78
|
+
# * +cell+ cell to add
|
79
|
+
def add_cell(cell)
|
80
|
+
cells[cell.coordinates] = cell
|
81
|
+
end
|
82
|
+
|
83
|
+
# Will return true, it this gird is solved.
|
84
|
+
def solved?
|
85
|
+
Solver.new(self).solved?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Will return matrix of values of this Grid.
|
89
|
+
def to_s
|
90
|
+
out = ''
|
91
|
+
GridFactory.new.generate_all_coordinates.each_with_index do |x, index|
|
92
|
+
out << get_cell(x).value.to_s << x.to_s
|
93
|
+
(index + 1).modulo(9).zero? ? out << "\n" : out << ' '
|
94
|
+
end
|
95
|
+
out
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sudoku/model/grid'
|
2
|
+
|
3
|
+
module Sudoku
|
4
|
+
# This class provides method for solving or checking solution of the
|
5
|
+
# Sudoku game.
|
6
|
+
class Solver
|
7
|
+
# Will initialize this solver with given grid. Exception is thrown
|
8
|
+
# if the given grid is not kind of Sudoku::Grid
|
9
|
+
def initialize(grid)
|
10
|
+
fail ArgumentError,
|
11
|
+
'Invalid grid passed to solver' unless grid.is_a?(Grid)
|
12
|
+
@grid = grid
|
13
|
+
end
|
14
|
+
|
15
|
+
# Will check if the sudoku rules are violated, but the 0 value is
|
16
|
+
# ignored. Returns true if violated, false otherwise.
|
17
|
+
def rules_violated?
|
18
|
+
rows_violated? || cols_violated? || areas_violated?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Will return true, if all cells of the grid are filled and no
|
22
|
+
# Sudoku rule is violated.
|
23
|
+
def solved?
|
24
|
+
!rules_violated? && grid_filled?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Will return true, if the grid is filled, which means, that all
|
28
|
+
# of the values are other than 0. False otherwise.
|
29
|
+
def grid_filled?
|
30
|
+
@grid.filled?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Will return true, if all rows are correctly solved.
|
34
|
+
def rows_violated?
|
35
|
+
(0..8).to_a.collect { |x|cells_violated?(@grid.get_row(x)) }.any?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Will return true, if all cols are correctly solved.
|
39
|
+
def cols_violated?
|
40
|
+
(0..8).to_a.collect { |x|cells_violated?(@grid.get_col(x)) }.any?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Will return true, if given set of cells does not contain
|
44
|
+
# duplicities in values other than 0.
|
45
|
+
# * +cells+ set of cells to check.
|
46
|
+
def cells_violated?(cells)
|
47
|
+
values = cells.select { |x| x.value != 0 }.collect(&:value)
|
48
|
+
values.uniq.size != values.size
|
49
|
+
end
|
50
|
+
|
51
|
+
# Will return true, if in some area of the grid are duplicit or
|
52
|
+
# illegal numbers. Returns false otherwise.
|
53
|
+
def areas_violated?
|
54
|
+
[(0..2), (3..5), (6..8)].repeated_permutation(2).each do |x, y|
|
55
|
+
cells = @grid.cells.select { |cell| cell.in_area(x, y) }
|
56
|
+
return true if cells_violated?(cells)
|
57
|
+
end
|
58
|
+
false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/sudoku.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::GridFactory do
|
4
|
+
GRID_FACTORY ||= Sudoku::GridFactory
|
5
|
+
CELL_COORDINATES ||= Sudoku::CellCoordinates
|
6
|
+
let(:factory) { GRID_FACTORY.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
factory.disable_log
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'creates all coordinates set correctly' do
|
13
|
+
set = factory.generate_all_coordinates
|
14
|
+
expect(set.include?(CELL_COORDINATES.new(0, 0))).to be true
|
15
|
+
expect(set.include?(CELL_COORDINATES.new(8, 8))).to be true
|
16
|
+
expect(set.size).to eql(81)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'grid creation' do
|
20
|
+
let(:random_grid) { factory.create_random }
|
21
|
+
let(:solved_grid) { factory.create_full_grid }
|
22
|
+
let(:free_cell) { Sudoku::Cell.new(CELL_COORDINATES.random, false, 5) }
|
23
|
+
|
24
|
+
it 'the created solved grid does not have any free cells' do
|
25
|
+
invalid_cells = solved_grid.cells.values.select { |x| !x.fixed }
|
26
|
+
expect(invalid_cells.size).to eql(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'the random grid has no fixed cells with values other than 0' do
|
30
|
+
invalid = random_grid.cells.values.select { |x| !x.fixed && x.value > 0 }
|
31
|
+
expect(invalid.size).to eql(0)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'the random grid does not contains fixed cells with value = 0' do
|
35
|
+
invalid = random_grid.cells.values.select { |x| x.fixed && x.value == 0 }
|
36
|
+
expect(invalid.size).to eql(0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'number of opened cells corresponds to the settings of factory' do
|
40
|
+
cells = random_grid.cells.values.select { |x| !x.fixed }
|
41
|
+
expect(cells.size).to eql(GRID_FACTORY::CELLS_TO_OPEN)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'parsing of bad sudoku format fails' do
|
45
|
+
expect { factory.parse_file('lib/version.rb') }.to raise_error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::Logging do
|
4
|
+
LOGGING ||= Sudoku::Logging
|
5
|
+
|
6
|
+
let(:some_class) { Class.new.extend(Sudoku::Logging) }
|
7
|
+
|
8
|
+
before { some_class.disable_log }
|
9
|
+
|
10
|
+
it 'logger not null' do
|
11
|
+
expect(LOGGING::LOGGER).not_to be nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'no method raises exception' do
|
15
|
+
expect { some_class.info('whatever') }.not_to raise_error
|
16
|
+
expect { some_class.error('whatever') }.not_to raise_error
|
17
|
+
expect { some_class.fatal('whatever') }.not_to raise_error
|
18
|
+
expect { some_class.disable_log }.not_to raise_error
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::CellCoordinates do
|
4
|
+
CELL_COORDINATES ||= Sudoku::CellCoordinates
|
5
|
+
COORDINATE ||= Sudoku::Coordinate
|
6
|
+
|
7
|
+
let(:cell_coordinates_5_5) { CELL_COORDINATES.new(5, 5) }
|
8
|
+
let(:cell_coordinates_7_7) { CELL_COORDINATES.new(7, 7) }
|
9
|
+
let(:cell_coordinates_3_7) { CELL_COORDINATES.new(COORDINATE.new(3), 7) }
|
10
|
+
let(:cell_coordinates_wrong) { CELL_COORDINATES.new(0, 9) }
|
11
|
+
|
12
|
+
it 'proper initializations' do
|
13
|
+
expect(cell_coordinates_5_5.coordinate_x).to eql(5)
|
14
|
+
expect(cell_coordinates_5_5.coordinate_y).to eql(5)
|
15
|
+
expect(cell_coordinates_3_7.coordinate_x).to eql(3)
|
16
|
+
expect(cell_coordinates_3_7.coordinate_y).to eql(7)
|
17
|
+
expect { cell_coordinates_wrong }.to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'proper eql method' do
|
21
|
+
expect(cell_coordinates_5_5).to eql(cell_coordinates_5_5)
|
22
|
+
expect(cell_coordinates_5_5.eql?(CELL_COORDINATES.new(5, 5))).to be true
|
23
|
+
expect(cell_coordinates_5_5).not_to eql(cell_coordinates_3_7)
|
24
|
+
expect(cell_coordinates_5_5).not_to eql(5)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'proper to_s method' do
|
28
|
+
expect(cell_coordinates_5_5.to_s).to eql('[5, 5]')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'proper hash method' do
|
32
|
+
expect(cell_coordinates_5_5.hash).to eql(CELL_COORDINATES.new(5, 5).hash)
|
33
|
+
expect(cell_coordinates_5_5.hash == cell_coordinates_3_7.hash).to be false
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::Cell do
|
4
|
+
CELL_COORDINATES ||= Sudoku::CellCoordinates
|
5
|
+
CELL ||= Sudoku::Cell
|
6
|
+
let(:cell_coordinates_5_5) { CELL_COORDINATES.new(5, 5) }
|
7
|
+
let(:cell_coordinates_7_7) { CELL_COORDINATES.new(7, 7) }
|
8
|
+
|
9
|
+
context 'basic simple cells testing' do
|
10
|
+
let(:test_cell) { CELL.new(cell_coordinates_5_5, false, 0) }
|
11
|
+
let(:custom_cell) { CELL.new(cell_coordinates_5_5, true, 5) }
|
12
|
+
|
13
|
+
it 'can create valid cell' do
|
14
|
+
expect { test_cell }.not_to raise_error
|
15
|
+
expect { custom_cell }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has correct string representation' do
|
19
|
+
expect(test_cell.to_s).to eql('[5, 5], 0, false')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'increments correctly' do
|
23
|
+
(0..9).each do |i|
|
24
|
+
expect(test_cell.value).to eql(i)
|
25
|
+
test_cell.increment
|
26
|
+
end
|
27
|
+
expect(test_cell.value).to eql(0)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'decrements correctly' do
|
31
|
+
test_cell.decrement
|
32
|
+
(9.downto(0)).each do |i|
|
33
|
+
expect(test_cell.value).to eql(i)
|
34
|
+
test_cell.decrement
|
35
|
+
end
|
36
|
+
expect(test_cell.value).to eql(9)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'has correctly set parameters' do
|
40
|
+
expect(test_cell.value).to eql(0)
|
41
|
+
expect(test_cell.fixed).to eql(false)
|
42
|
+
expect(test_cell.coordinates).to eql(cell_coordinates_5_5)
|
43
|
+
|
44
|
+
expect(custom_cell.value).to eql(5)
|
45
|
+
expect(custom_cell.fixed).to eql(true)
|
46
|
+
expect(custom_cell.coordinates).to eql(cell_coordinates_5_5)
|
47
|
+
|
48
|
+
expect(custom_cell.coordinates.coordinate_x).to eql(5)
|
49
|
+
expect(custom_cell.coordinates.coordinate_y).to eql(5)
|
50
|
+
|
51
|
+
expect(test_cell.coordinates.coordinate_x).to eql(5)
|
52
|
+
expect(test_cell.coordinates.coordinate_y).to eql(5)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'the cells on same coordinates are equal' do
|
56
|
+
expect(test_cell.eql?(custom_cell)).to be true
|
57
|
+
expect(test_cell == custom_cell).to be true
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'the cells with different coordinates are not equal' do
|
61
|
+
expect(test_cell.eql?(CELL.new(cell_coordinates_7_7))).to be false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'does not allow to create fixed 0 cell' do
|
66
|
+
expect { CELL.new(cell_coordinates_5_5, true, 0) }.to raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'accepts only valid coordinates' do
|
70
|
+
expect { CELL.new('whatever') }.to raise_error
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns correct cell string representation' do
|
74
|
+
expect(CELL.new(cell_coordinates_5_5, false, 0).as_string).to eql('')
|
75
|
+
expect(CELL.new(cell_coordinates_5_5, true, 5).as_string).to eql('5')
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'setting value to cell' do
|
79
|
+
let(:fixed_cell) { CELL.new(cell_coordinates_7_7, true, 5) }
|
80
|
+
let(:free_cell) { CELL.new(cell_coordinates_5_5, false, 0) }
|
81
|
+
|
82
|
+
it 'cant assign value to fixed cell' do
|
83
|
+
expect { fixed_cell.value = 5 }.to raise_error
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'cant assign values out of interval 0-9' do
|
87
|
+
expect { free_cell.value = -1 }.to raise_error
|
88
|
+
expect { free_cell.value = 10 }.to raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'can assign correct values' do
|
92
|
+
expect { free_cell.value = 0 }.not_to raise_error
|
93
|
+
expect { free_cell.value = 9 }.not_to raise_error
|
94
|
+
expect { free_cell.value = 2 }.not_to raise_error
|
95
|
+
expect(free_cell.value).to eql(2)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::Coordinate do
|
4
|
+
COORDINATE ||= Sudoku::Coordinate
|
5
|
+
|
6
|
+
let(:coordinate5) { COORDINATE.new(5) }
|
7
|
+
let(:coordinate7) { COORDINATE.new(7) }
|
8
|
+
let(:coordinate0) { COORDINATE.new(0) }
|
9
|
+
let(:coordinate8) { COORDINATE.new(8) }
|
10
|
+
|
11
|
+
it 'accepts the number and COORDINATE in the constructor' do
|
12
|
+
expect(COORDINATE.new(5).coordinate).to eq(5)
|
13
|
+
expect(COORDINATE.new(COORDINATE.new(5)).coordinate).to eq(5)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns correct string' do
|
17
|
+
expect(coordinate5.to_s).to eq(5.to_s)
|
18
|
+
expect(coordinate5.to_s).not_to eq(10.to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'converts to_i and to_int' do
|
22
|
+
expect(coordinate5.to_i).to eq(5.to_i)
|
23
|
+
expect(coordinate5.to_int).to eq(5.to_int)
|
24
|
+
expect(coordinate5.to_i).not_to eq(10.to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'compares with coordinate and number' do
|
28
|
+
expect(coordinate5).to be < coordinate7
|
29
|
+
expect(coordinate7).to be > coordinate5
|
30
|
+
expect(coordinate5).to be == COORDINATE.new(5)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'accepts only vales from the interval 0-8 inclusive' do
|
34
|
+
expect { COORDINATE.new(10) }.to raise_error ArgumentError
|
35
|
+
expect { COORDINATE.new(-10) }.to raise_error ArgumentError
|
36
|
+
expect { COORDINATE.new(0) }.not_to raise_error
|
37
|
+
expect { COORDINATE.new(8) }.not_to raise_error
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
0[0, 0] 0[1, 0] 0[2, 0] 0[3, 0] 0[4, 0] 0[5, 0] 0[6, 0] 0[7, 0] 0[8, 0]
|
2
|
+
0[0, 1] 0[1, 1] 0[2, 1] 0[3, 1] 0[4, 1] 0[5, 1] 0[6, 1] 0[7, 1] 0[8, 1]
|
3
|
+
0[0, 2] 0[1, 2] 0[2, 2] 0[3, 2] 0[4, 2] 0[5, 2] 0[6, 2] 0[7, 2] 0[8, 2]
|
4
|
+
0[0, 3] 0[1, 3] 0[2, 3] 0[3, 3] 0[4, 3] 0[5, 3] 0[6, 3] 0[7, 3] 0[8, 3]
|
5
|
+
0[0, 4] 0[1, 4] 0[2, 4] 0[3, 4] 0[4, 4] 0[5, 4] 0[6, 4] 0[7, 4] 0[8, 4]
|
6
|
+
0[0, 5] 0[1, 5] 0[2, 5] 0[3, 5] 0[4, 5] 0[5, 5] 0[6, 5] 0[7, 5] 0[8, 5]
|
7
|
+
0[0, 6] 0[1, 6] 0[2, 6] 0[3, 6] 0[4, 6] 0[5, 6] 0[6, 6] 0[7, 6] 0[8, 6]
|
8
|
+
0[0, 7] 0[1, 7] 0[2, 7] 0[3, 7] 0[4, 7] 0[5, 7] 0[6, 7] 0[7, 7] 0[8, 7]
|
9
|
+
0[0, 8] 0[1, 8] 0[2, 8] 0[3, 8] 0[4, 8] 0[5, 8] 0[6, 8] 0[7, 8] 0[8, 8]
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::Grid do
|
4
|
+
CELL_COORDINATES ||= Sudoku::CellCoordinates
|
5
|
+
CELL ||= Sudoku::Cell
|
6
|
+
GRID ||= Sudoku::Grid
|
7
|
+
|
8
|
+
let(:cell_coordinates_5_5) { CELL_COORDINATES.new(5, 5) }
|
9
|
+
let(:cell_coordinates_7_7) { CELL_COORDINATES.new(7, 7) }
|
10
|
+
let(:fixed_cell) { CELL.new(cell_coordinates_5_5, true, 5) }
|
11
|
+
let(:free_cell) { CELL.new(cell_coordinates_7_7, false, 0) }
|
12
|
+
let(:same_free_cell) { CELL.new(cell_coordinates_7_7, true, 7) }
|
13
|
+
let(:test_grid) { GRID.new }
|
14
|
+
let(:factory) { Sudoku::GridFactory.new }
|
15
|
+
|
16
|
+
before { factory.disable_log }
|
17
|
+
|
18
|
+
context 'adding elements' do
|
19
|
+
it 'adds elements' do
|
20
|
+
test_grid.add_cell(fixed_cell)
|
21
|
+
cell_stored = test_grid.get_cell(cell_coordinates_5_5)
|
22
|
+
expect(cell_stored).not_to be_nil
|
23
|
+
expect(cell_stored.value).to eql(5)
|
24
|
+
expect(cell_stored.fixed).to be true
|
25
|
+
expect(cell_stored.coordinates == cell_coordinates_5_5).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'replaces element which exists' do
|
29
|
+
test_grid.add_cell(free_cell)
|
30
|
+
test_grid.add_cell(same_free_cell)
|
31
|
+
cell_stored = test_grid.get_cell(cell_coordinates_7_7)
|
32
|
+
|
33
|
+
expect(cell_stored.value).to eql(same_free_cell.value)
|
34
|
+
expect(cell_stored.coordinates).to eql(same_free_cell.coordinates)
|
35
|
+
expect(cell_stored.fixed).to eql(same_free_cell.fixed)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'getting elements' do
|
40
|
+
let(:grid) { Sudoku::GridFactory.new.create_random }
|
41
|
+
|
42
|
+
it 'returns default element, when element does not exist' do
|
43
|
+
cell_stored = test_grid.get_cell(cell_coordinates_7_7)
|
44
|
+
default_cell = test_grid.generate_default_cell(cell_coordinates_7_7)
|
45
|
+
|
46
|
+
expect(cell_stored.value).to eql(default_cell.value)
|
47
|
+
expect(cell_stored.coordinates).to eql(default_cell.coordinates)
|
48
|
+
expect(cell_stored.fixed).to eql(default_cell.fixed)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'misc operations' do
|
53
|
+
let(:grid) { factory.create_random }
|
54
|
+
let(:full_grid) { factory.create_full_grid }
|
55
|
+
let(:invalid_grid) do
|
56
|
+
grid = factory.create_full_grid
|
57
|
+
grid.add_cell(CELL.new(CELL_COORDINATES.new(0, 0), false, 5))
|
58
|
+
grid.add_cell(CELL.new(CELL_COORDINATES.new(1, 0), false, 5))
|
59
|
+
grid
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'test filled properly' do
|
63
|
+
expect(GRID.new.filled?).to be false
|
64
|
+
expect(Sudoku::GridFactory.new.create_full_grid.filled?).to be true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'test grid violation' do
|
68
|
+
expect(full_grid.rules_violated?).to be false
|
69
|
+
expect(invalid_grid.rules_violated?).to be true
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'test grid solved' do
|
73
|
+
expect(full_grid.solved?).to be true
|
74
|
+
expect(invalid_grid.solved?).to be false
|
75
|
+
expect(grid.solved?).to be false
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'resets cell' do
|
79
|
+
default_cell = grid.generate_default_cell(cell_coordinates_5_5)
|
80
|
+
grid.reset_cell(default_cell.coordinates)
|
81
|
+
reset_cell = grid.get_cell(default_cell.coordinates)
|
82
|
+
|
83
|
+
expect(default_cell.coordinates).to eql(reset_cell.coordinates)
|
84
|
+
expect(default_cell.value).to eql(reset_cell.value)
|
85
|
+
expect(default_cell.fixed).to eql(reset_cell.fixed)
|
86
|
+
expect(default_cell == reset_cell).to be true
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'has correct to_s method' do
|
90
|
+
path = 'spec/sudoku/model/empty_grid.txt'
|
91
|
+
empty_grid_s = GRID.new.to_s
|
92
|
+
(File.open(path).zip empty_grid_s.lines).each do |x, y|
|
93
|
+
expect(x).to eql(y)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sudoku::Solver do
|
4
|
+
SOLVER ||= Sudoku::Solver
|
5
|
+
CELL ||= Sudoku::Cell
|
6
|
+
CELL_COORDINATES ||= Sudoku::CellCoordinates
|
7
|
+
|
8
|
+
let(:factory) { Sudoku::GridFactory.new }
|
9
|
+
|
10
|
+
before do
|
11
|
+
factory.disable_log
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'cells set solving' do
|
15
|
+
let(:solver) { SOLVER.new(factory.create_full_grid) }
|
16
|
+
let(:solvable) do
|
17
|
+
(1..9).to_a.collect { |x| CELL.new(CELL_COORDINATES.random, false, x) }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'solves the 9 cells set' do
|
21
|
+
expect(solver.cells_violated?(solvable)).to be false
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does not accept invalid set' do
|
25
|
+
solvable[5].value = 4
|
26
|
+
expect(solver.cells_violated?(solvable)).to be true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/sudoku_spec.rb
ADDED
data/sudoku.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sudoku/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sudoku_bad"
|
8
|
+
spec.version = Sudoku::VERSION
|
9
|
+
spec.authors = ["Tomáš Hauk"]
|
10
|
+
spec.email = ["hauktoma@fit.cvut.cz"]
|
11
|
+
spec.summary = %q{This is a basic gem for Sudoku program.}
|
12
|
+
spec.description = %q{Dont use this software.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "require_all"
|
25
|
+
spec.add_development_dependency "guard"
|
26
|
+
spec.add_development_dependency "guard-rspec"
|
27
|
+
spec.add_development_dependency "simplecov"
|
28
|
+
spec.add_development_dependency "green_shoes"
|
29
|
+
end
|