Last active
December 17, 2023 07:16
-
-
Save ZeikJT/67b8ef3bc670cff88a6b48516e0d488b to your computer and use it in GitHub Desktop.
Advent of Code 2023
This file contains hidden or 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 adventOfCode2023_Day01_Part1(str) { | |
return str.trim().split('\n').map((line) => { | |
const firstNum = /\d/.exec(line)[0] | |
const lastNum = /(\d)[a-zA-Z]*?$/.exec(line)[1] | |
return Number(firstNum + lastNum) | |
}).reduce((total, num) => total + num, 0) | |
} | |
function adventOfCode2023_Day01_Part2(str) { | |
const CONVERSION = new Map([ | |
['zero', '0'], // Not needed by prompt, but feels wrong to exclude. | |
['one', '1'], | |
['two', '2'], | |
['three', '3'], | |
['four', '4'], | |
['five', '5'], | |
['six', '6'], | |
['seven', '7'], | |
['eight', '8'], | |
['nine', '9'], | |
]) | |
const CONVERSION_NUM_NAMES = Array.from(CONVERSION.keys()).join('|') | |
const NUM_REGEXP = new RegExp(`(?=(${CONVERSION_NUM_NAMES}|\\d))`, 'g') | |
return str.trim().split('\n').map((line) => { | |
const matches = Array.from(line.matchAll(NUM_REGEXP), (matchData) => matchData[1]) | |
let firstNum = matches[0] | |
let lastNum = matches[matches.length - 1] | |
if (CONVERSION.has(firstNum)) { | |
firstNum = CONVERSION.get(firstNum) | |
} | |
if (CONVERSION.has(lastNum)) { | |
lastNum = CONVERSION.get(lastNum) | |
} | |
return Number(firstNum + lastNum) | |
}).reduce((total, num) => total + num, 0) | |
} |
This file contains hidden or 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
const NUM_COLOR_REGEX = /(\d+)\s(red|blue|green)/g | |
function adventOfCode2023_Day02_Part1(str) { | |
const COUNTS = { | |
red: 12, | |
green: 13, | |
blue: 14, | |
} | |
return str.trim().split('\n').reduce((total, line) => { | |
const gameNum = Number(line.substring(5, line.indexOf(':'))) | |
let isValid = true | |
for (const set of line.split(';')) { | |
for (const [, numStr, color] of set.matchAll(NUM_COLOR_REGEX)) { | |
if (COUNTS[color] < Number(numStr)) { | |
isValid = false | |
break | |
} | |
} | |
if (!isValid) { | |
break | |
} | |
} | |
return total + (isValid ? gameNum : 0) | |
}, 0) | |
} | |
function adventOfCode2023_Day02_Part2(str) { | |
return str.trim().split('\n').reduce((total, line) => { | |
const gameNum = Number(line.substring(5, line.indexOf(':'))) | |
const minCounts = { | |
red: 0, | |
green: 0, | |
blue: 0, | |
} | |
for (const set of line.split(';')) { | |
for (const [, numStr, color] of set.matchAll(NUM_COLOR_REGEX)) { | |
const num = Number(numStr) | |
if (minCounts[color] < num) { | |
minCounts[color] = num | |
} | |
} | |
} | |
return total + (minCounts.red * minCounts.green * minCounts.blue) | |
}, 0) | |
} |
This file contains hidden or 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
const NUMBERS = new Set(new Array(10).fill(0).map((num, index) => String(index))) | |
// Include undefined to handle rows before and after the input. Could pad grid but eh. | |
const NON_SYMBOLS = new Set([...NUMBERS, '.', undefined]) | |
function adventOfCode2023_Day03_Part1(str) { | |
const grid = str.trim().split('\n') | |
function checkAdjacentSymbols(y, startX, endX) { | |
startX-- | |
endX++ | |
if (!NON_SYMBOLS.has(grid[y][startX]) || !NON_SYMBOLS.has(grid[y][endX])) { | |
return true | |
} | |
for (let i = startX; i <= endX; i++) { | |
if (!NON_SYMBOLS.has(grid[y - 1]?.[i]) || !NON_SYMBOLS.has(grid[y + 1]?.[i])) { | |
return true | |
} | |
} | |
return false | |
} | |
return grid.reduce((total, line, y) => { | |
let start = -1 | |
let end = -1 | |
// Go one extra character to terminate numbers at the end | |
for (let x = 0; x <= line.length; x++) { | |
if (NUMBERS.has(line[x])) { | |
if (start === -1) { | |
start = x | |
end = x | |
} else { | |
end = x | |
} | |
} else if (start !== -1) { | |
// Detect symbols left and right first, most local data, easiest to check | |
if (checkAdjacentSymbols(y, start, end)) { | |
total += Number(line.substring(start, end + 1)) | |
} | |
start = -1 | |
end = -1 | |
} | |
} | |
return total | |
}, 0) | |
} | |
function adventOfCode2023_Day03_Part2(str) { | |
const grid = str.trim().split('\n') | |
function getFullNum(y, x) { | |
let startX = x | |
let endX = x | |
if (!NUMBERS.has(grid[y][x])) { | |
throw new Error(`Number not found at y ${y} and x ${x}: ${grid[y][x]}`) | |
} | |
while (NUMBERS.has(grid[y][startX - 1])) { | |
startX-- | |
} | |
while (NUMBERS.has(grid[y][endX + 1])) { | |
endX++ | |
} | |
return Number(grid[y].substring(startX, endX + 1)) | |
} | |
function getGearRatio(y, x) { | |
if (NON_SYMBOLS.has(grid[y][x])) { | |
throw new Error(`Non symbol found at y ${y} and x ${x}: ${grid[y][x]}`) | |
} | |
const same = [] | |
if (NUMBERS.has(grid[y][x - 1])) { | |
same.push(x - 1) | |
} | |
if (NUMBERS.has(grid[y][x + 1])) { | |
same.push(x + 1) | |
} | |
const above = new Set | |
const below = new Set | |
for (let i = x - 1; i < x + 2; i++) { | |
if (NUMBERS.has(grid[y - 1]?.[i])) { | |
above.delete(i - 1) | |
above.add(i) | |
} | |
if (NUMBERS.has(grid[y + 1]?.[i])) { | |
below.delete(i - 1) | |
below.add(i) | |
} | |
} | |
const foundCount = same.length + above.size + below.size | |
if (foundCount !== 2) { | |
return null | |
} | |
const found = [] | |
for (const sameX of same) { | |
found.push(getFullNum(y, sameX)) | |
} | |
for (const aboveX of above) { | |
found.push(getFullNum(y - 1, aboveX)) | |
} | |
for (const belowX of below) { | |
found.push(getFullNum(y + 1, belowX)) | |
} | |
return found[0] * found[1] | |
} | |
return grid.reduce((total, line, y) => { | |
for (let x = 0; x < line.length; x++) { | |
if (!NON_SYMBOLS.has(line[x])) { | |
const gearRatio = getGearRatio(y, x) | |
if (gearRatio !== null) { | |
total += gearRatio | |
} | |
} | |
} | |
return total | |
}, 0) | |
} |
This file contains hidden or 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 adventOfCode2023_Day04_Part1(str) { | |
return str.trim().split('\n').reduce((total, line) => { | |
const [winningNums, haveNums] = line.substring(line.indexOf(':') + 1).split(' | ').map((str) => str.trim().split(' ').filter((str) => str)) | |
const winningNumSet = new Set(winningNums) | |
let winTotal = 0 | |
for (const num of haveNums) { | |
if (winningNumSet.has(num)) { | |
if (winTotal === 0) { | |
winTotal = 1 | |
} else { | |
winTotal *= 2 | |
} | |
} | |
} | |
return total + winTotal | |
}, 0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment