├── .gitignore ├── LICENSE ├── README.md └── src ├── lib ├── binomial.nim ├── bithacks.nim ├── digits.nim ├── fibonacci.nim ├── functional.nim ├── integer_math.nim ├── modular_arithmetic.nim └── primes.nim ├── pe001_multiples_of_3_and_5.nim ├── pe002_even_fibonacci_numbers.nim ├── pe003_largest_prime_factors.nim ├── pe004_largest_palindrome_product.nim ├── pe005_smallest_multiple.nim ├── pe006_sum_square_difference.nim ├── pe007_10001st prime.nim ├── pe008_largest_product_in_a_series.nim ├── pe009_special_pythagorean_triplets.nim ├── pe010_summation_of_primes.nim ├── pe011_largest_product_in_a_grid.nim ├── pe012_highly_divisible_triangular_number.nim ├── pe013_large_sum.nim ├── pe014_longest_collatz_sequence.nim ├── pe015_lattice_paths.nim ├── pe016_power_digit_sum.nim └── pe017_number_letter_counts.nim /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries 2 | bin/ 3 | 4 | # Cache 5 | nimcache/ 6 | 7 | # OSX 8 | .DS_Store 9 | 10 | # Research 11 | reference_code/ 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Solving Project Euler problems with Nim 2 | 3 | Project Euler is a website that publish hundreds of mathematics oriented problems. 4 | It's an excellent website to learn a new language with a numeric focus. (You won't learn web development ;) ) 5 | 6 | [Project Euler](https://projecteuler.net/) 7 | 8 | - Pb 1: Find the sum of all the multiples of 3 or 5 below 1000. 9 | 10 | *Solved with list comprehension* 11 | - Pb 2: Sum of even number from Fibonacci numver < 4000000. 12 | 13 | *Solved with functional programming (takeWhile, filter)* 14 | - Pb 3: Largest prime factor of the number 600851475143. 15 | 16 | *Solved by creating a prime factorization method.* 17 | - Pb 4: Find the largest palindrome made from the product of two 3-digit numbers (same number even if read backward). 18 | 19 | *Solved with list comprehension and implementing unfold, haskell-style.* 20 | - Pb 5: What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20. 21 | 22 | *Solved by folding a least common multiple function.* 23 | - Pb 6: Difference between the sum of the squares of the first one hundred natural numbers and the square of the sum. 24 | 25 | *Solved with map* 26 | - Pb 7: What is the 10 001st prime number? 27 | 28 | *Solved by implementing a prime sieve with a BitVector type to optimize CPU cache. I benchmarked it against primegen, primesieve and a lot of prime sieve on Rosetta Stone. It's very very fast and memory efficient and less than 50lines, comment included. Only thing faster is the Nim inline implementation on Rosetta Code.* 29 | - Pb 8: Find the thirteen adjacent digits in the given 1000-digit number that have the greatest product. What is the value of this product? 30 | 31 | *Solved by creating a sliding window that returns an iterator containing the product of the 13 numbers. Then fold to get the maximum.* 32 | 33 | - Pb 9: A Pythagorean triplet is a set of three natural numbers, a < b < c, for which, a^2 + b^2 = c^2. There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc. 34 | 35 | *Solved using list comprehension* 36 | 37 | - Pb 10: Find the sum of all the primes below two million. 38 | 39 | *Solved using the primesieve from Pb7* -------------------------------------------------------------------------------- /src/lib/binomial.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | # The MIT License (MIT) 23 | 24 | proc binomialCoeff*(n, k: int): int = 25 | result = 1 26 | for i in 0.. zero: 30 | y = y shr 1 31 | inc(result) 32 | 33 | 34 | type 35 | Bit = range[0..1] 36 | Base = seq[int] 37 | BitVector = distinct Base 38 | 39 | # proc `[]`(b: BitVector, i: Slice[int]): BitVector = 40 | # (if i.a < i.b: Base(b)[i] else: Base(b)[i.b .. i.a]) 41 | 42 | # proc `[]=`(b: var BitVector; i: Slice[int], value: BitVector) = ... 43 | 44 | proc `[]`*(b: BitVector, i: int): Bit = Base(b)[i shr 5] shr (i and 31) and 1 # i and 31 is a fast way to do i mod 32 45 | 46 | proc `[]=`*(b: var BitVector, i: int, value: Bit) = 47 | # let index = i and 31 48 | var w = addr Base(b)[i shr 5] 49 | 50 | # Alternative 0 to set bit 51 | # w[] = w[] and (not (1'i32 shl index)) or (value shl index) 52 | 53 | # Alternative 1 with xor for bitsetter 54 | # w[] = w[] xor (((-value) xor w[]) and (1'i32 shl index)) 55 | 56 | # Alternative 2 bit setter 57 | if value == 0: w[] = w[] and not (1'i32 shl (i and 31)) 58 | else: w[] = w[] or (1'i32 shl (i and 31)) 59 | 60 | proc newBoolBV*(n: int, b: bool): BitVector = 61 | ## New bit packed booleean array, initialized to b bool value 62 | result = newSeq[int](n+1).BitVector 63 | if b: 64 | for i in 0..n: 65 | result[i]=1 -------------------------------------------------------------------------------- /src/lib/digits.nim: -------------------------------------------------------------------------------- 1 | from functional import unfold 2 | from options import Option, some, none 3 | from algorithm import reversed 4 | 5 | proc divmod10_opt(n: int): Option[(int, int)] = 6 | if n == 0: 7 | return none((int,int)) 8 | return some((n mod 10, n div 10)) 9 | 10 | proc toDigits*(n: int): seq[int] = 11 | unfold(divmod10_opt,n).reversed 12 | 13 | proc divmod10*(n: int): tuple[rem: int, quot: int] = 14 | if n == 0: 15 | return (0, 0) 16 | return (n mod 10, n div 10) -------------------------------------------------------------------------------- /src/lib/fibonacci.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | iterator fib*: int {.closure.} = 25 | var a = 0 26 | var b = 1 27 | while true: 28 | yield a 29 | swap a, b 30 | b = a + b -------------------------------------------------------------------------------- /src/lib/functional.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | # Ripped off nimLazy MIT License Peter Mora 24 | # takeWhile, take and count 25 | 26 | proc takeWhile*[T](iter: iterator(): T, cond: proc(x: T):bool): iterator(): T = 27 | ## .. code-block:: Nim 28 | ## takeWhile(1;2;3;4, proc(x: int): bool = x < 4) -> 1;2;3 29 | result = iterator(): T {.closure.}= 30 | var r = iter() 31 | while not finished(iter) and cond(r): 32 | yield r 33 | r = iter() 34 | 35 | proc take*[T](iter: iterator(): T, n: int): iterator(): T = 36 | ## .. code-block:: Nim 37 | ## take(1;2;3;4, 3) -> 1;2;3 38 | ## take(1;2, 3) -> 1;2 39 | result = iterator(): T {.closure.}= 40 | var i = 0 41 | while i < n: 42 | i += 1 43 | var r = iter() 44 | if finished(iter): 45 | break 46 | yield r 47 | 48 | proc take*[T](s: seq[T], n: int): iterator(): T = 49 | ## .. code-block:: Nim 50 | ## take(1;2;3;4, 3) -> 1;2;3 51 | ## take(1;2, 3) -> 1;2 52 | 53 | result = iterator(): T = 54 | for i, value in s: 55 | yield value 56 | if i == s.len()-1 or i >= n: 57 | break #TODO TEST: if it's proper stop 58 | 59 | iterator take*[T](oa: openarray[T], n: int): T = 60 | for i, value in oa: #arr.len()-1 61 | yield value 62 | if i == oa.len()-1: 63 | break #TODO TEST: if it's proper stop 64 | 65 | 66 | 67 | # count infinite iterator 68 | 69 | proc count*[T](start: T): iterator(): T = 70 | ## .. code-block:: Nim 71 | ## count(x0) -> x0; x0 + 1; x0 + 2; ... 72 | result = iterator(): T {.closure.} = 73 | var x = start 74 | while true: 75 | yield x 76 | x = x+1 77 | 78 | proc count*[T](start: T, till: T, step: T = 1, includeLast = false): 79 | iterator(): T = 80 | ## .. code-block:: Nim 81 | ## count(x0, x1) -> x0; x0 + 1; x0 + 2; ...; x1-1 82 | result = iterator (): T {.closure.} = 83 | var x = start 84 | while x < till or (includeLast and x == till): 85 | yield x 86 | x = x + step 87 | 88 | # no "any", "fold" on arrays :/ 89 | proc any*[T](arr: openarray[T], pred: proc(item: T): bool {.closure.}): bool = 90 | ## Return true if any element of the array respects the predicate 91 | for i in arr: 92 | if pred(i): 93 | return true 94 | return false 95 | 96 | # unfold rewrite with Option monad 97 | from options import Option, isSome, get 98 | proc unfold*[T](f: proc(items: T): Option[(T, T)] {.closure.}, x:T): seq[T] = 99 | ## Build a sequence from function f: T -> Option(T,T) and a seed of type T 100 | result = @[] 101 | var u, r = x 102 | 103 | while f(u).isSome(): 104 | (r, u) = f(u).get() 105 | result.add(r) 106 | 107 | #fold for iterators: 108 | proc foldl*[T](iter: iterator(): T {.closure.}, f : proc(a:T, b:T):T, initval : T ):T = 109 | var i = iter 110 | result = initval 111 | for x in i(): 112 | result = f(result, x) -------------------------------------------------------------------------------- /src/lib/integer_math.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | from bithacks import bit_length 24 | 25 | # TODO: inline 26 | proc isOdd*[T: SomeInteger](i: T): bool {.inline.}= (i and 1) != 0 27 | proc isEven*[T: SomeInteger](i: T): bool {.inline.}= (i and 1) == 0 28 | 29 | proc divmod*[T: SomeInteger](n: T, b: T): (T, T) {.inline.}= 30 | ## return (n div base, n mod base) 31 | return (n div b, n mod b) 32 | 33 | proc isqrt*[T: SomeInteger](n: T): T = 34 | ##integer square root, return the biggest squarable number under n 35 | ##Computation via Newton method 36 | var x = n 37 | const two: T = 2 #necessary to cover uint and int 38 | var y = (two shl ((n.bit_length()+1) shr 1)) - 1 39 | while y < x: 40 | x = y 41 | y = (x + n div x) shr 1 42 | return x 43 | 44 | proc product*[T](x: openArray[T]): T {.noSideEffect.} = 45 | ## Computes the sum of the elements in `x`. 46 | ## If `x` is empty, 0 is returned. 47 | result = 1 48 | for i in items(x): 49 | result = result * i -------------------------------------------------------------------------------- /src/lib/modular_arithmetic.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2017 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | from ./integer_math import isOdd 24 | 25 | 26 | proc mulmod*[T: SomeInteger](a, b, modulus: T): T = 27 | var a_m = a mod modulus 28 | var b_m = b mod modulus 29 | if b_m > a_m: 30 | swap(a_m, b_m) 31 | while b_m > 0: 32 | if b_m.isOdd: 33 | result = (result + a_m) mod modulus 34 | a_m = (a_m shl 1) mod modulus 35 | b_m = b_m shr 1 36 | 37 | proc expmod*[T: SomeInteger](base, exponent, modulus: T): T = 38 | ## Modular exponentiation 39 | 40 | # Formula from applied Cryptography by Bruce Schneier 41 | # function modular_pow(base, exponent, modulus) 42 | # result := 1 43 | # while exponent > 0 44 | # if (exponent mod 2 == 1): 45 | # result := (result * base) mod modulus 46 | # exponent := exponent >> 1 47 | # base = (base * base) mod modulus 48 | # return result 49 | 50 | result = 1 # (exp 0 = 1) 51 | 52 | var e = exponent 53 | var b = base 54 | 55 | while e > 0: 56 | if isOdd e: 57 | result = mulmod(result, b, modulus) 58 | e = e shr 1 # e div 2 59 | b = mulmod(b,b,modulus) 60 | 61 | proc addmod*[T: SomeInteger](a, b, modulus: T): T = 62 | let a_m = if a < modulus: a else: a mod modulus 63 | 64 | if b == 0: 65 | return a_m 66 | let b_m = if b < modulus: b else: b mod modulus 67 | 68 | # We don't do a + b to avoid overflows 69 | # But we now that m at least is inferior to biggest T 70 | 71 | let b_from_m = modulus - b_m 72 | if a_m >= b_from_m: 73 | result = a_m - b_from_m 74 | else: 75 | result = modulus - b_from_m + a_m 76 | 77 | when isMainModule: 78 | # https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/fast-modular-exponentiation 79 | assert expmod(5, 117,19) == 1 80 | assert expmod(3, 1993, 17) == 14 -------------------------------------------------------------------------------- /src/lib/primes.nim: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | # Copyright (c) 2016 Mamy Ratsimbazafy 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | from math import `^`, gcd 24 | from ./integer_math import isEven, divmod, isqrt 25 | from ./functional import take, any 26 | from ./bithacks import bit_length 27 | from random import random 28 | from future import `=>` 29 | import ./modular_arithmetic 30 | 31 | 32 | const lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37] #, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997] 33 | 34 | proc witnessCoPrime(witness, s, d, n: int): bool = 35 | var v = expmod(witness, d, n) 36 | if v == 1: 37 | return true 38 | for i in 0 .. s-2: 39 | if v == n - 1: 40 | return true 41 | v = expmod(v, 2, n) 42 | return v == n - 1 43 | 44 | 45 | proc millerRabin(n: int): bool = 46 | ## Prime probablistic test, return True if probably prime 47 | 48 | # If n is composite then the Miller–Rabin primality test declares n probably prime with a probability at most 4−k 49 | # When the number n to be tested is small, trying all a < 2(ln n)2 is not necessary, as much smaller sets of potential witnesses are known to suffice. For example, Pomerance, Selfridge and Wagstaff[8] and Jaeschke[9] have verified that 50 | 51 | # if n < 2,047, it is enough to test a = 2; 52 | # if n < 1,373,653, it is enough to test a = 2 and 3; 53 | # if n < 9,080,191, it is enough to test a = 31 and 73; 54 | # if n < 25,326,001, it is enough to test a = 2, 3, and 5; 55 | # if n < 3,215,031,751, it is enough to test a = 2, 3, 5, and 7; 56 | # if n < 4,759,123,141, it is enough to test a = 2, 7, and 61; 57 | # if n < 1,122,004,669,633, it is enough to test a = 2, 13, 23, and 1662803; 58 | # if n < 2,152,302,898,747, it is enough to test a = 2, 3, 5, 7, and 11; 59 | # if n < 3,474,749,660,383, it is enough to test a = 2, 3, 5, 7, 11, and 13; 60 | # if n < 341,550,071,728,321, it is enough to test a = 2, 3, 5, 7, 11, 13, and 17. 61 | # Using the work of Feitsma and Galway enumerating all base 2 pseudoprimes in 2010, this was extended (see OEIS A014233), with the first result later shown using different methods in Jiang and Deng:[10] 62 | 63 | # if n < 3,825,123,056,546,413,051, it is enough to test a = 2, 3, 5, 7, 11, 13, 17, 19, and 23. 64 | # if n < 18,446,744,073,709,551,616 = 2^64, it is enough to test a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, and 37. 65 | # Sorenson and Webster[11] verify the above and calculate precise results for these larger than 64-bit results: 66 | 67 | # if n < 318,665,857,834,031,151,167,461, it is enough to test a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, and 37. 68 | # if n < 3,317,044,064,679,887,385,961,981, it is enough to test a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, and 41. 69 | 70 | # For n < 2^64, it is possible to perform strong-pseudoprime tests to the seven bases 2, 325, 9375, 28178, 450775, 9780504, and 1795265022 and completely determine the primality of n; see http://miller-rabin.appspot.com/. 71 | 72 | var d = n-1 73 | var s = 0 74 | while isEven d: 75 | d = d shr 1 # s div 2 76 | inc(s) 77 | 78 | for witness in lowPrimes.take(20): 79 | if not witnessCoPrime(witness, s, d, n): 80 | return false 81 | 82 | return true 83 | 84 | proc isProbablyPrime*(n: int): bool = 85 | ## Probabilistic determination via Miller-Rabin test : 25 trials: 4^-25 probability of error 86 | 87 | if n < 2: 88 | return false #0, 1 and negative numbers are not prime 89 | 90 | # TODO only one pass 91 | 92 | # Check if it's on the prime list 93 | if any(lowPrimes, p => n == p): 94 | return true 95 | 96 | # check if one of those divides n 97 | if any(lowPrimes, p => n mod p == 0): 98 | return false 99 | 100 | # check if no divisor and n is smaller than p*p it's prime 101 | if any(lowPrimes, p => n < p * p): 102 | return true 103 | 104 | # check with Miller-Rabin 105 | return millerRabin(n) 106 | 107 | 108 | # unfortunately Nim random function only accepts int for now instead of SomeInteger or SomeUnsignedInt for large numbers 109 | 110 | ############## Pollard Rho algorithm 111 | proc pollard_f(x: int, c:int, n:int): int = 112 | ## pseudo random function (x2 + 1) mod n for Pollard Rho algo 113 | result = expmod(x,2,n) 114 | result = addmod(result, c, n) 115 | 116 | proc pollardRho(n: int): int = 117 | if n.isEven(): return 2 118 | if n == 1: return 1 119 | 120 | # Check if it's on the prime list 121 | if any(lowPrimes, p => n == p): 122 | return n 123 | 124 | var x: int = random(n.int-3)+2 # from 2 to n-2 125 | var y: int = x 126 | var d: int = 1 127 | let c: int = random(n.int-1)+1 # from 1 to n-1 128 | 129 | while (d == 1): 130 | x = x.pollard_f(c,n) 131 | y = y.pollard_f(c,n).pollard_f(c,n) 132 | d = abs(x-y).gcd(n) 133 | 134 | if isProbablyPrime(d): 135 | return d 136 | return pollardRho(d) # if d = n retry with different random values 137 | 138 | 139 | ###### Pollard Rho retrieves 1 factor only, get the other 140 | proc primFac_pollardRho*(n: int): seq[int] = 141 | if isProbablyPrime(n): 142 | return @[n] 143 | 144 | var x = n 145 | result = @[] 146 | 147 | while x > 1: 148 | let f = x.pollardRho() 149 | result.add(f) 150 | x = x div f 151 | 152 | ###### 153 | #Roll own bitvector for speed 154 | 155 | type 156 | Base = seq[uint] #necessary to use the basic seq [] operator 157 | OddPackedBV = distinct Base 158 | 159 | proc `[]`(b: OddPackedBV, i: uint): uint = 160 | Base(b)[cast[int](i shr 5)] shr (i and 31) and 1 # i and 31 is a fast way to do i mod 32 161 | 162 | proc bv_composite_set(b: var OddPackedBV, i: uint) = 163 | var w = addr Base(b)[cast[int](i shr 5)] 164 | w[] = w[] or (1'u shl (i and 31)) # bit hack to set bit to 1 165 | 166 | # Ideally we should implement items and pairs for proper iteration 167 | 168 | #proc is faster than iterator 169 | #to limit initialization time, primes will be with value 0 in the bit array 170 | proc primeSieve*(n: uint): seq[uint] = 171 | result = @[] 172 | var a = newSeq[uint](n shr 6 + 1).OddPackedBV 173 | let maxn = (n - 1) shr 1 #TODO test boundaries 174 | let sqn = isqrt(n) shr 1 #TODO test boundaries 175 | for i in 1||sqn: #Use parallel OpenMP loops 176 | if a[i]==0: 177 | let prime = i shl 1 + 1 178 | for j in countup((prime*prime) shr 1, maxn, cast[int](prime)): #cross off multiples from i^2 to n, increment by i^2 + 2i because i^2+i is even 179 | a.bv_composite_set(j) 180 | result.add(2) 181 | for i in 1||maxn: 182 | if a[i]==0: result.add(i shl 1 + 1) -------------------------------------------------------------------------------- /src/pe001_multiples_of_3_and_5.nim: -------------------------------------------------------------------------------- 1 | ## Multiple of 3 and 5 2 | 3 | # If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. 4 | # Find the sum of all the multiples of 3 or 5 below 1000. 5 | 6 | from math import sum 7 | from future import lc,`[]` #list comprehension 8 | 9 | echo sum(lc[x | (x <- 1..1000, x mod 3 == 0 or x mod 5 == 0), int]) -------------------------------------------------------------------------------- /src/pe002_even_fibonacci_numbers.nim: -------------------------------------------------------------------------------- 1 | ## Even Fibonacci numbers 2 | 3 | # Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be: 4 | # 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 5 | # By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms. 6 | 7 | from math import sum 8 | from sequtils import toSeq, filterIt 9 | from future import `=>` 10 | from lib/integer_math import isEven 11 | from lib/functional import takeWhile 12 | from lib/fibonacci import fib 13 | 14 | 15 | var s = fib.takeWhile(x => x < 4_000_000) 16 | echo s().toSeq.filterIt(isEven(it)).sum() -------------------------------------------------------------------------------- /src/pe003_largest_prime_factors.nim: -------------------------------------------------------------------------------- 1 | ## largest prime factors` 2 | 3 | # The prime factors of 13195 are 5, 7, 13 and 29. 4 | # What is the largest prime factor of the number 600851475143 ? 5 | 6 | from lib/primes import primFac_pollardRho 7 | # from os import paramStr, commandLineParams 8 | # from strutils import parseInt 9 | from random import randomize 10 | 11 | 12 | # initialize random seed 13 | randomize() 14 | 15 | # let programName = paramStr(0) 16 | # let arguments = commandLineParams() 17 | # echo arguments[0].parseInt().primFac_pollardRho().max() 18 | 19 | echo 600_851_475_143.int().primFac_pollardRho().max() -------------------------------------------------------------------------------- /src/pe004_largest_palindrome_product.nim: -------------------------------------------------------------------------------- 1 | ## Largest palindrome product 2 | 3 | # A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99. 4 | # Find the largest palindrome made from the product of two 3-digit numbers. 5 | 6 | from lib/digits import toDigits 7 | from future import lc,`[]` 8 | from algorithm import reversed 9 | 10 | proc isPalindrome*(n: int) : bool = 11 | n.toDigits == n.toDigits.reversed 12 | 13 | echo lc[ x*y | (x <- 100..999, y <- 100..999, isPalindrome(x*y)), int].max() -------------------------------------------------------------------------------- /src/pe005_smallest_multiple.nim: -------------------------------------------------------------------------------- 1 | ## Smallest multiple 2 | 3 | # 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder . 4 | # What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? 5 | 6 | from sequtils import toSeq, foldr 7 | from math import lcm 8 | 9 | echo toSeq(1..20).foldr(lcm(a,b)) -------------------------------------------------------------------------------- /src/pe006_sum_square_difference.nim: -------------------------------------------------------------------------------- 1 | # The sum of the squares of the first ten natural numbers is, 2 | # 1^2 +2^2 +...+10^2 =385 3 | # The square of the sum of the first ten natural numbers is, (1+2+...+10)^2 =55^2 =3025 4 | # Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640. 5 | # Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum. 6 | 7 | from sequtils import toSeq, mapIt 8 | from math import sum, `^` 9 | 10 | const oneHundred = toSeq(1..100) 11 | 12 | echo oneHundred.sum ^ 2 - oneHundred.mapIt(it * it).sum() -------------------------------------------------------------------------------- /src/pe007_10001st prime.nim: -------------------------------------------------------------------------------- 1 | ## 10001st prime 2 | 3 | # By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. 4 | # What is the 10 001st prime number? 5 | 6 | from lib/primes import primeSieve 7 | # from os import commandLineParams 8 | from strutils import parseFloat 9 | from math import ln 10 | 11 | # let arguments = commandLineParams() 12 | # let n = arguments[0].parseFloat - 1 #prime 1 is in pos 0, 10001 in pos 10000 13 | 14 | let n = 10001.0f # Need float for ln computation of upperbound 15 | 16 | # nth prime number is upper bound by 17 | # n(ln⁡ n+ln⁡ ln ⁡n)>pn>n(ln⁡ n + ln⁡ ln ⁡n−1) 18 | 19 | let up_bound = n * (n.ln + n.ln.ln) 20 | 21 | 22 | let r = up_bound.uint.primeSieve() 23 | echo r[n.int-1] -------------------------------------------------------------------------------- /src/pe008_largest_product_in_a_series.nim: -------------------------------------------------------------------------------- 1 | ## Largest product in a series 2 | 3 | # The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832. 4 | # 73167176531330624919225119674426574742355349194934 5 | # 96983520312774506326239578318016984801869478851843 6 | # 85861560789112949495459501737958331952853208805511 7 | # 12540698747158523863050715693290963295227443043557 8 | # 66896648950445244523161731856403098711121722383113 9 | # 62229893423380308135336276614282806444486645238749 10 | # 30358907296290491560440772390713810515859307960866 11 | # 70172427121883998797908792274921901699720888093776 12 | # 65727333001053367881220235421809751254540594752243 13 | # 52584907711670556013604839586446706324415722155397 14 | # 53697817977846174064955149290862569321978468622482 15 | # 83972241375657056057490261407972968652414535100474 16 | # 82166370484403199890008895243450658541227588666881 17 | # 16427171479924442928230863465674813919123162824586 18 | # 17866458359124566529476545682848912883142607690042 19 | # 24219022671055626321111109370544217506941658960408 20 | # 07198403850962455444362981230987879927244284909188 21 | # 84580156166097919133875499200524063689912560717606 22 | # 05886116467109405077541002256983155200055935729725 23 | # 71636269561882670428252483600823257530420752963450 24 | # Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product? 25 | 26 | const monsterHunterNumber = "73167176531330624919225119674426574742355349194934" & 27 | "96983520312774506326239578318016984801869478851843" & 28 | "85861560789112949495459501737958331952853208805511" & 29 | "12540698747158523863050715693290963295227443043557" & 30 | "66896648950445244523161731856403098711121722383113" & 31 | "62229893423380308135336276614282806444486645238749" & 32 | "30358907296290491560440772390713810515859307960866" & 33 | "70172427121883998797908792274921901699720888093776" & 34 | "65727333001053367881220235421809751254540594752243" & 35 | "52584907711670556013604839586446706324415722155397" & 36 | "53697817977846174064955149290862569321978468622482" & 37 | "83972241375657056057490261407972968652414535100474" & 38 | "82166370484403199890008895243450658541227588666881" & 39 | "16427171479924442928230863465674813919123162824586" & 40 | "17866458359124566529476545682848912883142607690042" & 41 | "24219022671055626321111109370544217506941658960408" & 42 | "07198403850962455444362981230987879927244284909188" & 43 | "84580156166097919133875499200524063689912560717606" & 44 | "05886116467109405077541002256983155200055935729725" & 45 | "71636269561882670428252483600823257530420752963450" 46 | 47 | from lib/digits import toDigits 48 | from strutils import parseInt 49 | from lib/integer_math import product 50 | from lib/functional import foldl 51 | from algorithm import reversed 52 | from future import `=>` 53 | 54 | type 55 | # Digit = range[0..9] # difficult to convert from seq[int] to seq[Digit] 56 | Window = seq[int] 57 | DigProduct = tuple[ 58 | window : Window, 59 | prod : int 60 | ] 61 | const zeroDP: DigProduct = (@[],0) 62 | 63 | 64 | proc genWindows(n_str: string, size: int): 65 | iterator (): DigProduct = 66 | result = iterator(): DigProduct = 67 | for i,v in n_str: 68 | let s = n_str[i.int..i.int+size-1].parseInt.toDigits 69 | yield (s.reversed,s.product) 70 | 71 | proc keepMaxProd(a: DigProduct, b: DigProduct): DigProduct = 72 | if a.prod >= b.prod: 73 | return a 74 | return b 75 | 76 | let r = monsterHunterNumber.genWindows(13) 77 | .foldl( (a,b) => keepMaxProd(a,b), zeroDP) 78 | echo r -------------------------------------------------------------------------------- /src/pe009_special_pythagorean_triplets.nim: -------------------------------------------------------------------------------- 1 | ## Special Pythagorean triplets 2 | 3 | # A Pythagorean triplet is a set of three natural numbers, a < b < c, for which, a^2 + b^2 = c^2 4 | # For example,3^2 +4^2 =9+16=25=5^2. 5 | # There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc. 6 | 7 | from future import lc, `[]` #list comprehension 8 | 9 | let pyth = lc[(a,b,c) | (a<-1..1000, 10 | b<-a..1000, #avoid duplicate 11 | c<-b..1000, #c is superior to a and b 12 | a*a + b*b == c*c, 13 | a+b+c == 1000), 14 | tuple[a,b,c: int]] 15 | 16 | echo pyth[0].a * pyth[0].b * pyth[0].c -------------------------------------------------------------------------------- /src/pe010_summation_of_primes.nim: -------------------------------------------------------------------------------- 1 | ## Summation of primes 2 | 3 | # The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. 4 | # 5 | # Find the sum of all the primes below two million. 6 | 7 | from lib/primes import primeSieve 8 | from math import sum 9 | 10 | echo primeSieve(2_000_000).sum -------------------------------------------------------------------------------- /src/pe011_largest_product_in_a_grid.nim: -------------------------------------------------------------------------------- 1 | # Largest product in a grid 2 | # Problem 11 3 | # In the 20×20 grid below, four numbers along a diagonal line have been marked in red. 4 | 5 | # 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 6 | # 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 7 | # 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 8 | # 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 9 | # 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 10 | # 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 11 | # 32 98 81 28 64 23 67 10 *26 38 40 67 59 54 70 66 18 38 64 70 12 | # 67 26 20 68 02 62 12 20 95 *63 94 39 63 08 40 91 66 49 94 21 13 | # 24 55 58 05 66 73 99 26 97 17 *78 78 96 83 14 88 34 89 63 72 14 | # 21 36 23 09 75 00 76 44 20 45 35 *14 00 61 33 97 34 31 33 95 15 | # 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 16 | # 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 17 | # 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 18 | # 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 19 | # 04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66 20 | # 88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69 21 | # 04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36 22 | # 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16 23 | # 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54 24 | # 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48 25 | 26 | # The product of these numbers is 26 × 63 × 78 × 14 = 1788696. 27 | 28 | # What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid? 29 | 30 | 31 | ############################################################# 32 | 33 | # Strategy: 34 | # We create an object with : 35 | # - Current number 36 | # - 3 optional adjacent numbers 37 | # 38 | # Proc for all directions that store the adjacent numbers in that direction 39 | # 40 | # We only need to check everything because some 0 might pose problems in some directions, but not in the inverse one. 41 | # 42 | # And we reduce over the whole matrix 43 | # This way we only need one-loop to get the result. 44 | 45 | #### Edit, misread: I thought it was maximum product of 4 or less numbers, so my solution with option type is overkill 46 | #### We could just iterate in 16, 16 and forego options ... oh well 47 | 48 | import options, sequtils, future 49 | 50 | type Adj4 = object 51 | adj0: int # current position 52 | adj1: Option[int] 53 | adj2: Option[int] 54 | adj3: Option[int] 55 | 56 | proc up(s: seq[int], idx: int): Adj4 = 57 | result.adj0 = s[idx] 58 | result.adj1 = if idx div 20 >= 1: some(s[idx-20]) else: none(int) 59 | result.adj2 = if idx div 20 >= 2: some(s[idx-40]) else: none(int) 60 | result.adj3 = if idx div 20 >= 3: some(s[idx-60]) else: none(int) 61 | 62 | proc down(s: seq[int], idx: int): Adj4 = 63 | result.adj0 = s[idx] 64 | result.adj1 = if idx div 20 < 19: some(s[idx+20]) else: none(int) 65 | result.adj2 = if idx div 20 < 18: some(s[idx+40]) else: none(int) 66 | result.adj3 = if idx div 20 < 17: some(s[idx+60]) else: none(int) 67 | 68 | proc left(s: seq[int], idx: int): Adj4 = 69 | result.adj0 = s[idx] 70 | result.adj1 = if idx mod 20 >= 1: some(s[idx-1]) else: none(int) 71 | result.adj2 = if idx mod 20 >= 2: some(s[idx-2]) else: none(int) 72 | result.adj3 = if idx mod 20 >= 3: some(s[idx-3]) else: none(int) 73 | 74 | proc right(s: seq[int], idx: int): Adj4 = 75 | result.adj0 = s[idx] 76 | result.adj1 = if idx mod 20 < 19: some(s[idx+1]) else: none(int) 77 | result.adj2 = if idx mod 20 < 18: some(s[idx+2]) else: none(int) 78 | result.adj3 = if idx mod 20 < 17: some(s[idx+3]) else: none(int) 79 | 80 | proc upleft(s: seq[int], idx: int): Adj4 = 81 | result.adj0 = s[idx] 82 | result.adj1 = if (idx div 20 >= 1) and (idx mod 20 >= 1): some(s[idx-21]) 83 | else: none(int) 84 | result.adj2 = if (idx div 20 >= 2) and (idx mod 20 >= 2): some(s[idx-42]) 85 | else: none(int) 86 | result.adj3 = if (idx div 20 >= 3) and (idx mod 20 >= 3): some(s[idx-63]) 87 | else: none(int) 88 | 89 | proc downleft(s: seq[int], idx: int): Adj4 = 90 | result.adj0 = s[idx] 91 | result.adj1 = if (idx div 20 < 19) and (idx mod 20 >= 1): some(s[idx+19]) 92 | else: none(int) 93 | result.adj2 = if (idx div 20 < 18) and (idx mod 20 >= 2): some(s[idx+38]) 94 | else: none(int) 95 | result.adj3 = if (idx div 20 < 17) and (idx mod 20 >= 3): some(s[idx+57]) 96 | else: none(int) 97 | 98 | proc upright(s: seq[int], idx: int): Adj4 = 99 | result.adj0 = s[idx] 100 | result.adj1 = if (idx div 20 >= 1) and (idx mod 20 < 19): some(s[idx-19]) 101 | else: none(int) 102 | result.adj2 = if (idx div 20 >= 2) and (idx mod 20 < 18): some(s[idx-38]) 103 | else: none(int) 104 | result.adj3 = if (idx div 20 >= 3) and (idx mod 20 < 17): some(s[idx-57]) 105 | else: none(int) 106 | 107 | proc downright(s: seq[int], idx: int): Adj4 = 108 | result.adj0 = s[idx] 109 | result.adj1 = if (idx div 20 < 19) and (idx mod 20 < 19): some(s[idx+21]) 110 | else: none(int) 111 | result.adj2 = if (idx div 20 < 18) and (idx mod 20 < 18): some(s[idx+42]) 112 | else: none(int) 113 | result.adj3 = if (idx div 20 < 17) and (idx mod 20 < 17): some(s[idx+63]) 114 | else: none(int) 115 | 116 | let a = @[08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08, 117 | 49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00, 118 | 81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65, 119 | 52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91, 120 | 22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80, 121 | 24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50, 122 | 32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70, 123 | 67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21, 124 | 24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72, 125 | 21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95, 126 | 78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92, 127 | 16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57, 128 | 86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58, 129 | 19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40, 130 | 04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66, 131 | 88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69, 132 | 04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36, 133 | 20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16, 134 | 20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54, 135 | 01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48] 136 | 137 | # Position 4-4 (20*3 + 3 = 63) 138 | # echo up(a, 63) 139 | # echo down(a, 63) 140 | # echo left(a, 63) 141 | # echo right(a, 63) 142 | # echo upleft(a, 63) 143 | # echo downleft(a, 63) 144 | # echo upright(a, 63) 145 | # echo downright(a, 63) 146 | 147 | proc prod(a: Adj4): int = 148 | a.adj0 * a.adj1.get(otherwise = 1) * a.adj2.get(otherwise = 1) * a.adj3.get(otherwise = 1) 149 | 150 | proc maxAdj(s: seq[int], idx: int): int = 151 | let adjs = [up(s,idx), 152 | down(s,idx), 153 | left(s,idx), 154 | right(s,idx), 155 | upleft(s,idx), 156 | downleft(s,idx), 157 | upright(s,idx), 158 | downright(s,idx)] 159 | 160 | # We use the inline template `foldl` from `sequtils` that export (a,b) parameters for (previous result, next_elem) 161 | result = adjs.foldl(max(a, b.prod), 0) 162 | 163 | var r = 0 164 | for idx, _ in a: 165 | r = max(r, maxAdj(a, idx)) 166 | 167 | echo r -------------------------------------------------------------------------------- /src/pe012_highly_divisible_triangular_number.nim: -------------------------------------------------------------------------------- 1 | ## Highly divisible triangular number 2 | 3 | # The sequence of triangle numbers is generated by adding the natural numbers. 4 | # So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. 5 | # 6 | # The first ten terms would be: 7 | # 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ... 8 | # Let us list the factors of the first seven triangle numbers: 9 | # 1: 1 10 | # 3: 1,3 11 | # 6: 1,2,3,6 12 | # 10: 1,2,5,10 13 | # 15: 1,3,5,15 14 | # 21: 1,3,7,21 15 | # 28: 1,2,4,7,14,28 16 | # 17 | # We can see that 28 is the first triangle number to have over five divisors. 18 | # What is the value of the first triangle number to have over five hundred divisors? 19 | 20 | import ./lib/primes 21 | import tables 22 | 23 | 24 | proc count_divisors(n: int): int = 25 | var count_factors = newCountTable[int](initialSize = 64) 26 | 27 | for factor in primFac_pollardRho(n): 28 | count_factors.inc(factor) 29 | 30 | result = 1 31 | for val in count_factors.values: 32 | result *= val+1 33 | 34 | # for v in [1, 3, 6, 10, 15, 21, 28]: 35 | # echo count_divisors v 36 | 37 | var i = 1 38 | var triangle = 1 39 | 40 | while count_divisors(triangle) <= 500: 41 | i += 1 42 | triangle += i 43 | 44 | 45 | echo triangle -------------------------------------------------------------------------------- /src/pe013_large_sum.nim: -------------------------------------------------------------------------------- 1 | ## Large sum 2 | # 3 | # Work out the first ten digits of the sum of the following one-hundred 50-digit numbers. 4 | 5 | let nbs = [ 6 | "37107287533902102798797998220837590246510135740250", 7 | "46376937677490009712648124896970078050417018260538", 8 | "74324986199524741059474233309513058123726617309629", 9 | "91942213363574161572522430563301811072406154908250", 10 | "23067588207539346171171980310421047513778063246676", 11 | "89261670696623633820136378418383684178734361726757", 12 | "28112879812849979408065481931592621691275889832738", 13 | "44274228917432520321923589422876796487670272189318", 14 | "47451445736001306439091167216856844588711603153276", 15 | "70386486105843025439939619828917593665686757934951", 16 | "62176457141856560629502157223196586755079324193331", 17 | "64906352462741904929101432445813822663347944758178", 18 | "92575867718337217661963751590579239728245598838407", 19 | "58203565325359399008402633568948830189458628227828", 20 | "80181199384826282014278194139940567587151170094390", 21 | "35398664372827112653829987240784473053190104293586", 22 | "86515506006295864861532075273371959191420517255829", 23 | "71693888707715466499115593487603532921714970056938", 24 | "54370070576826684624621495650076471787294438377604", 25 | "53282654108756828443191190634694037855217779295145", 26 | "36123272525000296071075082563815656710885258350721", 27 | "45876576172410976447339110607218265236877223636045", 28 | "17423706905851860660448207621209813287860733969412", 29 | "81142660418086830619328460811191061556940512689692", 30 | "51934325451728388641918047049293215058642563049483", 31 | "62467221648435076201727918039944693004732956340691", 32 | "15732444386908125794514089057706229429197107928209", 33 | "55037687525678773091862540744969844508330393682126", 34 | "18336384825330154686196124348767681297534375946515", 35 | "80386287592878490201521685554828717201219257766954", 36 | "78182833757993103614740356856449095527097864797581", 37 | "16726320100436897842553539920931837441497806860984", 38 | "48403098129077791799088218795327364475675590848030", 39 | "87086987551392711854517078544161852424320693150332", 40 | "59959406895756536782107074926966537676326235447210", 41 | "69793950679652694742597709739166693763042633987085", 42 | "41052684708299085211399427365734116182760315001271", 43 | "65378607361501080857009149939512557028198746004375", 44 | "35829035317434717326932123578154982629742552737307", 45 | "94953759765105305946966067683156574377167401875275", 46 | "88902802571733229619176668713819931811048770190271", 47 | "25267680276078003013678680992525463401061632866526", 48 | "36270218540497705585629946580636237993140746255962", 49 | "24074486908231174977792365466257246923322810917141", 50 | "91430288197103288597806669760892938638285025333403", 51 | "34413065578016127815921815005561868836468420090470", 52 | "23053081172816430487623791969842487255036638784583", 53 | "11487696932154902810424020138335124462181441773470", 54 | "63783299490636259666498587618221225225512486764533", 55 | "67720186971698544312419572409913959008952310058822", 56 | "95548255300263520781532296796249481641953868218774", 57 | "76085327132285723110424803456124867697064507995236", 58 | "37774242535411291684276865538926205024910326572967", 59 | "23701913275725675285653248258265463092207058596522", 60 | "29798860272258331913126375147341994889534765745501", 61 | "18495701454879288984856827726077713721403798879715", 62 | "38298203783031473527721580348144513491373226651381", 63 | "34829543829199918180278916522431027392251122869539", 64 | "40957953066405232632538044100059654939159879593635", 65 | "29746152185502371307642255121183693803580388584903", 66 | "41698116222072977186158236678424689157993532961922", 67 | "62467957194401269043877107275048102390895523597457", 68 | "23189706772547915061505504953922979530901129967519", 69 | "86188088225875314529584099251203829009407770775672", 70 | "11306739708304724483816533873502340845647058077308", 71 | "82959174767140363198008187129011875491310547126581", 72 | "97623331044818386269515456334926366572897563400500", 73 | "42846280183517070527831839425882145521227251250327", 74 | "55121603546981200581762165212827652751691296897789", 75 | "32238195734329339946437501907836945765883352399886", 76 | "75506164965184775180738168837861091527357929701337", 77 | "62177842752192623401942399639168044983993173312731", 78 | "32924185707147349566916674687634660915035914677504", 79 | "99518671430235219628894890102423325116913619626622", 80 | "73267460800591547471830798392868535206946944540724", 81 | "76841822524674417161514036427982273348055556214818", 82 | "97142617910342598647204516893989422179826088076852", 83 | "87783646182799346313767754307809363333018982642090", 84 | "10848802521674670883215120185883543223812876952786", 85 | "71329612474782464538636993009049310363619763878039", 86 | "62184073572399794223406235393808339651327408011116", 87 | "66627891981488087797941876876144230030984490851411", 88 | "60661826293682836764744779239180335110989069790714", 89 | "85786944089552990653640447425576083659976645795096", 90 | "66024396409905389607120198219976047599490197230297", 91 | "64913982680032973156037120041377903785566085089252", 92 | "16730939319872750275468906903707539413042652315011", 93 | "94809377245048795150954100921645863754710598436791", 94 | "78639167021187492431995700641917969777599028300699", 95 | "15368713711936614952811305876380278410754449733078", 96 | "40789923115535562561142322423255033685442488917353", 97 | "44889911501440648020369068063960672322193204149535", 98 | "41503128880339536053299340368006977710650566631954", 99 | "81234880673210146739058568557934581403627822703280", 100 | "82616570773948327592232845941706525094512325230608", 101 | "22918802058777319719839450180888072429661980811197", 102 | "77158542502016545090413245809786882778948721859617", 103 | "72107838435069186155435662884062257473692284509516", 104 | "20849603980134001723930671666823555245252804609722", 105 | "53503534226472524250874054075591789781264330331690" 106 | ] 107 | 108 | import lib/digits 109 | 110 | template charToInt(c: char): int = 111 | # char '0' .. '9' have an byte offset 112 | # '0'.int == 48 113 | c.int - '0'.int 114 | 115 | 116 | proc addStrArray[N, D: static[int]](a: array[N, string]): array[2*D, int]= 117 | # N: number of numbers 118 | # D: digits per number 119 | var i = 1 120 | var carry: int 121 | var sum: int 122 | 123 | while i <= D or carry > 0: 124 | if i <= D: 125 | sum = carry 126 | for nb in a: 127 | sum += nb[^i].charToInt 128 | (result[^i], carry) = sum.divmod10 129 | else: 130 | (result[^i], carry) = carry.divmod10 131 | inc i 132 | 133 | 134 | 135 | # let a = ["777777", 136 | # "777777" 137 | # ] 138 | # echo "\n ###########" 139 | # echo addStrArray[2, 6](a) 140 | 141 | # import strutils 142 | # echo a[0].parseInt+a[1].parseInt 143 | 144 | let ans = addStrArray[100, 50](nbs) 145 | 146 | echo ans -------------------------------------------------------------------------------- /src/pe014_longest_collatz_sequence.nim: -------------------------------------------------------------------------------- 1 | ## Longest Collatz sequence 2 | # 3 | # The following iterative sequence is defined for the set of positive integers: 4 | # 5 | # n → n/2 (n is even) 6 | # n → 3n + 1 (n is odd) 7 | # 8 | # Using the rule above and starting with 13, we generate the following sequence: 9 | # 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 10 | # 11 | # It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1. 12 | # 13 | # Which starting number, under one million, produces the longest chain? 14 | 15 | 16 | import sequtils 17 | from lib/integer_math import isEven 18 | 19 | proc collatz(n: int): int = 20 | result = 1 # n 21 | 22 | var a = n 23 | 24 | while a != 1: 25 | if a.isEven: 26 | a = a shr 1 27 | else: 28 | a = 3*a + 1 29 | inc result 30 | inc result # Last item is 1 31 | 32 | proc maxCollatz(a, b: int): int = 33 | if a.collatz >= b.collatz: 34 | return a 35 | return b 36 | 37 | echo toSeq(2..1_000_000).foldl(maxCollatz(a,b), 1) 38 | 39 | # TODO: use hashmap to cache/memoize the results -------------------------------------------------------------------------------- /src/pe015_lattice_paths.nim: -------------------------------------------------------------------------------- 1 | # Lattice paths: 2 | # Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner. 3 | # How many such routes are there through a 20×20 grid? 4 | 5 | # Count of lattice paths from (0,0) to (n,k) with only 2 directions allowed 6 | # is the binomial coef (n+k, n) i.e C(n+k, n) = (n+k)! / n!(n+k - n)! 7 | # with a square grid k = n so C(2n, n) = (2n)! / n!n! 8 | 9 | import lib/binomial 10 | 11 | echo binomialCoeff(40,20) -------------------------------------------------------------------------------- /src/pe016_power_digit_sum.nim: -------------------------------------------------------------------------------- 1 | # Power digit sum 2 | 3 | # 2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26. 4 | 5 | # What is the sum of the digits of the number 2^1000? 6 | 7 | ## Strategy: 8 | # 2^1 = 2 9 | # 2^2 = 2 + 2 10 | # 2^3 = (2 + 2) + (2 + 2) 11 | 12 | # i.e.: 2^n = 2^(n-1) + 2^(n-1) 13 | 14 | import lib/digits 15 | import sequtils 16 | 17 | proc addArray[N: static[int]](a, b: array[N, int]): array[N, int] = 18 | # N: number of digits 19 | # Note: it will overflow if N is too small and last addition has a carry 20 | # Having that automatically grow with N+1 is easy here 21 | # but will make the proc hard to use in practice 22 | var i = 1 23 | var carry: int 24 | var sum: int 25 | 26 | while i <= N or carry > 0: 27 | if i <= N: 28 | sum = carry + a[^i] + b[^i] 29 | (result[^i], carry) = sum.divmod10 30 | else: 31 | (result[^i], carry) = carry.divmod10 32 | inc i 33 | 34 | # let a = [4,5,2,1] 35 | # echo addArray(a,a) 36 | # echo 4521+4521 37 | 38 | proc bigint_2pow1000: array[1000, int] = 39 | result[^1] = 2 40 | 41 | for e in 2..1000: 42 | result = addArray(result, result) 43 | 44 | 45 | echo bigint_2pow1000().foldl(a + b) -------------------------------------------------------------------------------- /src/pe017_number_letter_counts.nim: -------------------------------------------------------------------------------- 1 | ## Number letter counts 2 | 3 | # If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total. 4 | # 5 | # If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used? 6 | # 7 | # NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage. 8 | 9 | 10 | import tables, sequtils 11 | 12 | let map = { # 1000: "thousand", 13 | 100: "hundred", 14 | 90: "ninety", 15 | 80: "eighty", 16 | 70: "seventy", 17 | 60: "sixty", 18 | 50: "fifty", 19 | 40: "forty", 20 | 30: "thirty", 21 | 20: "twenty", 22 | 19: "nineteen", 23 | 18: "eighteen", 24 | 17: "seventeen", 25 | 16: "sixteen", 26 | 15: "fifteen", 27 | 14: "fourteen", 28 | 13: "thirteen", 29 | 12: "twelve", 30 | 11: "eleven", 31 | 10: "ten", 32 | 9: "nine", 33 | 8: "eight", 34 | 7: "seven", 35 | 6: "six", 36 | 5: "five", 37 | 4: "four", 38 | 3: "three", 39 | 2: "two", 40 | 1: "one" 41 | # 0 is never written 42 | }.toTable 43 | 44 | proc n_to_string(n: Positive): string = 45 | result = "" 46 | 47 | if n == 1000: 48 | return "onethousand" 49 | 50 | let hundreds = n div 100 51 | if hundreds > 0: 52 | result &= map[hundreds] & "hundred" 53 | 54 | let mod100 = n mod 100 55 | if map.contains(mod100): 56 | if result != "": 57 | result &= "and" 58 | result &= map[mod100] 59 | return 60 | 61 | let tens = mod100 div 10 62 | if tens > 0: 63 | if result != "": 64 | result &= "and" 65 | result &= map[tens * 10] 66 | 67 | let units = n mod 10 68 | if units > 0: 69 | result &= map[units] 70 | 71 | 72 | echo toSeq(1..1000).foldl(a + b.n_to_string.len, 0) 73 | --------------------------------------------------------------------------------