fix(curriculum): rework Project Euler 61 (#42397)
This commit is contained in:
		@@ -10,37 +10,53 @@ dashedName: problem-61-cyclical-figurate-numbers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
 | 
					Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Type of Number | Formula                                                               | Sequence              |
 | 
					| Type of Number | Formula                      | Sequence              |
 | 
				
			||||||
| -------------- | --------------------------------------------------------------------- | --------------------- |
 | 
					| -------------- | ---------------------------- | --------------------- |
 | 
				
			||||||
| Triangle       | P<sub>3</sub>,<var><sub>n</sub></var>=<var>n</var>(<var>n</var>+1)/2  | 1, 3, 6, 10, 15, ...  |
 | 
					| Triangle       | $P_3(n) = \frac{n(n+1)}{2}$  | 1, 3, 6, 10, 15, ...  |
 | 
				
			||||||
| Square         | P<sub>4</sub>,<var><sub>n</sub></var>=<var>n</var><sup>2</sup>        | 1, 4, 9, 16, 25, ...  |
 | 
					| Square         | $P_4(n) = n^2$               | 1, 4, 9, 16, 25, ...  |
 | 
				
			||||||
| Pentagonal     | P<sub>5</sub>,<var><sub>n</sub></var>=<var>n</var>(3<var>n</var>−1)/2 | 1, 5, 12, 22, 35, ... |
 | 
					| Pentagonal     | $P_5(n) = \frac{n(3n−1)}2$   | 1, 5, 12, 22, 35, ... |
 | 
				
			||||||
| Hexagonal      | P<sub>6</sub>,<var><sub>n</sub></var>=<var>n</var>(2<var>n</var>−1)   | 1, 6, 15, 28, 45, ... |
 | 
					| Hexagonal      | $P_6(n) = n(2n−1)$           | 1, 6, 15, 28, 45, ... |
 | 
				
			||||||
| Heptagonal     | P<sub>7</sub>,<var><sub>n</sub></var>=<var>n</var>(5<var>n</var>−3)/2 | 1, 7, 18, 34, 55, ... |
 | 
					| Heptagonal     | $P_7(n) = \frac{n(5n−3)}{2}$ | 1, 7, 18, 34, 55, ... |
 | 
				
			||||||
| Octagonal      | P<sub>8</sub>,<var><sub>n</sub></var>=<var>n</var>(3<var>n</var>−2)   | 1, 8, 21, 40, 65, ... |
 | 
					| Octagonal      | $P_8(n) = n(3n−2)$           | 1, 8, 21, 40, 65, ... |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
 | 
					The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ol>
 | 
					1. The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
 | 
				
			||||||
  <li>The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).</li>
 | 
					2. Each polygonal type: triangle ($P_3(127) = 8128$), square ($P_4(91) = 8281$), and pentagonal ($P_5(44) = 2882$), is represented by a different number in the set.
 | 
				
			||||||
  <li>Each polygonal type: triangle (P<sub>3,127</sub> = 8128), square (P<sub>4,91</sub> = 8281), and pentagonal (P<sub>5,44</sub> = 2882), is represented by a different number in the set.</li>
 | 
					3. This is the only set of 4-digit numbers with this property.
 | 
				
			||||||
  <li>This is the only set of 4-digit numbers with this property.</li>
 | 
					 | 
				
			||||||
</ol>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
 | 
					Find the sum of all numbers in ordered sets of `n` cyclic 4-digit numbers for which each of the $P_3$ to $P_{n + 2}$ polygonal types, is represented by a different number in the set.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --hints--
 | 
					# --hints--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`cyclicalFigurateNums()` should return a number.
 | 
					`cyclicalFigurateNums(3)` should return a number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
assert(typeof cyclicalFigurateNums() === 'number');
 | 
					assert(typeof cyclicalFigurateNums(3) === 'number');
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`cyclicalFigurateNums()` should return 28684.
 | 
					`cyclicalFigurateNums(3)` should return `19291`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
assert.strictEqual(cyclicalFigurateNums(), 28684);
 | 
					assert.strictEqual(cyclicalFigurateNums(3), 19291);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`cyclicalFigurateNums(4)` should return `28684`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					assert.strictEqual(cyclicalFigurateNums(4), 28684);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`cyclicalFigurateNums(5)` should return `76255`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					assert.strictEqual(cyclicalFigurateNums(5), 76255);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`cyclicalFigurateNums(6)` should return `28684`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					assert.strictEqual(cyclicalFigurateNums(6), 28684);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --seed--
 | 
					# --seed--
 | 
				
			||||||
@@ -48,16 +64,189 @@ assert.strictEqual(cyclicalFigurateNums(), 28684);
 | 
				
			|||||||
## --seed-contents--
 | 
					## --seed-contents--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
function cyclicalFigurateNums() {
 | 
					function cyclicalFigurateNums(n) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cyclicalFigurateNums();
 | 
					cyclicalFigurateNums(3);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --solutions--
 | 
					# --solutions--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
// solution required
 | 
					function cyclicalFigurateNums(n) {
 | 
				
			||||||
 | 
					  function getChains(chain, n, numberTypes, numsExcludingLastNeededType) {
 | 
				
			||||||
 | 
					    if (chain.length === n) {
 | 
				
			||||||
 | 
					      return [chain];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const nextNumbers = getNextNumbersInChain(
 | 
				
			||||||
 | 
					      chain[chain.length - 1],
 | 
				
			||||||
 | 
					      numsExcludingLastNeededType
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const chains = [];
 | 
				
			||||||
 | 
					    for (let j = 0; j < nextNumbers.length; j++) {
 | 
				
			||||||
 | 
					      const nextNumber = nextNumbers[j];
 | 
				
			||||||
 | 
					      if (chain.indexOf(nextNumber) === -1) {
 | 
				
			||||||
 | 
					        const nextChain = [...chain, nextNumber];
 | 
				
			||||||
 | 
					        chains.push(
 | 
				
			||||||
 | 
					          ...getChains(nextChain, n, numberTypes, numsExcludingLastNeededType)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return chains;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function getNextNumbersInChain(num, numsExcludingLastNeededType) {
 | 
				
			||||||
 | 
					    const results = [];
 | 
				
			||||||
 | 
					    const beginning = num % 100;
 | 
				
			||||||
 | 
					    numsExcludingLastNeededType.forEach(number => {
 | 
				
			||||||
 | 
					      if (Math.floor(number / 100) === beginning) {
 | 
				
			||||||
 | 
					        results.push(number);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return results;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function fillNumberTypes(n, numberTypes, numsExcludingLastNeededType) {
 | 
				
			||||||
 | 
					    const [, lastTypeCheck, lastTypeArr] = numberTypes[n - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 1000; i <= 9999; i++) {
 | 
				
			||||||
 | 
					      for (let j = 0; j < n - 1; j++) {
 | 
				
			||||||
 | 
					        const [, typeCheck, typeArr] = numberTypes[j];
 | 
				
			||||||
 | 
					        if (typeCheck(i)) {
 | 
				
			||||||
 | 
					          typeArr.push(i);
 | 
				
			||||||
 | 
					          numsExcludingLastNeededType.add(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (lastTypeCheck(i)) {
 | 
				
			||||||
 | 
					        lastTypeArr.push(i);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isCyclicalChain(chain, n, numberTypes) {
 | 
				
			||||||
 | 
					    const numberTypesInChain = getNumberTypesInChain(chain, numberTypes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!isChainAllowed(numberTypesInChain, n)) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isChainCyclic =
 | 
				
			||||||
 | 
					      Math.floor(chain[0] / 100) === chain[chain.length - 1] % 100;
 | 
				
			||||||
 | 
					    return isChainCyclic;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function getNumberTypesInChain(chain, numberTypes) {
 | 
				
			||||||
 | 
					    const numbersInChain = {};
 | 
				
			||||||
 | 
					    for (let i = 0; i < numberTypes.length; i++) {
 | 
				
			||||||
 | 
					      const numberTypeName = numberTypes[i][0];
 | 
				
			||||||
 | 
					      numbersInChain[numberTypeName] = [];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 0; i < chain.length; i++) {
 | 
				
			||||||
 | 
					      for (let j = 0; j < n; j++) {
 | 
				
			||||||
 | 
					        const [typeName, , typeNumbers] = numberTypes[j];
 | 
				
			||||||
 | 
					        const typeNumbersInChain = numbersInChain[typeName];
 | 
				
			||||||
 | 
					        if (typeNumbers.indexOf(chain[i]) !== -1) {
 | 
				
			||||||
 | 
					          typeNumbersInChain.push(chain[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return numbersInChain;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isChainAllowed(numberTypesInChain, n) {
 | 
				
			||||||
 | 
					    for (let i = 0; i < n; i++) {
 | 
				
			||||||
 | 
					      const typeName = numberTypes[i][0];
 | 
				
			||||||
 | 
					      const isNumberWithTypeInChain = numberTypesInChain[typeName].length > 0;
 | 
				
			||||||
 | 
					      if (!isNumberWithTypeInChain) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let j = i + 1; j < n; j++) {
 | 
				
			||||||
 | 
					        const otherTypeName = numberTypes[j][0];
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					          isNumberRepeatedAsOnlyNumberInTwoTypes(
 | 
				
			||||||
 | 
					            numberTypesInChain[typeName],
 | 
				
			||||||
 | 
					            numberTypesInChain[otherTypeName]
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isNumberRepeatedAsOnlyNumberInTwoTypes(
 | 
				
			||||||
 | 
					    typeNumbers,
 | 
				
			||||||
 | 
					    otherTypeNumbers
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      typeNumbers.length === 1 &&
 | 
				
			||||||
 | 
					      otherTypeNumbers.length === 1 &&
 | 
				
			||||||
 | 
					      typeNumbers[0] === otherTypeNumbers[0]
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isTriangle(num) {
 | 
				
			||||||
 | 
					    return ((8 * num + 1) ** 0.5 - 1) % 2 === 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isSquare(num) {
 | 
				
			||||||
 | 
					    return num ** 0.5 === parseInt(num ** 0.5, 10);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isPentagonal(num) {
 | 
				
			||||||
 | 
					    return ((24 * num + 1) ** 0.5 + 1) % 6 === 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isHexagonal(num) {
 | 
				
			||||||
 | 
					    return ((8 * num + 1) ** 0.5 + 1) % 4 === 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isHeptagonal(num) {
 | 
				
			||||||
 | 
					    return ((40 * num + 9) ** 0.5 + 3) % 10 === 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function isOctagonal(num) {
 | 
				
			||||||
 | 
					    return ((3 * num + 1) ** 0.5 + 1) % 3 === 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const numberTypes = [
 | 
				
			||||||
 | 
					    ['triangle', isTriangle, []],
 | 
				
			||||||
 | 
					    ['square', isSquare, []],
 | 
				
			||||||
 | 
					    ['pentagonal', isPentagonal, []],
 | 
				
			||||||
 | 
					    ['hexagonal', isHexagonal, []],
 | 
				
			||||||
 | 
					    ['heptagonal', isHeptagonal, []],
 | 
				
			||||||
 | 
					    ['octagonal', isOctagonal, []]
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  const numsExcludingLastNeededType = new Set();
 | 
				
			||||||
 | 
					  fillNumberTypes(n, numberTypes, numsExcludingLastNeededType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const nNumberChains = [];
 | 
				
			||||||
 | 
					  const [, , lastType] = numberTypes[n - 1];
 | 
				
			||||||
 | 
					  for (let i = 0; i < lastType.length; i++) {
 | 
				
			||||||
 | 
					    const startOfChain = lastType[i];
 | 
				
			||||||
 | 
					    nNumberChains.push(
 | 
				
			||||||
 | 
					      ...getChains([startOfChain], n, numberTypes, numsExcludingLastNeededType)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const cyclicalChains = nNumberChains.filter(chain =>
 | 
				
			||||||
 | 
					    isCyclicalChain(chain, n, numberTypes)
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let sum = 0;
 | 
				
			||||||
 | 
					  for (let i = 0; i < cyclicalChains.length; i++) {
 | 
				
			||||||
 | 
					    for (let j = 0; j < cyclicalChains[0].length; j++) {
 | 
				
			||||||
 | 
					      sum += cyclicalChains[i][j];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return sum;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user