Skip to content

Instantly share code, notes, and snippets.

@bluenex
Last active February 16, 2021 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bluenex/a6899814873fa9eb3b2368f1f2be48f7 to your computer and use it in GitHub Desktop.
Save bluenex/a6899814873fa9eb3b2368f1f2be48f7 to your computer and use it in GitHub Desktop.
A collection of snippets for Advent of Code 2020
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();
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();
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();
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();
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();
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();
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();
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();
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