nonograms 0.1.1 → 0.2.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.
- data/README.md +19 -1
- data/lib/nonograms.rb +106 -1
- data/lib/nonograms/checker.rb +17 -0
- data/lib/nonograms/display.rb +29 -0
- data/lib/nonograms/version.rb +2 -2
- data/nonograms.gemspec +1 -1
- data/spec/checker_spec.rb +18 -0
- data/spec/nonograms_spec.rb +20 -1
- metadata +6 -3
- data/lib/nonograms/solver.rb +0 -104
data/README.md
CHANGED
@@ -54,6 +54,24 @@ You can solve this example when you write the code below
|
|
54
54
|
|
55
55
|
> vertical = [[1], [2, 1], [1], [], [1, 1]]
|
56
56
|
> horizontal = [[1], [2, 1], [1], [1, 1]]
|
57
|
-
> @nonograms = Nonograms
|
57
|
+
> @nonograms = Nonograms.new(horizontal, vertical)
|
58
58
|
> @nonograms.solve #=> ["01000"+"01101"+"10000"+"01001", ...]
|
59
59
|
|
60
|
+
|
61
|
+
Display result on the console
|
62
|
+
|
63
|
+
> @nonograms.display
|
64
|
+
#=> result: 0
|
65
|
+
#=>
|
66
|
+
#=> ■
|
67
|
+
#=> ■ ■ ■
|
68
|
+
#=> ■
|
69
|
+
#=> ■ ■
|
70
|
+
#=>
|
71
|
+
#=> result: 1
|
72
|
+
#=>
|
73
|
+
#=> ■
|
74
|
+
#=> ■ ■ ■
|
75
|
+
#=> ■
|
76
|
+
#=> ■ ■
|
77
|
+
|
data/lib/nonograms.rb
CHANGED
@@ -1,3 +1,108 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "nonograms/version"
|
3
|
-
require "nonograms/
|
3
|
+
require "nonograms/display"
|
4
|
+
require "nonograms/checker"
|
5
|
+
|
6
|
+
# class can solve the puzzle game Nonograms
|
7
|
+
class Nonograms
|
8
|
+
|
9
|
+
def initialize(horizontal, vertical)
|
10
|
+
@vertical = vertical
|
11
|
+
@horizontal = horizontal
|
12
|
+
@amount_row = horizontal.length
|
13
|
+
@amount_column = vertical.length
|
14
|
+
@puzzle = empty_puzzle
|
15
|
+
@results = []
|
16
|
+
end
|
17
|
+
|
18
|
+
# solve the nonograms
|
19
|
+
def solve
|
20
|
+
return @results unless @results.empty?
|
21
|
+
run_recursion
|
22
|
+
@results
|
23
|
+
end
|
24
|
+
|
25
|
+
# display the result on console
|
26
|
+
def display
|
27
|
+
Nonograms::Display.new(@results, @amount_row, @amount_column)
|
28
|
+
end
|
29
|
+
|
30
|
+
# count amount values '1' in vector
|
31
|
+
# for example:
|
32
|
+
# * vector : [0, 1, 1, 0, 0, 1, 0]
|
33
|
+
# * return: [2, 1]
|
34
|
+
def count_vector(vector)
|
35
|
+
vector.join("").scan(/[1]+/).map{|element| element.length}
|
36
|
+
end
|
37
|
+
|
38
|
+
# count amount values '1' in vertical vector
|
39
|
+
def count_vertical(column)
|
40
|
+
vertical_vector = @puzzle[0...@amount_row].map{|vector| vector[column]}
|
41
|
+
count_vector(vertical_vector)
|
42
|
+
end
|
43
|
+
|
44
|
+
# count amount values '1' in vertical vector
|
45
|
+
def count_horizontal(row)
|
46
|
+
horizontal_vector = @puzzle[row][0...@amount_column]
|
47
|
+
count_vector(horizontal_vector)
|
48
|
+
end
|
49
|
+
|
50
|
+
def vertical_acceptable?(row, column)
|
51
|
+
unless row == @amount_row-1
|
52
|
+
vector_acceptable?( @vertical[column], count_vertical(column) )
|
53
|
+
else
|
54
|
+
return ( @vertical[column] == count_vertical(column) )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def horizontal_acceptable?(row, column)
|
59
|
+
unless column == @amount_column-1
|
60
|
+
vector_acceptable?( @horizontal[row], count_horizontal(row) )
|
61
|
+
else
|
62
|
+
return ( @horizontal[row] == count_horizontal(row))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def vector_acceptable?(origin, piece)
|
67
|
+
return false if piece.length > origin.length
|
68
|
+
piece.each_with_index do |value, index|
|
69
|
+
if index == piece.length-1
|
70
|
+
return false unless origin[index] >= piece[index]
|
71
|
+
else
|
72
|
+
return false unless origin[index] == piece[index]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
|
78
|
+
# get the matrix with cells values zero
|
79
|
+
def empty_puzzle
|
80
|
+
result = []
|
81
|
+
@amount_row.times do |index|
|
82
|
+
result << [0]*@amount_column
|
83
|
+
end
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# run recursion from fixed position row and column if @puzzle is acceptable
|
90
|
+
def run_recursion(row = 0, column = 0)
|
91
|
+
return unless vertical_acceptable?(row, column) and horizontal_acceptable?(row, column)
|
92
|
+
if row == @amount_row-1 and column == @amount_column-1
|
93
|
+
@results << Marshal.load(Marshal.dump(@puzzle)).flatten.join("")
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
next_cell_set(0, row, column)
|
97
|
+
next_cell_set(1, row, column)
|
98
|
+
end
|
99
|
+
|
100
|
+
def next_cell_set(value, row, column)
|
101
|
+
new_row = (row*@amount_column + column + 1) / @amount_column
|
102
|
+
new_column = (row*@amount_column + column + 1) % @amount_column
|
103
|
+
@puzzle[new_row][new_column] = value
|
104
|
+
run_recursion(new_row, new_column)
|
105
|
+
@puzzle[new_row][new_column] = 0
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Nonograms
|
4
|
+
class Checker
|
5
|
+
|
6
|
+
def initialize(vertical, horizontal)
|
7
|
+
@vertical = vertical
|
8
|
+
@horizontal = horizontal
|
9
|
+
end
|
10
|
+
|
11
|
+
def properly_data_entered?
|
12
|
+
@vertical.flatten.inject(&:+) == @horizontal.flatten.inject(&:+)
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Nonograms
|
4
|
+
class Display
|
5
|
+
|
6
|
+
def initialize(results, amount_row, amount_column)
|
7
|
+
@results = results
|
8
|
+
@amount_row = amount_row
|
9
|
+
@amount_column = amount_column
|
10
|
+
show_results(results)
|
11
|
+
end
|
12
|
+
|
13
|
+
def show_results(results)
|
14
|
+
results.each_with_index do |result, index|
|
15
|
+
puts "result: " + index.to_s
|
16
|
+
show_result(result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def show_result(result)
|
21
|
+
result.split("").each_with_index do |value, index|
|
22
|
+
print "\n" if index % @amount_column == 0
|
23
|
+
print "■ " if value == "1"
|
24
|
+
print " " if value == "0"
|
25
|
+
end
|
26
|
+
print "\n\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/nonograms/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.
|
1
|
+
class Nonograms
|
2
|
+
VERSION = "0.2.0"
|
3
3
|
end
|
data/nonograms.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require File.expand_path('../lib/nonograms/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
|
-
gem.authors = ["
|
5
|
+
gem.authors = ["Michal Szyma"]
|
6
6
|
gem.email = ["raglub.ruby@gmail.com"]
|
7
7
|
gem.description = %q{solve the puzzle game nonograms.}
|
8
8
|
gem.summary = %q{Solve Nonograms.}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'nonograms'
|
3
|
+
|
4
|
+
describe Nonograms::Checker do
|
5
|
+
|
6
|
+
it "should return true" do
|
7
|
+
vertical = [[2, 1], [1]]
|
8
|
+
horizontal = [[1], [2], [], [1]]
|
9
|
+
Nonograms::Checker.new(vertical, horizontal).properly_data_entered?.should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return false" do
|
13
|
+
vertical = [[2, 1], [1]]
|
14
|
+
horizontal = [[1], [3], [], [1]]
|
15
|
+
Nonograms::Checker.new(vertical, horizontal).properly_data_entered?.should be_false
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/spec/nonograms_spec.rb
CHANGED
@@ -5,11 +5,30 @@ describe "Nonograms" do
|
|
5
5
|
before(:each) do
|
6
6
|
vertical = [[1], [2, 1], [1], [], [1, 1]]
|
7
7
|
horizontal = [[1], [2, 1], [1], [1, 1]]
|
8
|
-
@nonograms = Nonograms
|
8
|
+
@nonograms = Nonograms.new(horizontal, vertical)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should properly solve the nonograms" do
|
12
12
|
@nonograms.solve.should include("01000"+"01101"+"10000"+"01001")
|
13
13
|
end
|
14
14
|
|
15
|
+
it "should properly count amount of numbers 1 in vector" do
|
16
|
+
vector = [0, 0, 1, 1, 1, 0, 1]
|
17
|
+
@nonograms.count_vector(vector).should eql([3, 1])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "for vectors acceptable" do
|
21
|
+
origin = [3, 1, 2]
|
22
|
+
@nonograms.vector_acceptable?(origin, [3, 1]).should be_true
|
23
|
+
@nonograms.vector_acceptable?(origin, [3, 1, 2]).should be_true
|
24
|
+
@nonograms.vector_acceptable?(origin, [3, 1, 1]).should be_true
|
25
|
+
@nonograms.vector_acceptable?(origin, []).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "for vectors don't acceptable" do
|
29
|
+
origin = [3, 1, 2]
|
30
|
+
@nonograms.vector_acceptable?(origin, [4, 1]).should be_false
|
31
|
+
@nonograms.vector_acceptable?(origin, [3, 1, 2, 4]).should be_false
|
32
|
+
@nonograms.vector_acceptable?(origin, [3, 1, 3]).should be_false
|
33
|
+
end
|
15
34
|
end
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nonograms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Michal Szyma
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
@@ -40,9 +40,11 @@ files:
|
|
40
40
|
- README.md
|
41
41
|
- Rakefile
|
42
42
|
- lib/nonograms.rb
|
43
|
-
- lib/nonograms/
|
43
|
+
- lib/nonograms/checker.rb
|
44
|
+
- lib/nonograms/display.rb
|
44
45
|
- lib/nonograms/version.rb
|
45
46
|
- nonograms.gemspec
|
47
|
+
- spec/checker_spec.rb
|
46
48
|
- spec/nonograms_spec.rb
|
47
49
|
homepage: https://github.com/raglub/nonograms
|
48
50
|
licenses: []
|
@@ -69,4 +71,5 @@ signing_key:
|
|
69
71
|
specification_version: 3
|
70
72
|
summary: Solve Nonograms.
|
71
73
|
test_files:
|
74
|
+
- spec/checker_spec.rb
|
72
75
|
- spec/nonograms_spec.rb
|
data/lib/nonograms/solver.rb
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module Nonograms
|
3
|
-
|
4
|
-
# class can solve the puzzle game Nonograms
|
5
|
-
class Solver
|
6
|
-
|
7
|
-
attr_reader :results
|
8
|
-
|
9
|
-
def initialize(vertical, horizontal)
|
10
|
-
@vertical = vertical
|
11
|
-
@horizontal = horizontal
|
12
|
-
@amount_row = horizontal.length
|
13
|
-
@amount_column = vertical.length
|
14
|
-
@puzzle = empty_puzzle
|
15
|
-
@results = []
|
16
|
-
end
|
17
|
-
|
18
|
-
# solve the nonograms
|
19
|
-
def solve
|
20
|
-
return @results unless @results.empty?
|
21
|
-
run_recursion
|
22
|
-
@results
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# get the matrix with cells values zero
|
28
|
-
def empty_puzzle
|
29
|
-
result = []
|
30
|
-
@amount_row.times do |index|
|
31
|
-
result << [0]*@amount_column
|
32
|
-
end
|
33
|
-
result
|
34
|
-
end
|
35
|
-
|
36
|
-
# run recursion from fixed position row and column if @puzzle is acceptable
|
37
|
-
def run_recursion(row = 0, column = 0)
|
38
|
-
return unless vertical_acceptable?(row, column) and horizontal_acceptable?(row, column)
|
39
|
-
if row == @amount_row-1 and column == @amount_column-1
|
40
|
-
@results << Marshal.load(Marshal.dump(@puzzle)).flatten.join("")
|
41
|
-
return nil
|
42
|
-
end
|
43
|
-
next_cell_set(0, row, column)
|
44
|
-
next_cell_set(1, row, column)
|
45
|
-
end
|
46
|
-
|
47
|
-
def next_cell_set(value, row, column)
|
48
|
-
new_row = (row*@amount_column + column + 1) / @amount_column
|
49
|
-
new_column = (row*@amount_column + column + 1) % @amount_column
|
50
|
-
@puzzle[new_row][new_column] = value
|
51
|
-
run_recursion(new_row, new_column)
|
52
|
-
@puzzle[new_row][new_column] = 0
|
53
|
-
end
|
54
|
-
|
55
|
-
# count amount values '1' in vector
|
56
|
-
# for example:
|
57
|
-
# * vector : [0, 1, 1, 0, 0, 1, 0]
|
58
|
-
# * return: [2, 1]
|
59
|
-
def count_vector(vector)
|
60
|
-
vector.join("").scan(/[1]+/).map{|element| element.length}
|
61
|
-
end
|
62
|
-
|
63
|
-
# count amount values '1' in vertical vector
|
64
|
-
def count_vertical(column)
|
65
|
-
vertical_vector = @puzzle[0...@amount_row].map{|vector| vector[column]}
|
66
|
-
count_vector(vertical_vector)
|
67
|
-
end
|
68
|
-
|
69
|
-
# count amount values '1' in vertical vector
|
70
|
-
def count_horizontal(row)
|
71
|
-
horizontal_vector = @puzzle[row][0...@amount_column]
|
72
|
-
count_vector(horizontal_vector)
|
73
|
-
end
|
74
|
-
|
75
|
-
def vertical_acceptable?(row, column)
|
76
|
-
unless row == @amount_row-1
|
77
|
-
vector_acceptable?( @vertical[column], count_vertical(column) )
|
78
|
-
else
|
79
|
-
return ( @vertical[column] == count_vertical(column) )
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def horizontal_acceptable?(row, column)
|
84
|
-
unless column == @amount_column-1
|
85
|
-
vector_acceptable?( @horizontal[row], count_horizontal(row) )
|
86
|
-
else
|
87
|
-
return ( @horizontal[row] == count_horizontal(row))
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def vector_acceptable?(origin, piece)
|
92
|
-
return false if piece.length > origin.length
|
93
|
-
piece.each_with_index do |value, index|
|
94
|
-
if index == piece.length-1
|
95
|
-
return false unless origin[index] >= piece[index]
|
96
|
-
else
|
97
|
-
return false unless origin[index] == piece[index]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
return true
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|