Last active
February 16, 2021 06:06
-
-
Save bluenex/a6899814873fa9eb3b2368f1f2be48f7 to your computer and use it in GitHub Desktop.
A collection of snippets for Advent of Code 2020
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
function day1() { | |
var val = document.querySelector('pre').innerText; | |
var arr = val.split('\n').map(x => Number(x)); | |
var finder = (main, rest, target) => { | |
let result = null; | |
rest.forEach(x => { if (main + x === target) { result = [main, x] } }); | |
return result; | |
}; | |
let q1Answer; | |
for (let i = 0; i < arr.length; i++) { | |
var match = finder(arr[i], arr.slice(i+1), 2020); | |
// console.log(i, match); | |
if (match) { | |
q1Answer = match[0] * match[1]; | |
break; | |
} | |
} | |
let q2Answer; | |
var tripleFinder = (arr) => { | |
let result = null; | |
// https://stackoverflow.com/a/1564838/4010864 | |
mainLoop: | |
for (let ind1 = 0; ind1 < arr.length; ind1++) { | |
for (let ind2 = ind1 + 1; ind2 < arr.length; ind2++) { | |
var match = finder(arr[ind1] + arr[ind2], arr.slice(ind2 + 1), 2020); | |
if (match && !match.includes(0)) { | |
result = [arr[ind1], arr[ind2], match[1]] | |
break mainLoop; | |
} | |
} | |
} | |
return result; | |
} | |
var [i1, i2, i3] = tripleFinder(arr); | |
// console.log([i1, i2, i3]); | |
q2Answer = i1 * i2 * i3; | |
return { | |
q1: q1Answer, | |
q2: q2Answer, | |
}; | |
} | |
day1(); |
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
function day2() { | |
var data = document.querySelector('pre').innerText.split('\n'); | |
data = data.filter(x => x !== ""); | |
var checker = (line) => { | |
var [cond, pw] = line.split(':'); | |
var [limit, condChar] = cond.split(' '); | |
var [lowLimit, upLimit] = limit.split('-'); | |
var condCharCount = pw.split('').filter(x => x === condChar).length; | |
if (condCharCount >= Number(lowLimit) && condCharCount <= Number(upLimit)) { | |
return true; | |
} | |
return false; | |
} | |
let q1Answer; | |
q1Answer = data.filter((line) => checker(line)).length; | |
var officialPolicy = (line) => { | |
var [cond, pw] = line.split(': '); | |
var [indexes, condChar] = cond.split(' '); | |
var [ind1, ind2] = indexes.split('-'); | |
var charAtInd1 = pw[Number(ind1) - 1]; | |
var charAtInd2 = pw[Number(ind2) - 1]; | |
var matches = [charAtInd1 === condChar, charAtInd2 === condChar]; | |
var matchesTrue = matches.filter(x => x); | |
if (matchesTrue.length === 1) { | |
return true; | |
} | |
return false; | |
} | |
let q2Answer; | |
q2Answer = data.filter((line) => officialPolicy(line)).length; | |
return { | |
q1: q1Answer, | |
q2: q2Answer, | |
}; | |
} | |
day2(); |
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
function day3() { | |
var jungle = document.querySelector('pre').innerText.split('\n'); | |
jungle = jungle.filter(x => x !== '') | |
// what to do? | |
// - count the numnber of trees that we go across with the pattern 'right 3 down 1' | |
// thought | |
// - count the number of lines of jungle | |
// - count the number of chars of each jungle line | |
// - remember current position, if beyond number of chars, reset to 0 | |
// - count number of trees along the path | |
var traverse = (right, down) => { | |
let totalColumns = jungle[0].length; | |
let totalRows = jungle.length; | |
// [row, col] | |
let [currentRow, currentCol] = [0, 0]; | |
let encounteredTrees = 0; | |
let moveRight = (currentPosition, moveCount) => { | |
let newPosition = currentPosition + moveCount; | |
if (newPosition >= totalColumns) { | |
newPosition = newPosition % totalColumns; | |
} | |
return newPosition; | |
} | |
let moveDown = (currentPosition, moveCount) => { | |
return currentPosition + moveCount; | |
} | |
while (currentRow < totalRows) { | |
// move right | |
currentCol = moveRight(currentCol, right); | |
// move down | |
currentRow = moveDown(currentRow, down); | |
if (currentRow >= totalRows) { | |
console.log('done!'); | |
break; | |
} else { | |
// check if encounter tree | |
let currentPosition = jungle[currentRow][currentCol]; | |
if (currentPosition === '#') { | |
encounteredTrees += 1; | |
} | |
} | |
} | |
return encounteredTrees; | |
} | |
let slope31 = traverse(3, 1); | |
// q2 | |
// - Right 1, down 1. | |
// - Right 3, down 1. (This is the slope you already checked.) | |
// - Right 5, down 1. | |
// - Right 7, down 1. | |
// - Right 1, down 2. | |
let slope11 = traverse(1, 1); | |
let slope51 = traverse(5, 1); | |
let slope71 = traverse(7, 1); | |
let slope12 = traverse(1, 2); | |
console.log('slope11', slope11); | |
console.log('slope31', slope31); | |
console.log('slope51', slope51); | |
console.log('slope71', slope71); | |
console.log('slope12', slope12); | |
return { | |
q1: slope31, | |
q2: slope11 * slope31 * slope51 * slope71 * slope12, | |
}; | |
} | |
day3(); |
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
function day4() { | |
const data = document.querySelector('pre').innerText.trim().split('\n\n'); | |
const processedData = data.map(line => { | |
return line.split(/\s/).reduce((acc, cur) => { | |
const [label, val] = cur.split(':'); | |
return { | |
...acc, | |
[label]: val, | |
}; | |
}, {}) | |
}); | |
// - byr (Birth Year) | |
// - iyr (Issue Year) | |
// - eyr (Expiration Year) | |
// - hgt (Height) | |
// - hcl (Hair Color) | |
// - ecl (Eye Color) | |
// - pid (Passport ID) | |
// - cid (Country ID) -> optional due to North Pole Credentials | |
const requiredFields = ['byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid']; | |
let q1Answer; | |
const validFields = processedData | |
.filter(entry => requiredFields.every(field => Object.keys(entry).includes(field))); | |
q1Answer = validFields.length; | |
// q2 | |
// - byr (Birth Year) - four digits; at least 1920 and at most 2002. | |
// - iyr (Issue Year) - four digits; at least 2010 and at most 2020. | |
// - eyr (Expiration Year) - four digits; at least 2020 and at most 2030. | |
// - hgt (Height) - a number followed by either cm or in: | |
// - If cm, the number must be at least 150 and at most 193. | |
// - If in, the number must be at least 59 and at most 76. | |
// - hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. | |
// - ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. | |
// - pid (Passport ID) - a nine-digit number, including leading zeroes. | |
// - cid (Country ID) - ignored, missing or not. | |
const validator = ([key, val]) => { | |
if (key === 'byr') { | |
const yr = Number(val); | |
if (yr >= 1920 && yr <= 2002) { | |
return true; | |
} | |
} | |
if (key === 'iyr') { | |
const yr = Number(val); | |
if (yr >= 2010 && yr <= 2020) { | |
return true; | |
} | |
} | |
if (key === 'eyr') { | |
const yr = Number(val); | |
if (yr >= 2020 && yr <= 2030) { | |
return true; | |
} | |
} | |
if (key === 'hgt') { | |
const h = parseInt(val, 10); | |
if (val.includes('cm')) { | |
if (h >= 150 && h <= 193) { | |
return true; | |
} | |
} | |
if (val.includes('in')) { | |
if (h >= 59 && h <= 76) { | |
return true; | |
} | |
} | |
} | |
if (key === 'hcl') { | |
if (val.match(/#[0-9a-f]{6}/)) { | |
return true; | |
} | |
} | |
if (key === 'ecl') { | |
if (['amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'].some(x => val === x)) { | |
return true; | |
} | |
} | |
if (key === 'pid') { | |
if (val.length === 9) { | |
return true; | |
} | |
} | |
if (key === 'cid') { | |
return true; | |
} | |
return false; | |
} | |
const validatedData = validFields | |
.filter(each => Object.entries(each).every(([k, v]) => validator([k, v]))); | |
// console.log('processedData', processedData) | |
// console.log('validatedData', validatedData) | |
let q2Answer; | |
q2Answer = validatedData.length; | |
return { | |
q1: q1Answer, | |
q2: q2Answer, | |
}; | |
} | |
day4(); |
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
function day5() { | |
const boardingPasses = document.querySelector('pre').innerText.trim().split('\n'); | |
const maxRow = 128; | |
const maxCol = 8; | |
const avg = (arr) => arr.reduce((acc, cur) => acc + cur, 0) / arr.length; | |
const subDecoder = (splitCode, upperLimit, lowSign, highSign) => { | |
let [min, max] = [0, upperLimit - 1]; | |
for (let i = 0; i < splitCode.length; i++) { | |
if (splitCode[i] === lowSign) { | |
max = min + Math.floor((max - min) / 2); | |
} | |
if (splitCode[i] === highSign) { | |
min = min + Math.ceil((max - min) / 2); | |
} | |
// console.log(splitCode[i], min, max) | |
} | |
return avg([min, max]); | |
} | |
const decoder = (encodedSeat) => { | |
const rowCode = encodedSeat.slice(0, 7); | |
const colCode = encodedSeat.slice(7); | |
const row = subDecoder(rowCode, maxRow, 'F', 'B'); | |
const col = subDecoder(colCode, maxCol, 'L', 'R'); | |
const seatId = row * 8 + col; | |
return [row, col, seatId]; | |
} | |
const allSeatIds = boardingPasses.map(bdPass => decoder(bdPass)[2]); | |
// q2 | |
let q2Answer; | |
const sortedIds = allSeatIds.sort((a, b) => Number(a) > Number(b) ? 1 : -1); | |
for (let i = 0; i < sortedIds.length; i++) { | |
const cur = sortedIds[i]; | |
if (cur + 1 !== sortedIds[i + 1]) { | |
q2Answer = cur + 1; | |
break; | |
} | |
} | |
return { | |
q1: Math.max(...allSeatIds), | |
q2: q2Answer, | |
}; | |
} | |
day5(); |
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
function day6() { | |
const customDeclarations = document.querySelector('pre').innerText.trim().split('\n\n'); | |
// q1 | |
const processedData = customDeclarations.map(x => x.replace(/\s/g, '')); | |
const uniqueChar = (text) => text.split('').filter((el, i, array) => array.indexOf(el) === i); | |
const uniqueInGroup = processedData.map(x => uniqueChar(x).sort().join('')); | |
const countEachGroup = uniqueInGroup.map(x => x.length); | |
const q1Answer = countEachGroup.reduce((a,c) => a + c, 0); | |
// console.log(countEachGroup, q1Answer); | |
// q2 | |
const q2PreparedData = customDeclarations.map(x => x.split(/\s/g)); | |
const intersectChoices = (arr) => arr.reduce((acc, cur, ind) => { | |
if (acc === '' && ind === 0) { | |
// only for first loop | |
acc = cur; | |
} else { | |
acc.split('').forEach(x => { | |
if (!cur.includes(x)) { | |
acc = acc.replace(x, ''); | |
} | |
}) | |
cur.split('').forEach(x => { | |
if (!acc.includes(x)) { | |
acc = acc.replace(x, ''); | |
} | |
}) | |
} | |
return acc; | |
}, '').split('').sort().join(''); | |
const intersectInGroup = q2PreparedData.map(x => intersectChoices(x)); | |
const countIntersect = intersectInGroup.map(x => x.length); | |
const q2Answer = countIntersect.reduce((a,c) => a + c, 0); | |
// console.log(q2PreparedData); | |
// console.log(intersectInGroup); | |
return { | |
q1: q1Answer, | |
q2: q2Answer, | |
} | |
} | |
day6(); |
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
function day7() { | |
const data = document.querySelector('pre').innerText.trim().split('\n'); | |
const parser = (text) => { | |
const [thisBagColor, contentBagsColor] = text.replace(/bags?\.?/g, '').split(' contain '); | |
const parsedContentBags = contentBagsColor.split(',').reduce((a,c) => { | |
const [_, count, color] = c.trim().split(/(\d) /); | |
if (!color) { | |
return a; | |
} | |
return [ | |
...a, | |
[ | |
color.trim(), | |
parseInt(count, 10), | |
] | |
]; | |
}, []) | |
return [thisBagColor.trim(), parsedContentBags]; | |
} | |
const parsedData = data.map(x => parser(x)); | |
const unique = (arr) => arr.filter((el, i, array) => array.indexOf(el) === i); | |
let collection = []; | |
const recurFind = (targetColor) => { | |
const found = parsedData.filter(([color, content]) => content.some(x => x[0] === targetColor)); | |
// collect only name | |
collection = collection.concat(found.map(x => x[0])); | |
if (found.length > 0) { | |
found.forEach(([color, _]) => recurFind(color)); | |
} | |
} | |
recurFind('shiny gold', collection) | |
const q1Answer = unique(collection).length; | |
// q2 | |
let counter = 0; | |
const recurCount = (targetColor, factor) => { | |
const targetBag = parsedData.find(x => x[0] === targetColor); | |
const [name, content] = targetBag; | |
// console.log('current color:', targetColor); | |
content.forEach(([_, count]) => { | |
counter += (count * factor); | |
// console.log(`color ${_}, factor ${factor}, count ${count}`) | |
}); | |
// console.log('counter', counter, '\n----') | |
if (content.length > 0) { | |
content.forEach(([color, count]) => recurCount(color, factor * count)); | |
} | |
} | |
// start counting | |
recurCount('shiny gold', 1); | |
const q2Answer = counter; | |
return { | |
q1: q1Answer, | |
q2: q2Answer, | |
} | |
} | |
day7(); |
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
function day8() { | |
const data = document.querySelector('pre').innerText.trim().split('\n'); | |
const parser = (command) => { | |
const parsed = command.split(' '); | |
const val = parseInt(parsed[1], 10); | |
return [parsed[0], val]; | |
} | |
const runner = (code) => { | |
let acc = 0; | |
let opInd = 0; | |
let success = true; | |
let executed = []; | |
while (true) { | |
if (executed.includes(opInd)) { | |
success = false; | |
break; | |
} | |
executed.push(opInd); | |
try { | |
const [op, val] = parser(code[opInd]); | |
if (op === 'acc') { | |
acc += val; | |
opInd += 1; | |
} | |
if (op === 'nop') { | |
opInd += 1; | |
} | |
if (op === 'jmp') { | |
opInd += val; | |
} | |
} catch { | |
return [success, acc]; | |
} | |
} | |
return [success, acc]; | |
} | |
// q2 | |
let final = 0; | |
let curInd = 0; | |
while (true) { | |
const [op, val] = parser(data[curInd]); | |
if (op === 'jmp' || op === 'nop') { | |
const swp = op === 'jmp' ? 'nop' : 'jmp'; | |
const newData = [ | |
...data.slice(0, curInd), | |
`${swp} ${val}`, | |
...data.slice(curInd + 1), | |
]; | |
const [s, acc] = runner(newData); | |
if (s) { | |
console.log(`found success at ${curInd} from '${op} ${val}' to '${swp} ${val}'!`); | |
final = acc; | |
break; | |
} | |
} | |
curInd += 1; | |
if (curInd > data.length) { | |
break; | |
} | |
} | |
return { | |
q1: runner(data), | |
q2: final, | |
}; | |
} | |
day8(); |
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
function day9() { | |
const data = document.querySelector('pre').innerText.trim().split('\n').map(x => parseInt(x, 10)); | |
const validator = (current, preamble) => { | |
let currentIndex = 0; | |
let outOfBound = false; | |
while (!outOfBound) { | |
let starter = preamble[currentIndex]; | |
let rest = preamble.slice(currentIndex); | |
if (rest.some(x => x + starter === current)) { | |
return true; | |
} | |
currentIndex += 1; | |
if (currentIndex > preamble.length) { | |
outOfBound = true; | |
// console.log('out of bound!!'); | |
break; | |
} | |
} | |
return false; | |
} | |
const q1checker = () => { | |
let currentIndex = 25; | |
let outOfBound = false; | |
while(!outOfBound) { | |
let target = data[currentIndex]; | |
let preamble = data.slice(currentIndex - 25, currentIndex); | |
// console.log('target', target); | |
// console.log('preamble', preamble); | |
const result = validator(target, preamble); | |
// console.log('target:', target); | |
// console.log('preamble:', preamble); | |
// console.log('result:', result); | |
// console.log('----') | |
// if (currentIndex > 30) break; | |
if (!result) { | |
// console.log('first detect:', currentIndex); | |
return currentIndex; | |
} | |
currentIndex += 1; | |
if (currentIndex > data.length) { | |
outOfBound = true; | |
// console.log('out of bound!!'); | |
break; | |
} | |
} | |
} | |
const q1AnomalyIndex = q1checker(); | |
const q1AnomalyNumber = data[q1AnomalyIndex]; | |
// q2 | |
const q2Validator = (target, arr) => { | |
const sumArr = arr.reduce((acc, cur) => acc + cur, 0); | |
if (sumArr === target) { | |
return true; | |
} | |
return false; | |
} | |
const contiguousFinder = () => { | |
let currentIndex = 0; | |
let extender = 2; | |
let primaryOutBound = false; | |
let finalOutBound = false; | |
while (!finalOutBound) { | |
const contiguousArr = data.slice(currentIndex, currentIndex + extender); | |
const result = q2Validator(q1AnomalyNumber, contiguousArr); | |
// console.log(currentIndex, currentIndex + extender); | |
// console.log(contiguousArr); | |
// console.log('----'); | |
if (!result) { | |
if (!primaryOutBound) { | |
extender += 1; | |
} else { | |
// reset | |
extender = 2; | |
currentIndex += 1; | |
primaryOutBound = false; | |
} | |
} else { | |
return [currentIndex, currentIndex + extender] | |
} | |
if (extender > data.length) { | |
console.log('primarily out of bound!!'); | |
primaryOutBound = true; | |
} | |
if (currentIndex > data.length) { | |
console.log('something went wrong!!'); | |
finalOutBound = true; | |
} | |
} | |
} | |
const q2AnswerIndex = contiguousFinder(); | |
// console.log(q2AnswerIndex); | |
const contiguousFound = data.slice(q2AnswerIndex[0], q2AnswerIndex[1]); | |
const q2min = Math.min(...contiguousFound); | |
const q2max = Math.max(...contiguousFound); | |
// console.log([q2min, q2max]); | |
return { | |
q1: q1AnomalyNumber, | |
q2: q2min + q2max, | |
} | |
} | |
day9(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment