phg_sudoku_solver 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.
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'phg_sudoku_solver/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "phg_sudoku_solver"
8
+ gem.version = PhgSudokuSolver::VERSION
9
+ gem.authors = ["Miles Porter"]
10
+ gem.email = ["mporter@paintedharmony.com"]
11
+ gem.description = "A simple sudoku solving utility that uses two dimensional arrays and recursion."
12
+ gem.summary = "A simple sudoku solving utility"
13
+ gem.homepage = "http://rubygems.org/gems/phg_sudoku_solver"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.license = 'MIT'
20
+ end
data/test/cell_test.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'test/unit'
2
+ require './app/extras/cell.rb'
3
+
4
+
5
+ class MyTest < Test::Unit::TestCase
6
+
7
+ # Called before every test method runs. Can be used
8
+ # to set up fixture information.
9
+ def setup
10
+ # Do nothing
11
+ end
12
+
13
+ # Called after every test method runs. Can be used to tear
14
+ # down fixture information.
15
+
16
+ def teardown
17
+ # Do nothing
18
+ end
19
+
20
+ # Cell initialize
21
+ def test_initialize_fixed_value
22
+ c = Cell.new(1)
23
+ assert(c.get_fixed_value == 1, message="Fixed value not correctly initialized")
24
+ end
25
+
26
+ def test_initialize_possible_values
27
+ c = Cell.new([1,2,3,4])
28
+ assert(c.get_possible_values==[1,2,3,4], message="Possible values not correctly initialized")
29
+ end
30
+
31
+ def test_reset_possible_values
32
+ c = Cell.new()
33
+ c.add_possible_value(1)
34
+ c.reset_possible_values
35
+ self.assert(c.get_possible_values==[], message="Possible values not reset.")
36
+ end
37
+
38
+ def test_add_possible_value
39
+ c = Cell.new()
40
+ c.add_possible_value(1)
41
+ self.assert(c.get_possible_values==[1])
42
+ c.add_possible_value(2)
43
+ self.assert(c.get_possible_values==[1,2])
44
+ end
45
+
46
+ def test_contains_candidate
47
+ c = Cell.new([1,2,3,4])
48
+ self.assert(c.contains_possible_value(2), message="Contains candidate returns false when should be true.")
49
+ self.assert(not(c.contains_possible_value(9)), message="Contains candidate returns true when should be false.")
50
+ end
51
+
52
+
53
+ def test_copy
54
+ c = Cell.new([1,2,3,4])
55
+ d = c.copy
56
+ self.assert(c.get_possible_values==d.get_possible_values, message="Copied cell contains incorrect possible values")
57
+ self.assert(c.get_fixed_value==d.get_fixed_value, message="Copied cell contains incorrect fixed values")
58
+ c.set_fixed_value(1)
59
+ self.assert(c.get_possible_values!=d.get_possible_values, message="Source cell changes corrupt copied cell.")
60
+ self.assert(c.get_fixed_value!=d.get_fixed_value, message="Source cell changes corrupt copied cell.")
61
+ end
62
+
63
+ end
@@ -0,0 +1,407 @@
1
+ require 'test/unit'
2
+ require '../lib/phg_sudoku_solver'
3
+ require '../lib/phg_sudoku_solver/cell'
4
+
5
+ class PhgSudokuSolverTest < Test::Unit::TestCase
6
+
7
+ # Called before every test method runs. Can be used
8
+ # to set up fixture information.
9
+ def setup
10
+ # Do nothing
11
+ end
12
+
13
+ # Called after every test method runs. Can be used to tear
14
+ # down fixture information.
15
+
16
+ def teardown
17
+ # Do nothing
18
+ end
19
+
20
+ # Cell initialize
21
+ def test_initialize_sudoku
22
+ a = ["5xx4x67xx",
23
+ "xxx5xx9xx",
24
+ "2xxx17x4x",
25
+ "xxx72xx1x",
26
+ "9xxxxxxx8",
27
+ "x7xx68xxx",
28
+ "x3x27xxx5",
29
+ "xx4xx3xxx",
30
+ "xx26x4xx3"]
31
+
32
+ s = Sudoku.new(a)
33
+
34
+ self.assert(s.get_fixed_value(0,0)==5, message="Incorrect value returned")
35
+ self.assert(s.get_fixed_value(0,6)==7, message="Incorrect value returned")
36
+ self.assert(s.get_fixed_value(8,2)==2, message="Incorrect value returned")
37
+ self.assert(s.get_fixed_value(8,8)==3, message="Incorrect value returned")
38
+ self.assert(s.get_fixed_value(5,4)==6, message="Incorrect value returned")
39
+ end
40
+
41
+ def test_initialize_incomplete_sudoku
42
+ a = ['123123123']
43
+
44
+ self.assert_raise(Exception){
45
+ s = Sudoku.new(a)
46
+ }
47
+
48
+ end
49
+
50
+ def test_initialize_sparse_sudoku
51
+ a = [ "5xx4x67xx",
52
+ "xxx5xx9xx",
53
+ "2xxx17x4x",
54
+ "xxx72xx1x",
55
+ "9xxxxxxx8",
56
+ "x7xx68xxx",
57
+ "x3x27xxx5",
58
+ "xx4xx3xxx",
59
+ "xx26x4xx3"]
60
+
61
+ s = Sudoku.new(a)
62
+ x=s.get_fixed_value(0,0)
63
+ self.assert(x==5, message="Incorrect value returned. Expected %s but got %s" % [5, x])
64
+
65
+ x=s.get_fixed_value(0,8)
66
+ self.assert(x==-1, message="Incorrect value returned. Expected %s but got %s" % [-1, x])
67
+
68
+ x=s.get_fixed_value(8,0)
69
+ self.assert(x==-1, message="Incorrect value returned. Expected %s but got %s" % [-1, x])
70
+
71
+ x=s.get_fixed_value(8,8)
72
+ self.assert(x==3, message="Incorrect value returned. Expected %s but got %s" % [3, x])
73
+
74
+ x=s.get_fixed_value(5,5)
75
+ self.assert(x==8, message="Incorrect value returned. Expected %s but got %s" % [8, x])
76
+ end
77
+
78
+ def test_count_fixed_values
79
+ a = [ "5xx4x67xx", #4
80
+ "xxx5xx9xx", #2
81
+ "2xxx17x4x", #4
82
+ "xxx72xx1x", #3
83
+ "9xxxxxxx8", #2
84
+ "x7xx68xxx", #3
85
+ "x3x27xxx5", #4
86
+ "xx4xx3xxx", #2
87
+ "xx26x4xx3"] #4
88
+
89
+ s = Sudoku.new(a)
90
+ self.assert(s.count_fixed_cells==28, message="Expected 18 fixed cells, but got %s" % s.count_fixed_cells)
91
+ end
92
+
93
+ def test_set_and_get_possible_values
94
+ s = Sudoku.new()
95
+ s.set_possible_values(5,5,[1,2,3])
96
+ self.assert(s.get_possible_values(5,5)==[1,2,3])
97
+ end
98
+
99
+ def test_find_row_implied_values
100
+ a = [ "51849673x",
101
+ "647532981",
102
+ "293817546",
103
+ "385729614",
104
+ "926145378",
105
+ "471368259",
106
+ "839271465",
107
+ "164953827",
108
+ "752684193"]
109
+
110
+ s = Sudoku.new(a)
111
+ s.set_possible_values(0,8,[2])
112
+ s.find_row_implied_values()
113
+ self.assert(s.get_fixed_value(0,8)==2, message="Expected fixed value of 2, got %s" % s.get_fixed_value(0,8))
114
+ end
115
+
116
+ def test_find_col_implied_values
117
+ a = [ "518496732",
118
+ "647532981",
119
+ "293817546",
120
+ "385729614",
121
+ "926145378",
122
+ "4713x8259",
123
+ "839271465",
124
+ "164953827",
125
+ "752684193"]
126
+
127
+ s = Sudoku.new(a)
128
+ s.set_possible_values(5,4,[6])
129
+ s.find_col_implied_values()
130
+ self.assert(s.get_fixed_value(5,4)==6, message="Expected fixed value of 6 in (5,4), got %s" % s.get_fixed_value(0,8))
131
+ end
132
+
133
+ def test_find_matrix_implied_values
134
+ #012345678
135
+ a = [ "518496732", #0
136
+ "6 75 29 1", #1
137
+ "293817546", #2
138
+ "385729614", #3
139
+ "9 61 53 8", #4
140
+ "471368259", #5
141
+ "839271465", #6
142
+ "1 49 38 7", #7
143
+ "752684193"] #8
144
+
145
+ s = Sudoku.new(a)
146
+ #s.set_possible_values(1,1,[4])
147
+ #s.set_possible_values(1,4,[3])
148
+ #s.set_possible_values(1,7,[8])
149
+ #s.set_possible_values(4,1,[2])
150
+ #s.set_possible_values(4,4,[4])
151
+ #s.set_possible_values(4,7,[7])
152
+ #s.set_possible_values(7,1,[6])
153
+ #s.set_possible_values(7,4,[5])
154
+ #s.set_possible_values(7,7,[3])
155
+ s.compute_possible_values
156
+ s.find_matrix_implied_values
157
+ self.assert(s.get_fixed_value(1,1)==4, message="Expected fixed value of 4 in (1,1), got %s" % s.get_fixed_value(1,1))
158
+ self.assert(s.get_fixed_value(1,4)==3, message="Expected fixed value of 3 in (1,4), got %s" % s.get_fixed_value(1,4))
159
+ self.assert(s.get_fixed_value(1,7)==8, message="Expected fixed value of 8 in (1,7), got %s" % s.get_fixed_value(1,7))
160
+ self.assert(s.get_fixed_value(4,1)==2, message="Expected fixed value of 2 in (4,1), got %s" % s.get_fixed_value(4,1))
161
+ self.assert(s.get_fixed_value(4,4)==4, message="Expected fixed value of 4 in (4,4), got %s" % s.get_fixed_value(4,4))
162
+ self.assert(s.get_fixed_value(4,7)==7, message="Expected fixed value of 7 in (4,7), got %s" % s.get_fixed_value(4,7))
163
+ self.assert(s.get_fixed_value(7,1)==6, message="Expected fixed value of 6 in (7,1), got %s" % s.get_fixed_value(7,1))
164
+ self.assert(s.get_fixed_value(7,4)==5, message="Expected fixed value of 5 in (7,4), got %s" % s.get_fixed_value(7,4))
165
+ self.assert(s.get_fixed_value(7,7)==2, message="Expected fixed value of 2 in (7,7), got %s" % s.get_fixed_value(7,7))
166
+ end
167
+
168
+ def test_row_ok
169
+ a = [ "51849673x",
170
+ "647532981",
171
+ "293817546",
172
+ "385729614",
173
+ "926145378",
174
+ "471368259",
175
+ "839271465",
176
+ "164953827",
177
+ "752684193"]
178
+ s=Sudoku.new(a)
179
+ self.assert(s.check_row_value(0,8,2), message="Row Ok Test Failed.")
180
+ end
181
+
182
+ def test_row_NOT_ok
183
+ a = [ "51849673x",
184
+ "647532981",
185
+ "293817546",
186
+ "385729614",
187
+ "926145378",
188
+ "471368259",
189
+ "839271465",
190
+ "164953827",
191
+ "752684193"]
192
+ s=Sudoku.new(a)
193
+ self.assert(not(s.check_row_value(0,8,3)), message="Row Ok and should not have been.")
194
+ end
195
+
196
+ def test_col_ok
197
+ a = [ "51849673x",
198
+ "647532981",
199
+ "293817546",
200
+ "385729614",
201
+ "926145378",
202
+ "471368259",
203
+ "839271465",
204
+ "164953827",
205
+ "752684193"]
206
+ s=Sudoku.new(a)
207
+ self.assert(s.check_col_value(0,8,2), message="Row Ok Test Failed.")
208
+ end
209
+
210
+ def test_col_NOT_ok
211
+ a = [ "51849673x",
212
+ "647532981",
213
+ "293817546",
214
+ "385729614",
215
+ "926145378",
216
+ "471368259",
217
+ "839271465",
218
+ "164953827",
219
+ "752684193"]
220
+ s=Sudoku.new(a)
221
+ self.assert(not(s.check_col_value(0,8,3)), message="Row Ok and should not have been.")
222
+ end
223
+
224
+ def test_matrix_ok
225
+ a = [ "51849673x",
226
+ "647532981",
227
+ "293817546",
228
+ "385729614",
229
+ "926145378",
230
+ "471368259",
231
+ "839271465",
232
+ "164953827",
233
+ "752684193"]
234
+ s=Sudoku.new(a)
235
+ self.assert(s.check_matrix_value(4,4,4), message="Matrix Ok Test Failed.")
236
+ end
237
+
238
+ def test_matrix_NOT_ok
239
+ a = [ "51849673x",
240
+ "647532981",
241
+ "293817546",
242
+ "385729614",
243
+ "9261x5378",
244
+ "471368259",
245
+ "839271465",
246
+ "164953827",
247
+ "752684193"]
248
+ s=Sudoku.new(a)
249
+ self.assert(not(s.check_matrix_value(4,4,5)), message="Matrix Ok and should not have been.")
250
+ end
251
+
252
+ def test_compute_possible_values_1
253
+ a = [ "51849673x",
254
+ "647532981",
255
+ "293817546",
256
+ "385729614",
257
+ "9261x5378",
258
+ "471368259",
259
+ "839271465",
260
+ "164953827",
261
+ "752684193"]
262
+ s=Sudoku.new(a)
263
+ s.compute_possible_values
264
+ self.assert(s.get_fixed_value(0,8)==2)
265
+
266
+ end
267
+
268
+ def test_compute_possible_values_2
269
+ #012345678
270
+ a = [ "1!xxxxxxx",#0
271
+ "x2xx!xxxx",#1
272
+ "xx3xxxx!x",#2
273
+
274
+ "!xx4xxxxx",#3
275
+ "xxxx5!xxx",#4
276
+ "xxxxx6xx!",#5
277
+
278
+ "xx!xxx7xx",#6
279
+ "xxx!xxx8x",#7
280
+ "xxxxxx!x9"]#8
281
+ #012345678
282
+
283
+ s=Sudoku.new(a)
284
+ s.compute_possible_values
285
+ s.dump_to_str
286
+ val = s.get_possible_values(0,1)
287
+ self.assert(s.get_possible_values(0,1)==[4,5,6,7,8,9], message="Cell 0,1 failed. %s" % s.get_possible_values(0,1))
288
+ self.assert(s.get_possible_values(1,4)==[1,3,4,6,7,8,9])
289
+ self.assert(s.get_possible_values(2,7)==[1,2,4,5,6,7,9])
290
+ self.assert(s.get_possible_values(3,0)==[2,3,5,6,7,8,9])
291
+
292
+ self.assert(s.get_possible_values(4,5)==[1,2,3,7,8,9])
293
+ self.assert(s.get_possible_values(5,8)==[1,2,3,4,5,7,8])
294
+ self.assert(s.get_possible_values(6,2)==[1,2,4,5,6,8,9])
295
+ self.assert(s.get_possible_values(7,3)==[1,2,3,5,6,7,9])
296
+ self.assert(s.get_possible_values(8,6)==[1,2,3,4,5,6])
297
+ end
298
+
299
+ def test_validate
300
+ a = [ "518496732",
301
+ "647532981",
302
+ "293817546",
303
+ "385729614",
304
+ "9261x5378",
305
+ "471368259",
306
+ "839271465",
307
+ "164953827",
308
+ "752684193"]
309
+ s=Sudoku.new(a)
310
+ self.assert(s.validate_row(0))
311
+ self.assert(s.validate_column(3))
312
+ self.assert(s.validate_matrix(4,4))
313
+ end
314
+
315
+ def test_validate_sudoku
316
+ a = [ "518496732",
317
+ "647532981",
318
+ "293817546",
319
+ "385729614",
320
+ "926145378",
321
+ "471368259",
322
+ "839271465",
323
+ "164953827",
324
+ "752684193"]
325
+ s=Sudoku.new(a)
326
+
327
+ self.assert(s.validate_sudoku, "A perfectly good sudoku fails to validate. Boo.")
328
+
329
+ end
330
+
331
+ def test_invalid_validate_sudoku
332
+ a = [ "518496732",
333
+ "647532981",
334
+ "293817546",
335
+ "385729614",
336
+ "926185378",
337
+ "471368259",
338
+ "839271465",
339
+ "164953827",
340
+ "752684193"]
341
+ self.assert_raise(Exception){
342
+ s=Sudoku.new(a)
343
+ }
344
+
345
+ end
346
+
347
+ def test_solve
348
+ a = [ "5xx4x67xx",
349
+ "xxx5xx9xx",
350
+ "2xxx17x4x",
351
+ "xxx72xx1x",
352
+ "9xxxxxxx8",
353
+ "x7xx68xxx",
354
+ "x3x27xxx5",
355
+ "xx4xx3xxx",
356
+ "xx26x4xx3"]
357
+
358
+ s = Sudoku.new(a)
359
+ s.set_debug(true)
360
+ s.set_debug(false)
361
+ solved, total_iterations = s.solve()
362
+ self.assert(solved.validate_sudoku, "Solved sudoku is invalid!!!")
363
+ self.assert(solved.count_fixed_cells==81, "Sudoku is incomplete!!!")
364
+
365
+ end
366
+
367
+ def test_copy
368
+ a = [ "5xx4x67xx",
369
+ "xxx5xx9xx",
370
+ "2xxx17x4x",
371
+ "xxx72xx1x",
372
+ "9xxxxxxx8",
373
+ "x7xx68xxx",
374
+ "x3x27xxx5",
375
+ "xx4xx3xxx",
376
+ "xx26x4xx3"]
377
+ s1 = Sudoku.new(a)
378
+ s2 = s1.copy
379
+ for r in (0..8)
380
+ for c in (0..8)
381
+ self.assert(s1.get_fixed_value(r,c) == s2.get_fixed_value(r,c))
382
+ self.assert(s1.get_possible_values(r,c)==s2.get_possible_values(r,c))
383
+ end
384
+ end
385
+
386
+ end
387
+
388
+ def test_too_long_solve
389
+ a = [ "123 789 456",
390
+ "456 123 789",
391
+ "789 456 123",
392
+
393
+ "xxx xxx xxx",
394
+ "xxx xxx xxx",
395
+ "xxx xxx 231",
396
+
397
+ "xxx xxx xxx",
398
+ "xxx xxx xxx",
399
+ "xxx xxx xxx"]
400
+ s1 = Sudoku.new(a)
401
+ s1.set_max_iterations(100)
402
+ self.assert_raise(Exception) {
403
+ s1.solve() }
404
+ end
405
+
406
+
407
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: phg_sudoku_solver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Miles Porter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A simple sudoku solving utility that uses two dimensional arrays and
14
+ recursion.
15
+ email:
16
+ - mporter@paintedharmony.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - .idea/.name
23
+ - .idea/.rakeTasks
24
+ - .idea/codeStyleSettings.xml
25
+ - .idea/encodings.xml
26
+ - .idea/inspectionProfiles/Project_Default.xml
27
+ - .idea/inspectionProfiles/profiles_settings.xml
28
+ - .idea/misc.xml
29
+ - .idea/modules.xml
30
+ - .idea/phg_sudoku_solver.iml
31
+ - .idea/scopes/scope_settings.xml
32
+ - .idea/vcs.xml
33
+ - .idea/workspace.xml
34
+ - Gemfile
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - lib/phg_sudoku_solver.rb
39
+ - lib/phg_sudoku_solver/cell.rb
40
+ - lib/phg_sudoku_solver/version.rb
41
+ - phg_sudoku_solver.gemspec
42
+ - test/cell_test.rb
43
+ - test/sudoku_test.rb
44
+ homepage: http://rubygems.org/gems/phg_sudoku_solver
45
+ licenses:
46
+ - MIT
47
+ metadata: {}
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 2.1.7
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: A simple sudoku solving utility
68
+ test_files:
69
+ - test/cell_test.rb
70
+ - test/sudoku_test.rb