namero 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: ''