From 3866e8b43183077cffa4dc94aa9ceb592aa8c148 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Sat, 15 Oct 2022 17:31:47 -0500 Subject: [PATCH 1/8] [CREATE] Problem 28 solution for Project Euler --- Project-Euler/Problem028.js | 35 +++++++++++++++++++++++++++ Project-Euler/test/Problem028.test.js | 17 +++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 Project-Euler/Problem028.js create mode 100644 Project-Euler/test/Problem028.test.js diff --git a/Project-Euler/Problem028.js b/Project-Euler/Problem028.js new file mode 100644 index 0000000000..79b3637df1 --- /dev/null +++ b/Project-Euler/Problem028.js @@ -0,0 +1,35 @@ +/** + * Problem 28 - Number spiral diagonals + * + * @see {@link https://projecteuler.net/problem=28} + * + * Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows: + * + * 21 22 23 24 25 + * 20 07 08 09 10 + * 19 06 01 02 11 + * 18 05 04 03 12 + * 17 16 15 14 13 + * + * It can be verified that the sum of the numbers on the diagonals is 101. + * What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way? + * + * @author ddaniel27 + */ + +function problem28 (dim) { + if (dim % 2 === 0) { + throw new Error('Dimension must be odd') + } + if (dim < 1) { + throw new Error('Dimension must be positive') + } + + let result = 1 + for (let i = 3; i <= dim; i += 2) { + result += (4 * i * i) + 6 * (1 - i) // Calculate sum of each dimension corner + } + return result +} + +export { problem28 } diff --git a/Project-Euler/test/Problem028.test.js b/Project-Euler/test/Problem028.test.js new file mode 100644 index 0000000000..ad99654598 --- /dev/null +++ b/Project-Euler/test/Problem028.test.js @@ -0,0 +1,17 @@ +import { problem28 } from '../Problem028.js' + +describe('checking number spiral diagonals', () => { + it('should be invalid input if number is negative', () => { + expect(() => problem28(-3)).toThrowError('Dimension must be positive') + }) + it('should be invalid input if number is not odd', () => { + expect(() => problem28(4)).toThrowError('Dimension must be odd') + }) + test('if the number is equal to 5 result should be 101', () => { + expect(problem28(5)).toBe(101) + }) + // Project Euler Condition Check + test('if the number is equal to 1001 result should be 669171001', () => { + expect(problem28(1001)).toBe(669171001) + }) +}) From 3418cdd9a6e749e8d9a8e37edb65c3d69233fc78 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Sun, 16 Oct 2022 08:03:55 -0500 Subject: [PATCH 2/8] [UPDATE] Added an explanation for the formula used in the algorithm --- Project-Euler/Problem028.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Project-Euler/Problem028.js b/Project-Euler/Problem028.js index 79b3637df1..e55f31b959 100644 --- a/Project-Euler/Problem028.js +++ b/Project-Euler/Problem028.js @@ -27,6 +27,24 @@ function problem28 (dim) { let result = 1 for (let i = 3; i <= dim; i += 2) { + /** + * Adding more dimensions to the matrix, we will find at the top-right corner the follow sequence: + * 01, 09, 25, 49, 81, 121, 169, ... + * So this can be expressed as: + * i^2, where i is all odd numbers + * + * Also, we can know which numbers are in each corner dimension + * Just develop the sequence counter clockwise from top-right corner like this: + * First corner: i^2 + * Second corner: i^2 - (i - 1) | The "i - 1" is the distance between corners in each dimension + * Third corner: i^2 - 2 * (i - 1) + * Fourth corner: i^2 - 3 * (i - 1) + * + * Doing the sum of each corner and simplifing, we found that the result for each dimension is: + * sumDim = 4 * i^2 + 6 * (1 - i) + * + * In this case I skip the 1x1 dim matrix because is trivial, that's why I start in a 3x3 matrix + */ result += (4 * i * i) + 6 * (1 - i) // Calculate sum of each dimension corner } return result From 88fce402795425b44c33acb929215c1fcd7e3b87 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Sun, 16 Oct 2022 16:04:14 -0500 Subject: [PATCH 3/8] [CREATE] Added Problem 35 for Project-Euler --- Project-Euler/Problem035.js | 53 +++++++++++++++++++++++++++ Project-Euler/test/Problem035.test.js | 18 +++++++++ 2 files changed, 71 insertions(+) create mode 100644 Project-Euler/Problem035.js create mode 100644 Project-Euler/test/Problem035.test.js diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js new file mode 100644 index 0000000000..b2e73a3797 --- /dev/null +++ b/Project-Euler/Problem035.js @@ -0,0 +1,53 @@ +/** + * Problem 35 - Circular primes + * + * @see {@link https://projecteuler.net/problem=35} + * + * The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime. + * There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97. + * How many circular primes are there below one million? + * + * @author ddaniel27 + */ + +/** + * Function to get all prime numbers below a given number + * This function also discards all numbers that contain an even digit + * @see {@link https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes} + */ +function getPrimes (max) { + const sieve = [] + const primes = [] + + for (let i = 2; i <= max; ++i) { + if (!sieve[i]) { // If i has not been marked then it is prime + const hasEven = String(i).split('').some((n) => n % 2 === 0) // Check if i contains an even digit + !hasEven && primes.push(i) + + for (let j = i << 1; j <= max; j += i) { // Mark all multiples of i as non-prime + sieve[j] = true + } + } + } + return primes +} + +function problem35 (n) { + if (n < 2) { + throw new Error('Invalid input') + } + const list = getPrimes(n) + + const result = list.filter((number, _idx, arr) => { + const str = String(number) + const rotations = [] + for (let i = 0; i < str.length; i++) { // Get all rotations of the number + rotations.push(str.slice(i) + str.slice(0, i)) + } + return rotations.every((rotation) => arr.includes(Number(rotation))) // Check if all rotations are prime + }) + + return result.length + 1 // Add +1 to the result because 2 is not included in the list +} + +export { problem35 } diff --git a/Project-Euler/test/Problem035.test.js b/Project-Euler/test/Problem035.test.js new file mode 100644 index 0000000000..2d5745884c --- /dev/null +++ b/Project-Euler/test/Problem035.test.js @@ -0,0 +1,18 @@ +import { problem35 } from '../Problem035.js' + +describe('checking circular primes', () => { + it('should be invalid input if number is negative', () => { + expect(() => problem35(-3)).toThrowError('Invalid Input') + }) + it('should be invalid input if number is 0', () => { + expect(() => problem35(0)).toThrowError('Invalid Input') + }) + // Project Euler Condition Check + test('if the number is equal to 100 result should be 13', () => { + expect(problem35(100)).toBe(13) + }) + // Project Euler Challenge Check + test('if the number is equal to one million result should be 55', () => { + expect(problem35(1000000)).toBe(55) + }) +}) From 58d370ab584ff6a1935bcf5d3c5ec0f91960858a Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Sun, 16 Oct 2022 20:42:36 -0500 Subject: [PATCH 4/8] [UPDATE] Little typo in the error string --- Project-Euler/Problem035.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js index b2e73a3797..2a39e49089 100644 --- a/Project-Euler/Problem035.js +++ b/Project-Euler/Problem035.js @@ -34,7 +34,7 @@ function getPrimes (max) { function problem35 (n) { if (n < 2) { - throw new Error('Invalid input') + throw new Error('Invalid Input') } const list = getPrimes(n) From f5f8d3695be69dc5f4fbf316cb17c7ce3677d291 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Mon, 17 Oct 2022 11:07:03 -0500 Subject: [PATCH 5/8] [UPDATE] Some algorithm changes --- Project-Euler/Problem035.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js index 2a39e49089..86aa68ac23 100644 --- a/Project-Euler/Problem035.js +++ b/Project-Euler/Problem035.js @@ -15,14 +15,16 @@ * This function also discards all numbers that contain an even digit * @see {@link https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes} */ -function getPrimes (max) { +function getOddPrimes (max) { const sieve = [] const primes = [] for (let i = 2; i <= max; ++i) { if (!sieve[i]) { // If i has not been marked then it is prime const hasEven = String(i).split('').some((n) => n % 2 === 0) // Check if i contains an even digit - !hasEven && primes.push(i) + if (!hasEven) { + primes.push(i) + } for (let j = i << 1; j <= max; j += i) { // Mark all multiples of i as non-prime sieve[j] = true @@ -34,17 +36,19 @@ function getPrimes (max) { function problem35 (n) { if (n < 2) { - throw new Error('Invalid Input') + throw new Error('Invalid input') } - const list = getPrimes(n) + const list = getOddPrimes(n) const result = list.filter((number, _idx, arr) => { const str = String(number) - const rotations = [] for (let i = 0; i < str.length; i++) { // Get all rotations of the number - rotations.push(str.slice(i) + str.slice(0, i)) + const rotation = str.slice(i) + str.slice(0, i) + if (!arr.includes(Number(rotation))) { // Check if the rotation is prime + return false + } } - return rotations.every((rotation) => arr.includes(Number(rotation))) // Check if all rotations are prime + return true // If all rotations are prime, then the number is circular prime }) return result.length + 1 // Add +1 to the result because 2 is not included in the list From b7776bde66a24c85360354928a9e1a690638f138 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Mon, 17 Oct 2022 11:41:45 -0500 Subject: [PATCH 6/8] [UPDATE] Fix test string --- Project-Euler/test/Problem035.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project-Euler/test/Problem035.test.js b/Project-Euler/test/Problem035.test.js index 2d5745884c..ebaa4ac46f 100644 --- a/Project-Euler/test/Problem035.test.js +++ b/Project-Euler/test/Problem035.test.js @@ -2,10 +2,10 @@ import { problem35 } from '../Problem035.js' describe('checking circular primes', () => { it('should be invalid input if number is negative', () => { - expect(() => problem35(-3)).toThrowError('Invalid Input') + expect(() => problem35(-3)).toThrowError('Invalid input') }) it('should be invalid input if number is 0', () => { - expect(() => problem35(0)).toThrowError('Invalid Input') + expect(() => problem35(0)).toThrowError('Invalid input') }) // Project Euler Condition Check test('if the number is equal to 100 result should be 13', () => { From aa5f9db2fa2eaefd02f82810600c0d06feb4b098 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Tue, 18 Oct 2022 08:45:35 -0500 Subject: [PATCH 7/8] [UPDATE] Change prime numbers generator to import a standard sieve algorithm. --- Project-Euler/Problem035.js | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js index 86aa68ac23..f2c7c0545c 100644 --- a/Project-Euler/Problem035.js +++ b/Project-Euler/Problem035.js @@ -9,36 +9,13 @@ * * @author ddaniel27 */ - -/** - * Function to get all prime numbers below a given number - * This function also discards all numbers that contain an even digit - * @see {@link https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes} - */ -function getOddPrimes (max) { - const sieve = [] - const primes = [] - - for (let i = 2; i <= max; ++i) { - if (!sieve[i]) { // If i has not been marked then it is prime - const hasEven = String(i).split('').some((n) => n % 2 === 0) // Check if i contains an even digit - if (!hasEven) { - primes.push(i) - } - - for (let j = i << 1; j <= max; j += i) { // Mark all multiples of i as non-prime - sieve[j] = true - } - } - } - return primes -} +import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenes' function problem35 (n) { if (n < 2) { throw new Error('Invalid input') } - const list = getOddPrimes(n) + const list = sieveOfEratosthenes(n) const result = list.filter((number, _idx, arr) => { const str = String(number) @@ -51,7 +28,7 @@ function problem35 (n) { return true // If all rotations are prime, then the number is circular prime }) - return result.length + 1 // Add +1 to the result because 2 is not included in the list + return result.length } export { problem35 } From b94e5f9c6fd46a65d0121008a1cca10fddbce908 Mon Sep 17 00:00:00 2001 From: Daniel Dorado Date: Mon, 24 Oct 2022 00:09:51 -0500 Subject: [PATCH 8/8] [UPDATE] Change sieve algorithm implementation and now the solution works well. Also added some optimizations --- Project-Euler/Problem035.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js index f2c7c0545c..b62a8f0312 100644 --- a/Project-Euler/Problem035.js +++ b/Project-Euler/Problem035.js @@ -9,13 +9,13 @@ * * @author ddaniel27 */ -import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenes' +import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenesIntArray' function problem35 (n) { if (n < 2) { throw new Error('Invalid input') } - const list = sieveOfEratosthenes(n) + const list = sieveOfEratosthenes(n).filter(prime => !prime.toString().match(/[024568]/)) // Get a list of primes without 0, 2, 4, 5, 6, 8 const result = list.filter((number, _idx, arr) => { const str = String(number) @@ -28,7 +28,7 @@ function problem35 (n) { return true // If all rotations are prime, then the number is circular prime }) - return result.length + return result.length + 1 // Add 2 to the result because 2 is a circular prime } export { problem35 }