mirror of
https://github.com/seigler/aoc2021
synced 2025-07-26 08:56:10 +00:00
85 lines
2.4 KiB
JavaScript
85 lines
2.4 KiB
JavaScript
import run from "aocrunner"
|
|
|
|
const parseInput = (rawInput) => rawInput.match(/(?<=: )\d+/g).map(x=>+x)
|
|
|
|
const part1 = (rawInput) => {
|
|
const [aStart, bStart] = parseInput(rawInput)
|
|
let a = aStart, b = bStart, aScore = 0, bScore = 0, isATurn = true
|
|
let die = 0, numRolls = 0
|
|
function roll() {
|
|
numRolls++
|
|
return (die = die % 100 + 1)
|
|
}
|
|
while (aScore < 1000 && bScore < 1000) {
|
|
const rolls = [roll(),roll(),roll()]
|
|
if (isATurn) {
|
|
a += rolls[0] + rolls[1] + rolls[2]
|
|
a = (a - 1) % 10 + 1
|
|
aScore += a
|
|
} else {
|
|
b += rolls[0] + rolls[1] + rolls[2]
|
|
b = (b - 1) % 10 + 1
|
|
bScore += b
|
|
}
|
|
isATurn = !isATurn
|
|
}
|
|
return Math.min(aScore, bScore) * numRolls
|
|
}
|
|
|
|
const frequencies = []
|
|
for (let i = 1; i <= 3; i++)
|
|
for (let j = 1; j <= 3; j++)
|
|
for (let k = 1; k <= 3; k++) {
|
|
frequencies[i + j + k] = (frequencies[i + j + k] ?? 0) + 1
|
|
}
|
|
|
|
const part2 = (rawInput) => {
|
|
const [aStart, bStart] = parseInput(rawInput)
|
|
const memo = []
|
|
const winThreshold = 21
|
|
function countWins(aScore, bScore, aPos, bPos, isATurn) {
|
|
let existing = memo[[aScore, bScore, aPos, bPos, isATurn]]
|
|
if (existing !== undefined) return existing
|
|
if (aScore >= winThreshold) {
|
|
memo[[aScore, bScore, aPos, bPos, isATurn]] = [1, 0]
|
|
return [1, 0]
|
|
}
|
|
if (bScore >= winThreshold) {
|
|
memo[[aScore, bScore, aPos, bPos, isATurn]] = [0, 1]
|
|
return [0, 1]
|
|
}
|
|
let totalWins = [0, 0]
|
|
for (let diceSum = 3; diceSum <= 9; diceSum++) {
|
|
let thisWin
|
|
if (isATurn) {
|
|
const nextAPos = (aPos - 1 + diceSum) % 10 + 1
|
|
thisWin = countWins(aScore + nextAPos, bScore, nextAPos, bPos, !isATurn)
|
|
} else {
|
|
const nextBPos = (bPos - 1 + diceSum) % 10 + 1
|
|
thisWin = countWins(aScore, bScore + nextBPos, aPos, nextBPos, !isATurn)
|
|
}
|
|
totalWins = [totalWins[0] + frequencies[diceSum] * thisWin[0], totalWins[1] + frequencies[diceSum] * thisWin[1]]
|
|
}
|
|
memo[[aScore, bScore, aPos, bPos, isATurn]] = totalWins
|
|
return totalWins
|
|
}
|
|
return Math.max(...countWins(0, 0, aStart, bStart, true))
|
|
}
|
|
|
|
run({
|
|
part1: {
|
|
tests: [
|
|
{ input: `Player 1 starting position: 4
|
|
Player 2 starting position: 8`, expected: 739785 },
|
|
],
|
|
solution: part1,
|
|
},
|
|
part2: {
|
|
tests: [
|
|
{ input: `Player 1 starting position: 4
|
|
Player 2 starting position: 8`, expected: 444356092776315 },
|
|
],
|
|
solution: part2,
|
|
},
|
|
trimTestInputs: true,
|
|
})
|