-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #121 from amclin/feat/prep-2020
Solution for 2020 Day 1 parts 1 and 2
- Loading branch information
Showing
5 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
/** | ||
* Validates a list of records by comparing every combination | ||
* to the checksum. Stops when the first match is found | ||
* @param {array} records List of records to check | ||
* @param {int} checksum The target sum that records should add up to | ||
* @param {int} goal The number of records we hope to find | ||
*/ | ||
const validateRecords = (records, checksum = 2020, goal = 2) => { | ||
const results = [] | ||
|
||
// Intentionally using `function()` instead of `() =>` because | ||
// the thisArg won't get passed to the find callback otherwise | ||
// https://stackoverflow.com/questions/46639131/javascript-array-prototype-find-second-argument-thisarg-not-working | ||
function matcher (record) { | ||
this.depth = this.depth || 1 // depth tracking starts at level 1 | ||
this.tracker = this.tracker || 0 // for basic sums, start counter at 0 | ||
const subTotal = this.tracker + record | ||
// Found a match in the specified with desired qty of results, don't keep searching! | ||
if (subTotal === this.target && this.depth >= goal) { | ||
results.push(record) | ||
return true | ||
} | ||
// When subtotal exceeds target, return immediately and don't waste time | ||
// on more loops that won't get results | ||
if (subTotal > this.target) { | ||
return false | ||
} | ||
// If we're already at max depth, don't waste time on more loops | ||
if (this.depth >= this.maxDepth) { | ||
return false | ||
} | ||
// Check the next level down | ||
const res = records.find(matcher, { | ||
maxDepth: this.maxDepth, | ||
target: this.target, | ||
depth: this.depth + 1, | ||
tracker: this.tracker + record | ||
}) | ||
// Propogate maches back up the recursion chain, capturing each | ||
if (res) { | ||
results.push(record) | ||
return true | ||
} | ||
// Nothing found with this combo, step to the next sibling | ||
return false | ||
} | ||
|
||
// Parse the records to find results | ||
records.find(matcher, { | ||
maxDepth: goal, | ||
target: checksum | ||
}) | ||
|
||
if (results.length < 2) { | ||
throw new Error('Couldn\'t find a checksum match') | ||
} | ||
return results | ||
} | ||
|
||
module.exports = { | ||
validateRecords | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* eslint-env mocha */ | ||
const { expect } = require('chai') | ||
const { validateRecords } = require('./expenseValidation') | ||
|
||
/** | ||
* Sum all the values in an array | ||
*/ | ||
const arrSum = (arr) => arr.reduce((x, y) => x + y, 0) | ||
/** | ||
* Multiply all the values in an array | ||
*/ | ||
const arrMult = (arr) => arr.reduce((x, y) => x * y, 1) | ||
const testData = [ | ||
1721, | ||
979, | ||
366, | ||
299, | ||
675, | ||
1456 | ||
] | ||
|
||
describe('--- 2020 Day 1: Report Repair ---', () => { | ||
describe('Part 1', () => { | ||
describe('validateRecords()', () => { | ||
it('it finds the two records that sum to 2020', () => { | ||
const expected = [1721, 299] | ||
const results = validateRecords(testData, undefined, 2) | ||
// Should be 2 results | ||
expect(results.length).to.equal(2) | ||
// Result order is unnecessary, but all expected hould be in the result set | ||
expected.forEach(result => { | ||
expect(testData.indexOf(result)).to.be.greaterThan(-1) | ||
}) | ||
// Results add up to the checksum | ||
expect(arrSum(results)).to.equal(2020) | ||
// Confirm the multiplied total | ||
expect(arrMult(results)).to.equal(514579) | ||
}) | ||
it('it supports specifying an alternate checksum', () => { | ||
const expected = [testData[3], testData[5]] | ||
const checksum = arrSum(expected) | ||
const results = validateRecords(testData, checksum) | ||
// Should be 2 results | ||
expect(results.length).to.equal(2) | ||
// Result order is unnecessary, but all expected hould be in the result set | ||
expected.forEach(result => { | ||
expect(results.indexOf(result)).to.be.greaterThan(-1) | ||
}) | ||
// Results add up to the checksum | ||
expect(arrSum(results)).to.equal(checksum) | ||
}) | ||
it('Throws an error when no records provided', () => { | ||
expect(validateRecords).to.throw() | ||
}) | ||
it('Throws an error when no records match checksum', () => { | ||
expect(() => validateRecords([1, 2, 3], 100)).to.throw('Couldn\'t find a checksum match') | ||
}) | ||
}) | ||
}) | ||
describe('Part 2', () => { | ||
describe('validateRecords()', () => { | ||
it('it can find a specified number of records adding up to 2020', () => { | ||
const expected = [979, 366, 675] | ||
const results = validateRecords(testData, undefined, 3) | ||
// Should same number of results | ||
expect(results.length).to.equal(expected.length) | ||
// Result order is unnecessary, but all expected hould be in the result set | ||
expected.forEach(result => { | ||
expect(testData.indexOf(result)).to.be.greaterThan(-1) | ||
}) | ||
// Results add up to the checksum | ||
expect(arrSum(results)).to.equal(2020) | ||
// Confirm the multiplied total | ||
expect(arrMult(results)).to.equal(241861950) | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require('./solution') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
1539 | ||
1914 | ||
1866 | ||
1407 | ||
1706 | ||
1423 | ||
1834 | ||
1700 | ||
1573 | ||
1486 | ||
1743 | ||
1394 | ||
1693 | ||
1705 | ||
1530 | ||
1811 | ||
1626 | ||
1473 | ||
1901 | ||
1481 | ||
1527 | ||
1841 | ||
1891 | ||
1750 | ||
1343 | ||
1899 | ||
401 | ||
1896 | ||
1627 | ||
1593 | ||
1541 | ||
874 | ||
1484 | ||
1210 | ||
1692 | ||
1963 | ||
1964 | ||
1780 | ||
671 | ||
1862 | ||
1393 | ||
1309 | ||
1740 | ||
1831 | ||
1932 | ||
1185 | ||
1979 | ||
1504 | ||
1663 | ||
1610 | ||
1494 | ||
1511 | ||
1103 | ||
1738 | ||
1816 | ||
1871 | ||
1545 | ||
1595 | ||
1784 | ||
1412 | ||
1815 | ||
1998 | ||
1783 | ||
1770 | ||
1426 | ||
1699 | ||
1416 | ||
1880 | ||
1612 | ||
1989 | ||
1360 | ||
1869 | ||
1762 | ||
1690 | ||
1999 | ||
1990 | ||
1521 | ||
1730 | ||
703 | ||
1463 | ||
1670 | ||
1472 | ||
1413 | ||
1669 | ||
1502 | ||
1548 | ||
1475 | ||
1694 | ||
1314 | ||
1980 | ||
980 | ||
1667 | ||
890 | ||
1569 | ||
1456 | ||
1406 | ||
1924 | ||
1973 | ||
1965 | ||
1533 | ||
1827 | ||
2000 | ||
1847 | ||
1520 | ||
1729 | ||
1512 | ||
1555 | ||
1566 | ||
1505 | ||
1672 | ||
1169 | ||
1835 | ||
1850 | ||
1493 | ||
1861 | ||
1288 | ||
1675 | ||
1676 | ||
1556 | ||
1320 | ||
1757 | ||
1870 | ||
1642 | ||
1903 | ||
1372 | ||
1967 | ||
1894 | ||
176 | ||
1908 | ||
1418 | ||
1535 | ||
1487 | ||
1496 | ||
1491 | ||
1611 | ||
1970 | ||
1758 | ||
1563 | ||
1766 | ||
1629 | ||
1937 | ||
1763 | ||
1829 | ||
1772 | ||
1632 | ||
1517 | ||
1736 | ||
1971 | ||
1721 | ||
1716 | ||
1429 | ||
1408 | ||
1560 | ||
1958 | ||
1359 | ||
1890 | ||
1825 | ||
1536 | ||
1819 | ||
1697 | ||
1887 | ||
1832 | ||
2005 | ||
892 | ||
1471 | ||
1425 | ||
1677 | ||
1673 | ||
1128 | ||
1878 | ||
1062 | ||
1470 | ||
1875 | ||
1854 | ||
1518 | ||
1568 | ||
1919 | ||
256 | ||
1532 | ||
1711 | ||
1944 | ||
1344 | ||
1330 | ||
1636 | ||
1957 | ||
1709 | ||
1551 | ||
1983 | ||
1674 | ||
1671 | ||
1959 | ||
1760 | ||
1689 | ||
1767 | ||
1477 | ||
1589 | ||
1897 | ||
1144 | ||
1982 | ||
1544 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
const fs = require('fs') | ||
const path = require('path') | ||
const filePath = path.join(__dirname, 'input.txt') | ||
const { validateRecords } = require('./expenseValidation') | ||
const { inputToArray } = require('../../2018/inputParser') | ||
|
||
fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => { | ||
if (err) throw err | ||
|
||
initData = inputToArray(initData.trim()) | ||
.map(el => Number(el)) | ||
|
||
const resetInput = () => { | ||
// Deep copy to ensure we aren't mutating the original data | ||
return JSON.parse(JSON.stringify(initData)) | ||
} | ||
|
||
const part1 = () => { | ||
const data = resetInput() | ||
return validateRecords(data) // Find 2 results for 2020 | ||
.reduce((total, res) => total * res, 1) | ||
} | ||
|
||
const part2 = () => { | ||
const data = resetInput() | ||
return validateRecords(data, undefined, 3) // Find 3 results for 2020 | ||
.reduce((total, res) => total * res, 1) | ||
} | ||
const answers = [] | ||
answers.push(part1()) | ||
answers.push(part2()) | ||
|
||
answers.forEach((ans, idx) => { | ||
console.info(`-- Part ${idx + 1} --`) | ||
console.info(`Answer: ${ans}`) | ||
}) | ||
}) |