euler 1.0.8 → 1.1.0

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/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
- pkg/*
2
+ pkg/*
3
+ rdoc/*
@@ -1,18 +1,37 @@
1
1
  = euler
2
2
 
3
- Description goes here.
3
+ == DESCRIPTION
4
4
 
5
- == Note on Patches/Pull Requests
5
+ libeuler is a simple library you can include in your code to take away some of the boring repetitive parts of solving Project Euler problems.
6
+
7
+ == FEATURES
8
+
9
+ * Adds various methods to the Integer class, such as factorial, prime?, is_fibonacci?, etc.
10
+ * Provides various module methods, such as generate_sieve, get_primes, etc.
11
+
12
+ == SYNOPSIS
13
+
14
+ require 'rubygems'
15
+ require 'euler'
16
+
17
+ 5.factorial # => 120
18
+
19
+ == REQUIREMENTS
20
+
21
+ * none
22
+
23
+ == INSTALL
24
+
25
+ * sudo gem install euler
26
+
27
+ == COLLABORATION
6
28
 
7
29
  * Fork the project.
8
30
  * Make your feature addition or bug fix.
9
- * Add tests for it. This is important so I don't break it in a
10
- future version unintentionally.
11
- * Commit, do not mess with rakefile, version, or history.
12
- (if you want to have your own version, that is fine but
13
- bump version in a commit by itself I can ignore when I pull)
31
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
32
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
14
33
  * Send me a pull request. Bonus points for topic branches.
15
34
 
16
- == Copyright
35
+ == COPYRIGHT
17
36
 
18
- Copyright (c) 2009 Mike Skalnik. See LICENSE for details.
37
+ Copyright (c) 2009 Mike Skalnik, Nick Kezhaya. See LICENSE for details.
data/Rakefile CHANGED
@@ -9,8 +9,14 @@ begin
9
9
  gem.description = %Q{A gem that provides a small library to help in removing the repetativeness of solving Project Euler problems.}
10
10
  gem.email = "mike.skalnik@gmail.com"
11
11
  gem.homepage = "http://github.com/skalnik/euler"
12
- gem.authors = ["Mike Skalnik"]
12
+ gem.authors = ["Mike Skalnik", "Nick Kezhaya"]
13
+ gem.rubyforge_project = 'euler'
13
14
  end
15
+
16
+ Jeweler::RubyforgeTasks.new do |rubyforge|
17
+ rubyforge.doc_task = 'rdoc'
18
+ end
19
+ Jeweler::GemcutterTasks.new
14
20
  rescue LoadError
15
21
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
16
22
  end
@@ -51,4 +57,4 @@ Rake::RDocTask.new do |rdoc|
51
57
  rdoc.title = "euler #{version}"
52
58
  rdoc.rdoc_files.include('README*')
53
59
  rdoc.rdoc_files.include('lib/**/*.rb')
54
- end
60
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.8
1
+ 1.1.0
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{euler}
8
+ s.version = "1.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Mike Skalnik", "Nick Kezhaya"]
12
+ s.date = %q{2009-10-11}
13
+ s.description = %q{A gem that provides a small library to help in removing the repetativeness of solving Project Euler problems.}
14
+ s.email = %q{mike.skalnik@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "euler.gemspec",
26
+ "lib/euler.rb",
27
+ "lib/rudoku.rb",
28
+ "test/tc_integer_methods.rb",
29
+ "test/tc_module.rb",
30
+ "test/tc_rudoku.rb",
31
+ "test/test_euler.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/skalnik/euler}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubyforge_project = %q{euler}
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = %q{A small library to help solve Projet Euler problems.}
39
+ s.test_files = [
40
+ "test/tc_integer_methods.rb",
41
+ "test/tc_module.rb",
42
+ "test/tc_rudoku.rb",
43
+ "test/test_euler.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
@@ -173,7 +173,25 @@ module Euler
173
173
  return Math.sqrt(c**2 - a**2) if b.nil?
174
174
  return Math.sqrt(a**2 + b**2) if c.nil?
175
175
  end
176
-
176
+
177
+ # Solves a Sudoku puzzle passed in as a 2D array.
178
+ # Euler.solve_sudoku(
179
+ # [[0, 0, 3, 0, 2, 0, 6, 0, 0],
180
+ # [9, 0, 0, 3, 0, 5, 0, 0, 1],
181
+ # [0, 0, 1, 8, 0, 6, 4, 0, 0],
182
+ # [0, 0, 8, 1, 0, 2, 9, 0, 0],
183
+ # [7, 0, 0, 0, 0, 0, 0, 0, 8],
184
+ # [0, 0, 6, 7, 0, 8, 2, 0, 0],
185
+ # [0, 0, 2, 6, 0, 9, 5, 0, 0],
186
+ # [8, 0, 0, 2, 0, 3, 0, 0, 9],
187
+ # [0, 0, 5, 0, 1, 0, 3, 0, 0]]
188
+ # ) # => [[4, 8, 3, 9, 2, 1, 6, 5, 7], [9, 6, 7, 3, 4, 5, 8, 2, 1], [2, 5, 1, 8, 7, 6, 4, 9, 3], [5, 4, 8, 1, 3, 2, 9, 7, 6], [7, 2, 9, 5, 6, 4, 1, 3, 8], [1, 3, 6, 7, 9, 8, 2, 4, 5], [3, 7, 2, 6, 8, 9, 5, 1, 4], [8, 1, 4, 2, 5, 3, 7, 6, 9], [6, 9, 5, 4, 1, 7, 3, 8, 2]]
189
+ def solve_sudoku(puzzle)
190
+ require File.dirname(__FILE__) + "/rudoku"
191
+ rudoku = Rudoku.new(puzzle)
192
+ rudoku.backtrack_solve
193
+ rudoku.to_a
194
+ end
177
195
  end
178
196
 
179
197
  # Just adds Euler::IntegerMethods to the Integer class.
@@ -0,0 +1,178 @@
1
+ class Rudoku
2
+ def initialize(sudoku)
3
+ @n = sudoku.size
4
+ @sqrt_n = Math.sqrt(@n).to_i
5
+ raise "wrong sudoku size" unless @sqrt_n * @sqrt_n == @n
6
+
7
+ @arr = sudoku.collect { |row|
8
+ (0...@n).collect { |i|
9
+ ((1..@n) === row[i]) ? [row[i]] : (1..@n).to_a
10
+ }
11
+ }
12
+
13
+ @rfix = Array.new(@n) { [] }
14
+ @cfix = Array.new(@n) { [] }
15
+ @bfix = Array.new(@n) { [] }
16
+ @n.times { |r| @n.times { |c| update_fix(r, c) } }
17
+
18
+ [@rfix, @cfix, @bfix].each { |fix| fix.each { |x|
19
+ unless x.size == x.uniq.size
20
+ raise "non-unique numbers in row, col or box"
21
+ end
22
+ } }
23
+ end
24
+
25
+ def solve
26
+ begin
27
+ until finished?
28
+ progress = false
29
+ while reduce
30
+ progress = true
31
+ end
32
+ progress = true if deduce
33
+ return :unknown unless progress
34
+ end
35
+ :solved
36
+ rescue
37
+ :impossible
38
+ end
39
+ end
40
+
41
+ def backtrack_solve
42
+ if (res = solve) == :unknown
43
+ r, c = 0, 0
44
+ @rfix.each_with_index { |rf, r|
45
+ break if rf.size < @n
46
+ }
47
+ @arr[r].each_with_index { |x, c|
48
+ break if x.size > 1
49
+ }
50
+ partial = to_a
51
+ solutions = []
52
+ @arr[r][c].each { |guess|
53
+ partial[r][c] = guess
54
+ rsolver = Rudoku.new(partial)
55
+ case rsolver.backtrack_solve
56
+ when :multiple_solutions
57
+ initialize(rsolver.to_a)
58
+ return :multiple_solutions
59
+ when :solved
60
+ solutions << rsolver
61
+ end
62
+ }
63
+ if solutions.empty?
64
+ return :impossible
65
+ else
66
+ initialize(solutions[0].to_a)
67
+ return solutions.size > 1 ? :multiple_solutions : :solved
68
+ end
69
+ end
70
+ res
71
+ end
72
+
73
+ def to_a
74
+ @arr.collect { |row| row.collect { |x|
75
+ (x.size == 1) ? x[0] : nil
76
+ } }
77
+ end
78
+
79
+ def to_s
80
+ fw = @n.to_s.size
81
+ to_a.collect { |row| row.collect { |x|
82
+ (x ? x.to_s : "_").rjust(fw)
83
+ }.join " " }.join "\n"
84
+ end
85
+
86
+ def finished?
87
+ @arr.each { |row| row.each { |x| return false if x.size > 1 } }
88
+ true
89
+ end
90
+
91
+ def reduce
92
+ success = false
93
+ @n.times { |r| @n.times { |c|
94
+ if (sz = @arr[r][c].size) > 1
95
+ @arr[r][c] = @arr[r][c] -
96
+ (@rfix[r] | @cfix[c] | @bfix[rc2box(r, c)])
97
+ raise "impossible to solve" if @arr[r][c].empty?
98
+ if @arr[r][c].size < sz
99
+ success = true
100
+ update_fix(r, c)
101
+ end
102
+ end
103
+ } }
104
+ success
105
+ end
106
+
107
+ def deduce
108
+ success = false
109
+ [:col_each, :row_each, :box_each].each { |meth|
110
+ @n.times { |i|
111
+ u = uniqs_in(meth, i)
112
+ unless u.empty?
113
+ send(meth, i) { |x|
114
+ if x.size > 1 && ((u2 = u & x).size == 1)
115
+ success = true
116
+ u2
117
+ else
118
+ nil
119
+ end
120
+ }
121
+ return success if success
122
+ end
123
+ }
124
+ }
125
+ success
126
+ end
127
+
128
+ private
129
+ def rc2box(r, c)
130
+ (r - (r % @sqrt_n)) + (c / @sqrt_n)
131
+ end
132
+
133
+ def update_fix(r, c)
134
+ if @arr[r][c].size == 1
135
+ @rfix[r] << @arr[r][c][0]
136
+ @cfix[c] << @arr[r][c][0]
137
+ @bfix[rc2box(r, c)] << @arr[r][c][0]
138
+ end
139
+ end
140
+
141
+ def row_each(r)
142
+ @n.times { |c|
143
+ if (res = yield(@arr[r][c]))
144
+ @arr[r][c] = res
145
+ update_fix(r, c)
146
+ end
147
+ }
148
+ end
149
+
150
+ def col_each(c)
151
+ @n.times { |r|
152
+ if (res = yield(@arr[r][c]))
153
+ @arr[r][c] = res
154
+ update_fix(r, c)
155
+ end
156
+ }
157
+ end
158
+
159
+ def box_each(b)
160
+ off_r, off_c = (b - (b % @sqrt_n)), (b % @sqrt_n) * @sqrt_n
161
+ @n.times { |i|
162
+ r, c = off_r + (i / @sqrt_n), off_c + (i % @sqrt_n)
163
+ if (res = yield(@arr[r][c]))
164
+ @arr[r][c] = res
165
+ update_fix(r, c)
166
+ end
167
+ }
168
+ end
169
+
170
+ def uniqs_in(each_meth, index)
171
+ h = Hash.new(0)
172
+ send(each_meth, index) { |x|
173
+ x.each { |n| h[n] += 1 } if x.size > 1
174
+ nil
175
+ }
176
+ h.select { |k, v| v == 1 }.collect { |k, v| k }
177
+ end
178
+ end
@@ -1,6 +1,6 @@
1
1
  require "test/unit"
2
2
 
3
- require "euler"
3
+ require File.dirname(__FILE__) + "/../lib/euler"
4
4
 
5
5
  class TestIntegerMethods < Test::Unit::TestCase
6
6
  def test_factorial
@@ -42,4 +42,4 @@ class TestIntegerMethods < Test::Unit::TestCase
42
42
  assert_equal(2, 10.length, "10 has a length of 2")
43
43
  assert_equal(4, 4563.length, "4563 has a length of 4")
44
44
  end
45
- end
45
+ end
@@ -1,6 +1,6 @@
1
1
  require "test/unit"
2
2
 
3
- require "euler"
3
+ require File.dirname(__FILE__) + "/../lib/euler"
4
4
 
5
5
  class TestModule < Test::Unit::TestCase
6
6
  def test_sieve
@@ -37,4 +37,4 @@ class TestModule < Test::Unit::TestCase
37
37
  assert_equal(4, Euler.find_missing_pyth_value(3, nil, 5))
38
38
  assert_equal(5, Euler.find_missing_pyth_value(3, 4, nil))
39
39
  end
40
- end
40
+ end
@@ -0,0 +1,28 @@
1
+ require "test/unit"
2
+
3
+ require File.dirname(__FILE__) + "/../lib/euler"
4
+
5
+ class TestRudoku < Test::Unit::TestCase
6
+ def test_rudoku
7
+ assert_equal([[4, 8, 3, 9, 2, 1, 6, 5, 7],
8
+ [9, 6, 7, 3, 4, 5, 8, 2, 1],
9
+ [2, 5, 1, 8, 7, 6, 4, 9, 3],
10
+ [5, 4, 8, 1, 3, 2, 9, 7, 6],
11
+ [7, 2, 9, 5, 6, 4, 1, 3, 8],
12
+ [1, 3, 6, 7, 9, 8, 2, 4, 5],
13
+ [3, 7, 2, 6, 8, 9, 5, 1, 4],
14
+ [8, 1, 4, 2, 5, 3, 7, 6, 9],
15
+ [6, 9, 5, 4, 1, 7, 3, 8, 2]],
16
+ Euler.solve_sudoku([[0, 0, 3, 0, 2, 0, 6, 0, 0],
17
+ [9, 0, 0, 3, 0, 5, 0, 0, 1],
18
+ [0, 0, 1, 8, 0, 6, 4, 0, 0],
19
+ [0, 0, 8, 1, 0, 2, 9, 0, 0],
20
+ [7, 0, 0, 0, 0, 0, 0, 0, 8],
21
+ [0, 0, 6, 7, 0, 8, 2, 0, 0],
22
+ [0, 0, 2, 6, 0, 9, 5, 0, 0],
23
+ [8, 0, 0, 2, 0, 3, 0, 0, 9],
24
+ [0, 0, 5, 0, 1, 0, 3, 0, 0]]
25
+ )
26
+ )
27
+ end
28
+ end
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'test/unit/testsuite'
3
3
  require 'tc_integer_methods.rb'
4
- require 'tc_module.rb'
4
+ require 'tc_module.rb'
5
+ require 'tc_rudoku.rb'
metadata CHANGED
@@ -1,10 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: euler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.8
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Skalnik
8
+ - Nick Kezhaya
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
@@ -22,17 +23,18 @@ extensions: []
22
23
  extra_rdoc_files:
23
24
  - LICENSE
24
25
  - README.rdoc
25
- - README.txt
26
26
  files:
27
27
  - .gitignore
28
28
  - LICENSE
29
29
  - README.rdoc
30
- - README.txt
31
30
  - Rakefile
32
31
  - VERSION
32
+ - euler.gemspec
33
33
  - lib/euler.rb
34
+ - lib/rudoku.rb
34
35
  - test/tc_integer_methods.rb
35
36
  - test/tc_module.rb
37
+ - test/tc_rudoku.rb
36
38
  - test/test_euler.rb
37
39
  has_rdoc: true
38
40
  homepage: http://github.com/skalnik/euler
@@ -57,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
59
  version:
58
60
  requirements: []
59
61
 
60
- rubyforge_project:
62
+ rubyforge_project: euler
61
63
  rubygems_version: 1.3.5
62
64
  signing_key:
63
65
  specification_version: 3
@@ -65,4 +67,5 @@ summary: A small library to help solve Projet Euler problems.
65
67
  test_files:
66
68
  - test/tc_integer_methods.rb
67
69
  - test/tc_module.rb
70
+ - test/tc_rudoku.rb
68
71
  - test/test_euler.rb
data/README.txt DELETED
@@ -1,55 +0,0 @@
1
- = euler
2
-
3
- == DESCRIPTION:
4
-
5
- libeuler is a simple library you can include in your code to take away some of the boring repetitive parts of solving Project Euler problems.
6
-
7
- == FEATURES:
8
-
9
- * Adds various methods to the Integer class, such as factorial, prime?, is_fibonacci?, etc.
10
- * Provides various module methods, such as generate_sieve, get_primes, etc.
11
-
12
- == SYNOPSIS:
13
-
14
- require 'rubygems'
15
- require 'euler'
16
-
17
- 5.factorial # => 120
18
-
19
- == REQUIREMENTS:
20
-
21
- * none
22
-
23
- == INSTALL:
24
-
25
- * sudo gem install euler
26
-
27
- == LICENSE:
28
-
29
- (BSD License)
30
-
31
- Copyright (c) 2008, Mike "Oompa" Skalnik ("THE AUTHOR")
32
- All rights reserved. mike.skalnik@gmail.com
33
-
34
- Redistribution and use in source and binary forms, with or without
35
- modification, are permitted provided that the following conditions are met:
36
- * Redistributions of source code must retain the above copyright
37
- notice, this list of conditions and the following disclaimer.
38
- * Redistributions in binary form must reproduce the above copyright
39
- notice, this list of conditions and the following disclaimer in the
40
- documentation and/or other materials provided with the distribution.
41
- * Neither the name of the author nor the
42
- names of its contributors may be used to endorse or promote products
43
- derived from this software without specific prior written permission.
44
-
45
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
46
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
47
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48
- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
49
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
52
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55
-