euler(14): longest collatz sequence
This commit is contained in:
parent
a636726cb7
commit
6a9e214501
4 changed files with 95 additions and 27 deletions
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
|
@ -1,3 +1,13 @@
|
||||||
{
|
{
|
||||||
"java.project.sourcePaths": ["java"]
|
"java.project.sourcePaths": ["java"],
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": true,
|
||||||
|
"**/.svn": true,
|
||||||
|
"**/.hg": true,
|
||||||
|
"**/CVS": true,
|
||||||
|
"**/.DS_Store": true,
|
||||||
|
"**/Thumbs.db": true,
|
||||||
|
"euler/node_modules": true,
|
||||||
|
"euler/python_archive": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "project-euler",
|
"name": "project-euler",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
"start": "node run"
|
"start": "node run.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^16.11.6",
|
"@types/node": "^16.11.6",
|
||||||
|
|
68
euler/run.js
68
euler/run.js
|
@ -1,8 +1,10 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const { spawnSync } = require('child_process');
|
const { spawnSync, spawn } = require('child_process');
|
||||||
const perf = require('execution-time')();
|
const perf = require('execution-time')();
|
||||||
|
|
||||||
|
// todo: move to ts-node
|
||||||
|
|
||||||
const run = (file, puzzleName) => {
|
const run = (file, puzzleName) => {
|
||||||
// Calculate the length of the divider for the puzzle
|
// Calculate the length of the divider for the puzzle
|
||||||
let divider = '--';
|
let divider = '--';
|
||||||
|
@ -26,33 +28,49 @@ const run = (file, puzzleName) => {
|
||||||
console.log(chalk.bold(chalk.yellow(`Executed in ${results.words}`)));
|
console.log(chalk.bold(chalk.yellow(`Executed in ${results.words}`)));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get files
|
new Promise(async resolve => {
|
||||||
const tsFiles = fs
|
// Rebuild the files
|
||||||
.readdirSync('src')
|
const gulp = spawn('npx', ['gulp-cli', 'build'], { shell: true, stdio: 'pipe' });
|
||||||
.filter(f => f.endsWith('.ts'))
|
|
||||||
.filter(f => f !== 'utils.ts');
|
|
||||||
const jsFiles = fs
|
|
||||||
.readdirSync('build')
|
|
||||||
.filter(f => f.endsWith('.js'))
|
|
||||||
.filter(f => f !== 'utils.js');
|
|
||||||
|
|
||||||
try {
|
gulp.stdout.on('data', data => {
|
||||||
// Extract the puzzle number
|
const message = data.toString();
|
||||||
const puzzleNumber = process.argv[2];
|
const match = message.match(/Starting '(.*)'/)?.[1];
|
||||||
if (isNaN(puzzleNumber)) throw Error();
|
if (match) console.log(chalk.red(`[gulp] Running '${match}' task`));
|
||||||
|
});
|
||||||
|
|
||||||
// Find the associated puzzle
|
gulp.on('close', () => {
|
||||||
const tsFile = tsFiles.filter(f => f.startsWith(puzzleNumber))[0];
|
console.log();
|
||||||
const puzzleName = tsFile.split('.ts')[0];
|
resolve();
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
// Get files
|
||||||
|
const tsFiles = fs
|
||||||
|
.readdirSync('src')
|
||||||
|
.filter(f => f.endsWith('.ts'))
|
||||||
|
.filter(f => f !== 'utils.ts');
|
||||||
|
const jsFiles = fs
|
||||||
|
.readdirSync('build')
|
||||||
|
.filter(f => f.endsWith('.js'))
|
||||||
|
.filter(f => f !== 'utils.js');
|
||||||
|
|
||||||
run(`${puzzleNumber}.js`, puzzleName);
|
try {
|
||||||
} catch (error) {
|
// Extract the puzzle number
|
||||||
for (let i = 0; i < jsFiles.length; i++) {
|
const puzzleNumber = process.argv[2];
|
||||||
const file = jsFiles[i];
|
if (isNaN(puzzleNumber)) throw Error();
|
||||||
const tsFile = tsFiles[i];
|
|
||||||
|
// Find the associated puzzle
|
||||||
|
const tsFile = tsFiles.filter(f => f.startsWith(puzzleNumber))[0];
|
||||||
const puzzleName = tsFile.split('.ts')[0];
|
const puzzleName = tsFile.split('.ts')[0];
|
||||||
|
|
||||||
run(file, puzzleName);
|
run(`${puzzleNumber}.js`, puzzleName);
|
||||||
console.log();
|
} catch (error) {
|
||||||
|
for (let i = 0; i < jsFiles.length; i++) {
|
||||||
|
const file = jsFiles[i];
|
||||||
|
const tsFile = tsFiles[i];
|
||||||
|
const puzzleName = tsFile.split('.ts')[0];
|
||||||
|
|
||||||
|
run(file, puzzleName);
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
40
euler/src/14 - Longest Collatz sequence.ts
Normal file
40
euler/src/14 - Longest Collatz sequence.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// n -> n/2 (if n is even)
|
||||||
|
// n -> 3n + 1 (if n is odd)
|
||||||
|
// Start at a number, iterate until 1
|
||||||
|
// Which starting number under one million has the longest chain?
|
||||||
|
|
||||||
|
export {};
|
||||||
|
|
||||||
|
const isEven = (n: number) => n % 2 === 0;
|
||||||
|
|
||||||
|
const collatzSequence = (startNumber: number) => {
|
||||||
|
let currentNumber = startNumber;
|
||||||
|
let sequence = [startNumber];
|
||||||
|
|
||||||
|
while (currentNumber > 1) {
|
||||||
|
if (isEven(currentNumber)) currentNumber = currentNumber / 2;
|
||||||
|
else currentNumber = currentNumber * 3 + 1;
|
||||||
|
|
||||||
|
sequence.push(currentNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
const longestCollatzUnderLimit = (limit: number) => {
|
||||||
|
let longestStartingNumber = -1;
|
||||||
|
let longestStartingNumberLength = -1;
|
||||||
|
|
||||||
|
for (let i = 1; i < limit; i++) {
|
||||||
|
const sequence = collatzSequence(i);
|
||||||
|
|
||||||
|
if (sequence.length > longestStartingNumberLength) {
|
||||||
|
longestStartingNumber = i;
|
||||||
|
longestStartingNumberLength = sequence.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return longestStartingNumberLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(longestCollatzUnderLimit(1000000));
|
Loading…
Reference in a new issue