euler 1.0.8 → 1.1.0

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