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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d21908e8458c2569f1584e9e3f8b55ffd5907abb713ede832d1432d2ffd6df2
4
- data.tar.gz: 11d343b7e82c3bc8f679e8f60bf0eaed1986ea045b8681791da495b2d15bc459
3
+ metadata.gz: a16aa7fdc8f9a4b1eb651be7507bb91b42abb79e339f5ce0a2fa56481b8d83c4
4
+ data.tar.gz: c44cf9c0c379494ec46ebc4458ebce94590731eeee179051176c70db3cbbeb49
5
5
  SHA512:
6
- metadata.gz: 6c6353da77e5906617a5fdbe110490ec4006d1cb1ab1bd171f6ff5ab06a9ddd2d2cfbc4d21dab3c7a1000b5336c0f11512bbb6da4ed68f4be225e9f37ceb803b
7
- data.tar.gz: 64caf28995793c5a853d90f4a4ade297a761fc5b3ce10813ae3d1b215fe11e30b6e403b9cb02c93689cc9a09eb6d16cbe0ce1d9142841c37e5053c1522d3bf11
6
+ metadata.gz: 79fdeed7e19beb90ed5d14167e755a4115209e4f9e0b936d2b975c637a1820e80d99526b05dc851433083d6cc99bf7b4accf0c1b3548872206559144f449b5e2
7
+ data.tar.gz: d1cbba7f9774777b7ddbf1113eaa0cb1925b7769bf9ef65ecd9e392b621b6551b2eb2e212c392837fb5bf9641a2c0c6166c49b81f7ee934bf23d0339db296664
@@ -1,6 +1,7 @@
1
1
  require "namero/version"
2
2
  require 'namero/board'
3
3
  require 'namero/solver'
4
+ require 'namero/solver_extensions'
4
5
  require 'namero/value'
5
6
 
6
7
  module Namero
@@ -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
@@ -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 = @updated_candidate_queue.each.first
14
- break unless idx
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
@@ -1,3 +1,3 @@
1
1
  module Namero
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
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.1
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: 2018-11-17 00:00:00.000000000 Z
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
- rubyforge_project:
93
- rubygems_version: 2.7.6
93
+ rubygems_version: 3.0.3
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: ''