diff --git a/crystal/euler.cr b/crystal/euler.cr index b07b147..2c3f05e 100644 --- a/crystal/euler.cr +++ b/crystal/euler.cr @@ -3,57 +3,79 @@ require "big" module Euler - alias NumType = Int32 | Int64 | UInt32 | UInt64 | BigInt + extend self - def self.trial_division(n : NumType) - factors = [] of NumType - check = ->(p: NumType) { - q, r = n.divmod(p) - while r.zero? - factors << p - n = q + alias NumType = Int32 | Int64 | UInt32 | UInt64 + + macro trial_division_method(given_type) + def trial_division(n : {{given_type}}) + factors = [] of {{given_type}} + check = ->(p: {{given_type}}) { q, r = n.divmod(p) - end - } + while r.zero? + factors << p + n = q + q, r = n.divmod(p) + end + } - check.call(2) - check.call(3) - p = 5 - while p * p <= n - check.call(p) - p += 2 - check.call(p) - p += 4 + check.call(2) + check.call(3) + p = 5 + while p * p <= n + check.call(p) + p += 2 + check.call(p) + p += 4 + end + factors << n if n > 1 + factors end - factors << n if n > 1 - factors end - def self.prime_factorization(n : NumType) - result = {} of NumType => NumType - factors = self.trial_division(n) + macro prime_factorization_method(given_type) + def prime_factorization(n : {{given_type}}) + result = {} of {{given_type}} => Int32 + factors = self.trial_division(n) - factors.each do |f| - result[f] = 0 - num = n - while num % f == 0 - result[f] += 1 - num /= f + factors.each do |f| + result[f] = 0 + num = n + while num % f == 0 + result[f] += 1 + num /= f + end end - end - result + result + end end - def self.palindrome?(x) + macro to_digit_list_method(given_type) + def to_digit_list(n : {{given_type}}) + n.to_s.chars.map { |d| d.to_i } + end + end + + macro to_big_ints_method(given_type) + def to_big_ints(num_list : Array({{given_type}})) + num_list.map { |n| BigInt.new(n) } + end + end + + trial_division_method(NumType) + trial_division_method(BigInt) + + prime_factorization_method(NumType) + prime_factorization_method(BigInt) + + to_digit_list_method(NumType) + to_digit_list_method(BigInt) + + to_big_ints_method(NumType) + to_big_ints_method(BigInt) + + def palindrome?(x) x.to_s.reverse == x.to_s end - - def self.to_digit_list(n : NumType) - n.to_s.chars.map { |d| d.to_i } - end - - def self.to_big_ints(num_list : Array(NumType)) - num_list.map { |n| BigInt.new(n) } - end end diff --git a/crystal/euler001.cr b/crystal/euler001.cr index 702de76..69f7e4f 100644 --- a/crystal/euler001.cr +++ b/crystal/euler001.cr @@ -1 +1,9 @@ -puts (1..999).select { |n| (n % 3 == 0) || (n % 5 == 0) }.sum +module Euler + module Problem001 + extend self + + def solution + (1..999).select { |n| (n % 3 == 0) || (n % 5 == 0) }.sum + end + end +end diff --git a/crystal/euler002.cr b/crystal/euler002.cr index e4750df..49a0d6e 100644 --- a/crystal/euler002.cr +++ b/crystal/euler002.cr @@ -1,18 +1,26 @@ -def fibonacci_nums_up_to(n) - result = [1] of Int32 +module Euler + module Problem002 + extend self - a = 1 - b = 2 - accum = 0 + def fibonacci_nums_up_to(n) + result = [1] of Int32 - while accum < n - accum = a + b - result << b - a = b - b = accum + a = 1 + b = 2 + accum = 0 + + while accum < n + accum = a + b + result << b + a = b + b = accum + end + + result + end + + def solution + fibonacci_nums_up_to(4000000).select{ |n| n.even? }.sum + end end - - result end - -puts fibonacci_nums_up_to(4000000).select{ |n| n.even? }.sum diff --git a/crystal/euler003.cr b/crystal/euler003.cr index f4e64c9..5a86c82 100644 --- a/crystal/euler003.cr +++ b/crystal/euler003.cr @@ -1,3 +1,11 @@ require "./euler" -puts Euler.trial_division(600851475143).max +module Euler + module Problem003 + extend self + + def solution + Euler.trial_division(600851475143).max + end + end +end diff --git a/crystal/euler004.cr b/crystal/euler004.cr index 6b9b4e6..43de50a 100644 --- a/crystal/euler004.cr +++ b/crystal/euler004.cr @@ -1,7 +1,15 @@ require "./euler" -def products_of_three_digit_nums - (100..999).to_a.combinations(2).map { |p| p.product } -end +module Euler + module Problem004 + extend self -puts products_of_three_digit_nums.select { |x| Euler.palindrome?(x) }.max + def products_of_three_digit_nums + (100..999).to_a.combinations(2).map { |p| p.product } + end + + def solution + products_of_three_digit_nums.select { |x| Euler.palindrome?(x) }.max + end + end +end diff --git a/crystal/euler005.cr b/crystal/euler005.cr index 8ad35bd..18566b8 100644 --- a/crystal/euler005.cr +++ b/crystal/euler005.cr @@ -1,19 +1,27 @@ require "./euler" -def integer_factorization_divisible_by_all_up_to(n) - result = {} of Euler::NumType => Euler::NumType - (2..n).map do |i| - Euler.prime_factorization(i).each do |prime, exponent| - if !result.has_key?(prime) || (exponent > result[prime]) - result[prime] = exponent +module Euler + module Problem005 + extend self + + def integer_factorization_divisible_by_all_up_to(n) + result = {} of Euler::NumType => Euler::NumType + (2..n).map do |i| + Euler.prime_factorization(i).each do |prime, exponent| + if !result.has_key?(prime) || (exponent > result[prime]) + result[prime] = exponent + end + end end + result + end + + def factors_to_int(factorization : Hash(Euler::NumType, Euler::NumType)) + factorization.map { |prime, exponent| prime ** exponent }.product + end + + def solution + factors_to_int(integer_factorization_divisible_by_all_up_to(20)) end end - result end - -def factors_to_int(factorization : Hash(Euler::NumType, Euler::NumType)) - factorization.map { |prime, exponent| prime ** exponent }.product -end - -puts factors_to_int(integer_factorization_divisible_by_all_up_to(20)) diff --git a/crystal/euler006.cr b/crystal/euler006.cr index 8c172e6..fc7465e 100644 --- a/crystal/euler006.cr +++ b/crystal/euler006.cr @@ -1 +1,9 @@ -puts (1..100).sum ** 2 - (1..100).map { |n| n * n }.sum +module Euler + module Problem006 + extend self + + def solution + (1..100).sum ** 2 - (1..100).map { |n| n * n }.sum + end + end +end diff --git a/crystal/euler007.cr b/crystal/euler007.cr index b338dbc..1cf8770 100644 --- a/crystal/euler007.cr +++ b/crystal/euler007.cr @@ -1,3 +1,11 @@ -require "./euler" +require "./prime" -puts Euler.eratosthenes_sieve(1000000)[10000] +module Euler + module Problem007 + extend self + + def solution + Euler::Prime.new.skip(10000).next + end + end +end diff --git a/crystal/euler008.cr b/crystal/euler008.cr index 88c9cbe..c27acbf 100644 --- a/crystal/euler008.cr +++ b/crystal/euler008.cr @@ -1,27 +1,35 @@ require "./euler" -def largest_consecutive_product(n, adjacent) - Euler.to_big_ints(Euler.to_digit_list(n)).each_cons(adjacent).map { |x| x.product }.max -end +module Euler + module Problem008 + extend self -puts largest_consecutive_product( -BigInt.new("73167176531330624919225119674426574742355349194934 -96983520312774506326239578318016984801869478851843 -85861560789112949495459501737958331952853208805511 -12540698747158523863050715693290963295227443043557 -66896648950445244523161731856403098711121722383113 -62229893423380308135336276614282806444486645238749 -30358907296290491560440772390713810515859307960866 -70172427121883998797908792274921901699720888093776 -65727333001053367881220235421809751254540594752243 -52584907711670556013604839586446706324415722155397 -53697817977846174064955149290862569321978468622482 -83972241375657056057490261407972968652414535100474 -82166370484403199890008895243450658541227588666881 -16427171479924442928230863465674813919123162824586 -17866458359124566529476545682848912883142607690042 -24219022671055626321111109370544217506941658960408 -07198403850962455444362981230987879927244284909188 -84580156166097919133875499200524063689912560717606 -05886116467109405077541002256983155200055935729725 -71636269561882670428252483600823257530420752963450"), 13) + def largest_consecutive_product(n, adjacent) + Euler.to_big_ints(Euler.to_digit_list(n)).each_cons(adjacent).map { |x| x.product }.max + end + + def solution + largest_consecutive_product( + BigInt.new("73167176531330624919225119674426574742355349194934 + 96983520312774506326239578318016984801869478851843 + 85861560789112949495459501737958331952853208805511 + 12540698747158523863050715693290963295227443043557 + 66896648950445244523161731856403098711121722383113 + 62229893423380308135336276614282806444486645238749 + 30358907296290491560440772390713810515859307960866 + 70172427121883998797908792274921901699720888093776 + 65727333001053367881220235421809751254540594752243 + 52584907711670556013604839586446706324415722155397 + 53697817977846174064955149290862569321978468622482 + 83972241375657056057490261407972968652414535100474 + 82166370484403199890008895243450658541227588666881 + 16427171479924442928230863465674813919123162824586 + 17866458359124566529476545682848912883142607690042 + 24219022671055626321111109370544217506941658960408 + 07198403850962455444362981230987879927244284909188 + 84580156166097919133875499200524063689912560717606 + 05886116467109405077541002256983155200055935729725 + 71636269561882670428252483600823257530420752963450"), 13) + end + end +end diff --git a/crystal/euler009.cr b/crystal/euler009.cr index 76e045d..e31ae71 100644 --- a/crystal/euler009.cr +++ b/crystal/euler009.cr @@ -1,14 +1,22 @@ require "./euler" -def generate_pythagorean_triples(upper_bound) - ([] of Array(Euler::NumType)).tap do |triples| - (2..upper_bound).each do |a| - (a..upper_bound).each do |b| - c = Math.sqrt(a**2 + b**2) - triples << [a, b, c.to_i] if c % 1 == 0 +module Euler + module Problem009 + extend self + + def generate_pythagorean_triples(upper_bound) + ([] of Array(Euler::NumType)).tap do |triples| + (2..upper_bound).each do |a| + (a..upper_bound).each do |b| + c = Math.sqrt(a**2 + b**2) + triples << [a, b, c.to_i] if c % 1 == 0 + end + end end end + + def solution + generate_pythagorean_triples(500).find([-1]) { |x| x.sum == 1000 }.product + end end end - -puts generate_pythagorean_triples(500).find([-1]) { |x| x.sum == 1000 }.product diff --git a/crystal/euler010.cr b/crystal/euler010.cr index 2425db8..c431291 100644 --- a/crystal/euler010.cr +++ b/crystal/euler010.cr @@ -1,4 +1,12 @@ require "./prime" -prime = Euler::Prime.new -puts prime.take_while { |x| x < 2000000 }.sum +module Euler + module Problem010 + extend self + + def solution + prime = Euler::Prime.new + prime.take_while { |x| x < 2000000 }.sum + end + end +end diff --git a/crystal/prime.cr b/crystal/prime.cr index 08151db..02a5612 100644 --- a/crystal/prime.cr +++ b/crystal/prime.cr @@ -2,7 +2,8 @@ require "./euler" module Euler class Prime - include Iterator(NumType) + # needs to include BigInt ... + include Iterator(NumType | BigInt) def initialize() @sieve_size = 16 diff --git a/crystal/spec/euler001_spec.cr b/crystal/spec/euler001_spec.cr new file mode 100644 index 0000000..2af1d41 --- /dev/null +++ b/crystal/spec/euler001_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler001" + +describe Euler::Problem001 do + it "should return 233168" do + Euler::Problem001.solution.should eq 233168 + end +end diff --git a/crystal/spec/euler002_spec.cr b/crystal/spec/euler002_spec.cr new file mode 100644 index 0000000..de67cb5 --- /dev/null +++ b/crystal/spec/euler002_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler002" + +describe Euler::Problem002 do + it "should return 4613732" do + Euler::Problem002.solution.should eq 4613732 + end +end diff --git a/crystal/spec/euler003_spec.cr b/crystal/spec/euler003_spec.cr new file mode 100644 index 0000000..13ce39f --- /dev/null +++ b/crystal/spec/euler003_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler003" + +describe Euler::Problem003 do + it "should return 6857" do + Euler::Problem003.solution.should eq 6857 + end +end diff --git a/crystal/spec/euler004_spec.cr b/crystal/spec/euler004_spec.cr new file mode 100644 index 0000000..fdcf413 --- /dev/null +++ b/crystal/spec/euler004_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler004" + +describe Euler::Problem004 do + it "should return 906609" do + Euler::Problem004.solution.should eq 906609 + end +end diff --git a/crystal/spec/euler005_spec.cr b/crystal/spec/euler005_spec.cr new file mode 100644 index 0000000..a377fda --- /dev/null +++ b/crystal/spec/euler005_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler005" + +describe Euler::Problem005 do + it "should return 232792560" do + Euler::Problem005.solution.should eq 232792560 + end +end diff --git a/crystal/spec/euler006_spec.cr b/crystal/spec/euler006_spec.cr new file mode 100644 index 0000000..be682e5 --- /dev/null +++ b/crystal/spec/euler006_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler006" + +describe Euler::Problem006 do + it "should return 25164150" do + Euler::Problem006.solution.should eq 25164150 + end +end diff --git a/crystal/spec/euler007_spec.cr b/crystal/spec/euler007_spec.cr new file mode 100644 index 0000000..1a3a653 --- /dev/null +++ b/crystal/spec/euler007_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler007" + +describe Euler::Problem007 do + it "should return 104743" do + Euler::Problem007.solution.should eq 104743 + end +end diff --git a/crystal/spec/euler008_spec.cr b/crystal/spec/euler008_spec.cr new file mode 100644 index 0000000..d2e6ae8 --- /dev/null +++ b/crystal/spec/euler008_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler008" + +describe Euler::Problem008 do + it "should return 23514624000" do + Euler::Problem008.solution.should eq 23514624000 + end +end diff --git a/crystal/spec/euler009_spec.cr b/crystal/spec/euler009_spec.cr new file mode 100644 index 0000000..31a6277 --- /dev/null +++ b/crystal/spec/euler009_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler009" + +describe Euler::Problem009 do + it "should return 31875000" do + Euler::Problem009.solution.should eq 31875000 + end +end diff --git a/crystal/spec/euler010_spec.cr b/crystal/spec/euler010_spec.cr new file mode 100644 index 0000000..0c1c54e --- /dev/null +++ b/crystal/spec/euler010_spec.cr @@ -0,0 +1,8 @@ +require "spec" +require "../euler010" + +describe Euler::Problem010 do + it "should return 142913828922" do + Euler::Problem010.solution.should eq 142913828922 + end +end