2023 - Day 2
Intro
The puzzle prompt on adventofcode.com
# run solution with test data
zx content/advent-of-code/2023/2/_index.md
# run solution with input file data
zx content/advent-of-code/2023/2/_index.md content/advent-of-code/2023/2/input.txt
Code
const assert = require('assert')
debug(argv)
const [inputFile] = argv._
const sampleData = {
part1: `Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green`
}
const bagContents = {
red: 12,
green: 13,
blue: 14
}
const sampleSolutions = {
part1: 8,
part2: 2286
}
let inputContent
if (inputFile) {
debug(`input file specified, loading data from: ${inputFile}`)
inputContent = await fs.readFile(inputFile, 'utf-8')
} else {
debug(`no input file specified, using part 1 sample data`)
inputContent = sampleData.part1
}
const games = inputContent
.split('\n')
.map(value => value.toLowerCase())
.map(value => {
const gameNumber = parseInt(value.match(/^game [0-9]*/)[0].split(' ')[1], 10)
const gameText = value.replace(/^game [0-9]*\: /, '')
const grabs = gameText.split('; ')
// debug(grabs)
const grabReveals = grabs
.map(sr => sr.split(', '))
.map(rev => {
// debug(rev)
const samples = rev
.map(s => {
const [quantity, color] = s.split(' ')
return {
quantity: parseInt(quantity, 10),
color
}
})
// debug(samples)
return samples
// return {color, quantity}
})
return {
gameNumber,
gameText,
grabs,
grabReveals
}
})
// if (!inputFile) debug(games[0].grabReveals)
games.forEach(game => {
let gameIsPossible = true
const maxByColor = {
red: -1,
green: -1,
blue: -1,
}
game.grabReveals.forEach(gr => {
gr.forEach(reveal => {
if (reveal.quantity > bagContents[reveal.color]) gameIsPossible = false
if (reveal.quantity > maxByColor[reveal.color]) maxByColor[reveal.color] = reveal.quantity
})
})
game.isPossible = gameIsPossible
game.maxByColor = maxByColor
})
if (!inputFile) debug(games[0])
const possibleGame = games.filter(game => game.isPossible)
const possibleGameIdsSummed = possibleGame.reduce((memo, game) => {
memo += game.gameNumber
return memo
}, 0)
console.log(`Part 1: Sum of valid game ids: ${possibleGameIdsSummed}`)
if (!inputFile) assert.equal(possibleGameIdsSummed, sampleSolutions.part1, 'part 1 solution should match expected')
const gamePowers = games.map(g => {
const gamePower = Object.values(g.maxByColor).reduce((memo, val) => {
if (memo === 0) return val
memo *= val
return memo
}, 0)
return gamePower
})
const powerSums = gamePowers.reduce((memo, power) => {
memo += power
return memo
}, 0)
if (!inputFile) assert.equal(powerSums, sampleSolutions.part2, 'part 2 solution should match expected')
console.log(`Part 2: Sum of game powers: ${powerSums}`)
function debug (msg) {
if (process.env.DEBUG) console.log(msg)
}