fix(curriculum): rework Project Euler 61 (#42397)

This commit is contained in:
gikf
2021-06-14 08:31:28 +02:00
committed by GitHub
parent c4cf53a742
commit 2613622ef0

View File

@ -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(3n1)}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(2n1)$ | 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(5n3)}{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(3n2)$ | 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;
}
``` ```