namero 0.0.1 → 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 +4 -4
- data/lib/namero.rb +1 -0
- data/lib/namero/board.rb +94 -1
- data/lib/namero/solver.rb +11 -4
- data/lib/namero/solver_extensions.rb +50 -0
- data/lib/namero/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a16aa7fdc8f9a4b1eb651be7507bb91b42abb79e339f5ce0a2fa56481b8d83c4
|
4
|
+
data.tar.gz: c44cf9c0c379494ec46ebc4458ebce94590731eeee179051176c70db3cbbeb49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79fdeed7e19beb90ed5d14167e755a4115209e4f9e0b936d2b975c637a1820e80d99526b05dc851433083d6cc99bf7b4accf0c1b3548872206559144f449b5e2
|
7
|
+
data.tar.gz: d1cbba7f9774777b7ddbf1113eaa0cb1925b7769bf9ef65ecd9e392b621b6551b2eb2e212c392837fb5bf9641a2c0c6166c49b81f7ee934bf23d0339db296664
|
data/lib/namero.rb
CHANGED
data/lib/namero/board.rb
CHANGED
@@ -2,6 +2,21 @@ module Namero
|
|
2
2
|
class Board
|
3
3
|
attr_reader :n
|
4
4
|
|
5
|
+
# ..4.
|
6
|
+
# ...1
|
7
|
+
# 4...
|
8
|
+
# 21..
|
9
|
+
def self.load_from_string(str, n)
|
10
|
+
values = str.split("\n").map(&:chars).flatten.map.with_index do |v, idx|
|
11
|
+
if v == '.'
|
12
|
+
Namero::Value.new(value: nil, candidates: (1..n).to_a, index: idx)
|
13
|
+
else
|
14
|
+
Namero::Value.new(value: Integer(v), candidates: [Integer(v)], index: idx)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
Namero::Board.new(n: n, values: values)
|
18
|
+
end
|
19
|
+
|
5
20
|
# n: Integer
|
6
21
|
# values: Array<Integer>
|
7
22
|
def initialize(n:, values: Array.new(n**2))
|
@@ -86,10 +101,88 @@ module Namero
|
|
86
101
|
end
|
87
102
|
end
|
88
103
|
|
104
|
+
def each_affected_group
|
105
|
+
return enum_for(__method__) unless block_given?
|
106
|
+
|
107
|
+
n.times do |i|
|
108
|
+
yield self[i, :column]
|
109
|
+
yield self[i * n, :row]
|
110
|
+
yield self[(i % root_n) * root_n + (i / root_n) * n * root_n, :block]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
89
114
|
def complete?
|
90
|
-
@values.all? do |v|
|
115
|
+
all_filled = @values.all? do |v|
|
91
116
|
v.value
|
92
117
|
end
|
118
|
+
return false unless all_filled
|
119
|
+
|
120
|
+
return each_affected_group.all? do |group|
|
121
|
+
group.map(&:value).uniq.size == n
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_s(mode: :simple)
|
126
|
+
out = +""
|
127
|
+
case mode
|
128
|
+
when :simple
|
129
|
+
@values.each.with_index do |v, idx|
|
130
|
+
if v.value
|
131
|
+
out << (v.value).to_s
|
132
|
+
else
|
133
|
+
out << '.'
|
134
|
+
end
|
135
|
+
out << "\n" if idx % n == n - 1
|
136
|
+
end
|
137
|
+
when :with_candidates
|
138
|
+
@values.each.each_slice(n).with_index do |values, index|
|
139
|
+
values.each_slice(root_n) do |values2|
|
140
|
+
values2.each do |v|
|
141
|
+
if v.value
|
142
|
+
out << '***'
|
143
|
+
else
|
144
|
+
out << (v.candidates.include?(1) ? '1' : '.')
|
145
|
+
out << (v.candidates.include?(2) ? '2' : '.')
|
146
|
+
out << (v.candidates.include?(3) ? '3' : '.')
|
147
|
+
end
|
148
|
+
out << ' '
|
149
|
+
end
|
150
|
+
out << ' | '
|
151
|
+
end
|
152
|
+
out << "\n"
|
153
|
+
values.each_slice(root_n) do |values2|
|
154
|
+
values2.each do |v|
|
155
|
+
if v.value
|
156
|
+
out << "*#{v.value}*"
|
157
|
+
else
|
158
|
+
out << (v.candidates.include?(4) ? '4' : '.')
|
159
|
+
out << (v.candidates.include?(5) ? '5' : '.')
|
160
|
+
out << (v.candidates.include?(6) ? '6' : '.')
|
161
|
+
end
|
162
|
+
out << ' '
|
163
|
+
end
|
164
|
+
out << ' | '
|
165
|
+
end
|
166
|
+
out << "\n"
|
167
|
+
values.each_slice(root_n) do |values2|
|
168
|
+
values2.each do |v|
|
169
|
+
if v.value
|
170
|
+
out << '***'
|
171
|
+
else
|
172
|
+
out << (v.candidates.include?(7) ? '7' : '.')
|
173
|
+
out << (v.candidates.include?(8) ? '8' : '.')
|
174
|
+
out << (v.candidates.include?(9) ? '9' : '.')
|
175
|
+
end
|
176
|
+
out << ' '
|
177
|
+
end
|
178
|
+
out << ' | '
|
179
|
+
end
|
180
|
+
out << "\n#{'-' * ((root_n + 1) * n + (root_n) * 3) if index % root_n == root_n - 1}\n"
|
181
|
+
end
|
182
|
+
else
|
183
|
+
raise "unknown mode: #{mode}"
|
184
|
+
end
|
185
|
+
out
|
93
186
|
end
|
94
187
|
|
95
188
|
private
|
data/lib/namero/solver.rb
CHANGED
@@ -2,16 +2,23 @@ require 'set'
|
|
2
2
|
|
3
3
|
module Namero
|
4
4
|
class Solver
|
5
|
-
def initialize(board)
|
5
|
+
def initialize(board, extensions: [])
|
6
6
|
@board = board
|
7
7
|
@updated_candidate_queue = Set.new
|
8
|
+
@extensions = extensions
|
8
9
|
end
|
9
10
|
|
10
11
|
def solve
|
11
12
|
fill_candidates
|
12
13
|
loop do
|
13
|
-
idx =
|
14
|
-
|
14
|
+
idx = updated_candidate_queue.each.first
|
15
|
+
unless idx
|
16
|
+
extensions.each do |ex|
|
17
|
+
ex.solve(board, updated_candidate_queue)
|
18
|
+
end
|
19
|
+
break if updated_candidate_queue.empty?
|
20
|
+
next
|
21
|
+
end
|
15
22
|
@updated_candidate_queue.delete idx
|
16
23
|
fill_one_candidate(idx)
|
17
24
|
end
|
@@ -19,7 +26,7 @@ module Namero
|
|
19
26
|
|
20
27
|
private
|
21
28
|
|
22
|
-
attr_reader :board, :updated_candidate_queue
|
29
|
+
attr_reader :board, :updated_candidate_queue, :extensions
|
23
30
|
|
24
31
|
def fill_one_candidate(idx)
|
25
32
|
v = board[idx]
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Namero
|
2
|
+
module SolverExtensions
|
3
|
+
# If a candidate number exists only one place in an affected group,
|
4
|
+
# we can fill the box.
|
5
|
+
# For example:
|
6
|
+
# When candidates are: [1 2 3] [2 3] [1 2 3] [1 2 3 4]
|
7
|
+
# The last box's value is 4 because there is 4 candidate only the last box.
|
8
|
+
class CandidateExistsOnlyOnePlace
|
9
|
+
def self.solve(board, queue)
|
10
|
+
self.new(board, queue).solve
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(board, queue)
|
14
|
+
@board = board
|
15
|
+
@queue = queue
|
16
|
+
end
|
17
|
+
|
18
|
+
def solve
|
19
|
+
board.each_affected_group do |group|
|
20
|
+
(1..n).each do |v|
|
21
|
+
box = nil
|
22
|
+
group.each do |value|
|
23
|
+
if value.candidates.include?(v) && value.value.nil?
|
24
|
+
if box
|
25
|
+
box = nil
|
26
|
+
break
|
27
|
+
else
|
28
|
+
box = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if box
|
34
|
+
box.candidates = [v]
|
35
|
+
queue << box.index
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :board, :queue
|
44
|
+
|
45
|
+
def n
|
46
|
+
board.n
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/namero/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: namero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masataka Pocke Kuwabara
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/namero.rb
|
69
69
|
- lib/namero/board.rb
|
70
70
|
- lib/namero/solver.rb
|
71
|
+
- lib/namero/solver_extensions.rb
|
71
72
|
- lib/namero/value.rb
|
72
73
|
- lib/namero/version.rb
|
73
74
|
- namero.gemspec
|
@@ -89,8 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
90
|
- !ruby/object:Gem::Version
|
90
91
|
version: '0'
|
91
92
|
requirements: []
|
92
|
-
|
93
|
-
rubygems_version: 2.7.6
|
93
|
+
rubygems_version: 3.0.3
|
94
94
|
signing_key:
|
95
95
|
specification_version: 4
|
96
96
|
summary: ''
|