phg_sudoku_solver 0.0.2 → 0.0.3

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 CHANGED
@@ -1,13 +1,15 @@
1
1
  # PhgSudokuSolver
2
2
 
3
- Welcome to the PHG Sudoku Solver gem.
3
+ ##A simple little gem for solving sudoku puzzles.##
4
4
 
5
- Miles Porter
6
- Senior Software Consultant
7
- Painted Harmony Group, Inc.
8
- mporter(AT)paintedharmony(DOT)com
5
+ **Miles Porter**<br>
6
+ **Senior Software Consultant**<br>
7
+ **Painted Harmony Group, Inc.**<br>
8
+ **mporter@paintedharmony.com**<br>
9
9
 
10
- "I first started doing Sudoku puzzles a few years ago while on a 3 hour plane flight. I was hooked. Eventually, I came
10
+
11
+ # Background:
12
+ I first started doing Sudoku puzzles a few years ago while on a 3 hour plane flight. I was hooked. Eventually, I came
11
13
  across a Sudoku that I could not do. I was completely frustrated, and the puzzle that I was working on was printed in a
12
14
  weekly newspaper and I didn't want to wait an entire week to see the solution. So, I did what any good software engineer
13
15
  would do... I decided to write a program/algorithm to solve the puzzle. At first, I tried the brute-force method of
@@ -34,84 +36,84 @@ Or install it yourself as:
34
36
 
35
37
  The following snipit illustrates show to use this gem (taken from tests, mind you.)
36
38
 
37
- ± irb
38
- 1.9.3p194 :001 > require 'phg_sudoku_solver'
39
- => true
40
- 1.9.3p194 :002 >
41
- 1.9.3p194 :003 > a = [ "5xx4x67xx", "xxx5xx9xx", "2xxx17x4x", "xxx72xx1x", "9xxxxxxx8", "x7xx68xxx", "x3x27xxx5", "xx4xx3xxx","xx26x4xx3"]
42
- => ["5xx4x67xx", "xxx5xx9xx", "2xxx17x4x", "xxx72xx1x", "9xxxxxxx8", "x7xx68xxx", "x3x27xxx5", "xx4xx3xxx", "xx26x4xx3"]
43
- 1.9.3p194 :004 >
44
- 1.9.3p194 :005 > s = Sudoku.new(a)
45
39
 
46
- [blah blah blah]
40
+ Create a new Sudoku instance by passing in an array of 9 strings. Each string needs to be 9 characters. Any non-
41
+ numeric character (1-9) is considered to be an unsolved cell. You can use spaces, Xs or whatever you like.
47
42
 
48
- 1.9.3p194 :010 > x = s.solve
43
+ Call the `.solve` method on the sudoku instance that you create.
49
44
 
50
- [blah blah blah]
45
+ To get the results of the solved sudoku, you can
46
+ 1) Call the '.dump_known_cells_str' method, which will return a formatted string that represents the solved puzzle.
47
+ 2) Iterate over the '.get_fixed_value(r,c)' method, where r and c represent the row and column. The data returned
48
+ will be the value found for that cell.
51
49
 
52
- x.dump_known_cells_str
53
- => "\\n 5 1 8 | 4 9 6 | 7 3 2 \\n
54
- 6 4 7 | 5 3 2 | 9 8 1 \\n
55
- 2 9 3 | 8 1 7 | 5 4 6 \\n
56
- ----------------------------------------\\n
57
- 3 8 5 | 7 2 9 | 6 1 4 \\n
58
- 9 2 6 | 1 4 5 | 3 7 8 \\n
59
- 4 7 1 | 3 6 8 | 2 5 9 \\n
60
- ----------------------------------------\\n
61
- 8 3 9 | 2 7 1 | 4 6 5 \\n
62
- 1 6 4 | 9 5 3 | 8 2 7 \\n
63
- 7 5 2 | 6 8 4 | 1 9 3 \\n"
64
50
 
65
- (Note: The display has been cleaned up a bit above.)
51
+ Example from irb...
66
52
 
67
- Notes:
68
- Create a new Sudoku instance by passing in an array of 9 strings. Each string needs to be 9 characters. Any non-
69
- numeric character (1-9) is considered to be an unsolved cell. You can use spaces, Xs or whatever you like.
53
+ <pre>
54
+ require 'phg_sudoku_solver'
55
+ a = [ "5xx4x67xx",
56
+ "xxx5xx9xx",
57
+ "2xxx17x4x",
58
+ "xxx72xx1x",
59
+ "9xxxxxxx8",
60
+ "x7xx68xxx",
61
+ "x3x27xxx5",
62
+ "xx4xx3xxx",
63
+ "xx26x4xx3"]
70
64
 
71
- Call the .solve method on the sudoku instance that you create.
65
+ s = Sudoku.new(a)
72
66
 
73
- To get the results of the solved sudoku, you can
74
- 1) Call the .dump_known_cells_str method, which will return a formatted string that represents the solved puzzle.
75
- 2) Iterate over the .get_fixed_value(r,c) method, where r and c represent the row and column. The data returned
76
- will be the value found for that cell.
67
+ x = s.solve
68
+
69
+ x.dump_known_cells_str
77
70
 
78
- WHEN SOMETHING GOES WRONG... AND SOMETHING ALWAYS GOES WRONG...
71
+ 5 1 8 | 4 9 6 | 7 3 2
72
+ 6 4 7 | 5 3 2 | 9 8 1
73
+ 2 9 3 | 8 1 7 | 5 4 6
74
+ ----------------------------------------
75
+ 3 8 5 | 7 2 9 | 6 1 4
76
+ 9 2 6 | 1 4 5 | 3 7 8
77
+ 4 7 1 | 3 6 8 | 2 5 9
78
+ ----------------------------------------
79
+ 8 3 9 | 2 7 1 | 4 6 5
80
+ 1 6 4 | 9 5 3 | 8 2 7
81
+ 7 5 2 | 6 8 4 | 1 9 3
82
+ </pre>
83
+ Note: The display has been cleaned up a bit above.
79
84
 
80
- 1. If the sudoku entered is invalid, the solve method will return an error.
85
+ ## WHEN SOMETHING GOES WRONG... AND SOMETHING ALWAYS GOES WRONG...
81
86
 
82
- 1.9.3p194 :015 > a = ['123123123']
83
- => ["123123123"]
84
- 1.9.3p194 :016 > s = Sudoku.new(a)
85
- Exception: Sudoku entered appears to be invalid.
86
- from /Users/miles_r_porter/.rvm/gems/ruby-1.9.3-p194/gems/phg_sudoku_solver-0.0.2/lib/phg_sudoku_solver.rb:47:in `initialize'
87
- from (irb):16:in `new'
88
- from (irb):16
89
- from /Users/miles_r_porter/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
90
- 1.9.3p194 :017 >
87
+ 1. If the sudoku entered is invalid, the solve method will return an error.
91
88
 
92
- 2. Some sudoku are just to complex for the engine to compute a solution in the given maximum iterations
89
+ <pre>
90
+ a = ['123123123']
91
+ s = Sudoku.new(a)
92
+ Exception: Sudoku entered appears to be invalid.
93
+ ...
94
+ </pre>
93
95
 
94
- 1.9.3p194 :018 > a = ["123456789","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx"]
95
- => ["123456789", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx", "xxxxxxxxx"]
96
- 1.9.3p194 :019 > s = Sudoku.new(a)
96
+ 2. Some sudoku are just to complex for the engine to compute a solution in the given maximum iterations
97
97
 
98
- [blah blah blah]
98
+ <pre>
99
+ a = ["123456789","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx","xxxxxxxxx"]
100
+ s = Sudoku.new(a)
101
+ x = s.solve
102
+ Exception: Solution taking too long!
103
+ </pre>
99
104
 
100
- 1.9.3p194 :020 > x = s.solve()
101
105
 
102
- 1.9.3p194 :012 > x = s.solve
103
- Exception: Solution taking too long!\n\n
104
106
 
105
- Note: The number of iterations are checked after each recursion, so there total iterations may exceed the max
106
- iterations set.
107
+ Note: The number of iterations are checked after each recursion, so there total iterations may exceed the max
108
+ iterations set. You can set the max iterations like this:
107
109
 
108
- Oh... and you can set the max iterations:
110
+ `s.set_max_iterations(500)`
109
111
 
110
- s.set_max_iterations(500)
112
+ I have created a sample app running on Heroku (that includes a link to source code) that uses the gem...
111
113
 
112
- for example.
114
+ [Sample App Running On Heroku](https://sudoku-solver-2.herokuapp.com/)
113
115
 
114
- More features will be released at some point. Enjoy!
116
+ More features will be released at some point. Enjoy!
115
117
 
116
118
 
117
119
  ## Contributing
@@ -83,11 +83,13 @@ class Sudoku
83
83
  def solve
84
84
  iteration=0
85
85
  no_progress_count = 0
86
+ print_debug 'Max Iterations = %s' % @max_iterations
86
87
 
87
88
  while @solved_cell_count!=81
88
89
  iteration+=1
89
90
  @total_iterations+=1
90
91
  print_debug 'Iteration: %s SolvedCells: %s\n' % [iteration, @solved_cell_count]
92
+ puts dump_known_cells_str
91
93
  compute_possible_values()
92
94
 
93
95
  begin
@@ -311,24 +313,26 @@ class Sudoku
311
313
 
312
314
  def recurse
313
315
  recurse = copy()
314
- (0..8).each { |r|
315
- (0..8).each { |c|
316
- if (recurse.get_fixed_value(r, c)<=0) and (recurse.get_possible_values(r, c).count>0)
317
- (0..recurse.get_possible_values(r, c).count).each { |j|
318
- unless recurse.get_possible_values(r, c)[j].nil?
319
- print_debug '\nStarting recursion with (%s,%s) set to %s\n' % [r, c, recurse.get_possible_values(r, c)[j]]
320
- recurse.set_fixed_value(r, c, recurse.get_possible_values(r, c)[j])
321
- print_debug('Recursion starting...')
322
- recurse, iterations = recurse.solve
323
- @total_iterations = @total_iterations + iterations
324
- if recurse!=nil
325
- return recurse
326
- else
327
- recurse = copy()
316
+ (2..8).each { |guesses|
317
+ (0..8).each { |r|
318
+ (0..8).each { |c|
319
+ if (recurse.get_possible_values(r, c).count==guesses) #Staring with cells that have the fewest to solve.
320
+ (0..recurse.get_possible_values(r, c).count).each { |j|
321
+ unless recurse.get_possible_values(r, c)[j].nil?
322
+ print_debug '\nStarting recursion with (%s,%s) set to %s\n' % [r, c, recurse.get_possible_values(r, c)[j]]
323
+ recurse.set_fixed_value(r, c, recurse.get_possible_values(r, c)[j])
324
+ print_debug('Recursion starting...')
325
+ recurse, iterations = recurse.solve
326
+ @total_iterations = @total_iterations + iterations
327
+ if recurse!=nil
328
+ return recurse
329
+ else
330
+ recurse = copy()
331
+ end
328
332
  end
329
- end
330
- }
331
- end
333
+ }
334
+ end
335
+ }
332
336
  }
333
337
  }
334
338
  print_debug('Dead end found.\n')
@@ -483,7 +487,7 @@ class Sudoku
483
487
 
484
488
  def print_debug(message)
485
489
  if @debug
486
- print message
490
+ puts message + '\n'
487
491
  end
488
492
  end
489
493
 
@@ -1,3 +1,3 @@
1
1
  module PhgSudokuSolver
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/test/sudoku_test.rb CHANGED
@@ -19,7 +19,7 @@ class PhgSudokuSolverTest < Test::Unit::TestCase
19
19
 
20
20
  # Cell initialize
21
21
  def test_initialize_sudoku
22
- a = ["5xx4x67xx",
22
+ a = ["5xx4x67xx",
23
23
  "xxx5xx9xx",
24
24
  "2xxx17x4x",
25
25
  "xxx72xx1x",
@@ -386,22 +386,41 @@ class PhgSudokuSolverTest < Test::Unit::TestCase
386
386
  end
387
387
 
388
388
  def test_too_long_solve
389
- a = [ "123 789 456",
390
- "456 123 789",
391
- "789 456 123",
389
+ a = [ "123789456",
390
+ "456123789",
391
+ "789456123",
392
392
 
393
- "xxx xxx xxx",
394
- "xxx xxx xxx",
395
- "xxx xxx 231",
393
+ "xxxxxxxxx",
394
+ "xxxxxxxxx",
395
+ "xxxxxx231",
396
396
 
397
- "xxx xxx xxx",
398
- "xxx xxx xxx",
399
- "xxx xxx xxx"]
397
+ "xxxxxxxxx",
398
+ "xxxxxxxxx",
399
+ "xxxxxxxxx"]
400
400
  s1 = Sudoku.new(a)
401
- s1.set_max_iterations(100)
401
+ s1.set_max_iterations(10)
402
402
  self.assert_raise(Exception) {
403
403
  s1.solve() }
404
404
  end
405
405
 
406
+ def test_solve_super_hard
407
+ a = [ "xx8xx3xx5",
408
+ "xxxx4x9xx",
409
+ "x4x8xx7xx",
410
+ "xx3x5xx68",
411
+ "xxx462xxx",
412
+ "27xx3x4xx",
413
+ "xx4xx6x2x",
414
+ "xx1x9xxxx",
415
+ "8xx3xx6xx"]
416
+
417
+ s = Sudoku.new(a)
418
+ s.set_max_iterations(10000)
419
+ s.set_debug(true)
420
+ solved, total_iterations = s.solve()
421
+ puts "Got to here."
422
+ puts solved.dump_to_str
423
+ self.assert(solved.validate_sudoku, "Solved sudoku is invalid!!!")
424
+ end
406
425
 
407
426
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phg_sudoku_solver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Porter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-10 00:00:00.000000000 Z
11
+ date: 2015-03-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple sudoku solving utility that uses two dimensional arrays and
14
14
  recursion.
@@ -51,17 +51,17 @@ require_paths:
51
51
  - lib
52
52
  required_ruby_version: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ! '>='
54
+ - - '>='
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  required_rubygems_version: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  requirements: []
63
63
  rubyforge_project:
64
- rubygems_version: 2.1.7
64
+ rubygems_version: 2.4.5
65
65
  signing_key:
66
66
  specification_version: 4
67
67
  summary: A simple sudoku solving utility