.
This commit is contained in:
135
2021/21.js
Normal file
135
2021/21.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// turn: 0-1; 1 bit (0 = player 1; 1 = player 2)
|
||||||
|
// pos1: 1-10; 4 bits
|
||||||
|
// pos2: 1-10; 4 bits
|
||||||
|
// score1: 0-1009; 10 bits
|
||||||
|
// score2: 0-1009; 10 bits
|
||||||
|
const sizeS = 10
|
||||||
|
const sizeP = 4
|
||||||
|
const sizeT = 1
|
||||||
|
|
||||||
|
const maskS = (1 << sizeS) - 1
|
||||||
|
const maskP = (1 << sizeP) - 1
|
||||||
|
const maskT = (1 << sizeT) - 1
|
||||||
|
|
||||||
|
const offsetS2 = 0
|
||||||
|
const offsetS1 = offsetS2 + sizeS
|
||||||
|
const offsetP2 = offsetS1 + sizeS
|
||||||
|
const offsetP1 = offsetP2 + sizeP
|
||||||
|
const offsetT = offsetP1 + sizeP
|
||||||
|
|
||||||
|
function encodeState(turn, pos1, pos2, score1, score2) {
|
||||||
|
return (score2 << offsetS2) |
|
||||||
|
(score1 << offsetS1) |
|
||||||
|
(pos2 << offsetP2) |
|
||||||
|
(pos1 << offsetP1) |
|
||||||
|
(turn << offsetT)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScore(state, player) {
|
||||||
|
return state >> (player ? offsetS2 : offsetS1) & maskS
|
||||||
|
}
|
||||||
|
|
||||||
|
function advState(state, roll, win) {
|
||||||
|
let turn = state >> offsetT
|
||||||
|
|
||||||
|
let offsetPos = turn ? offsetP2 : offsetP1
|
||||||
|
let offsetScore = turn ? offsetS2 : offsetS1
|
||||||
|
|
||||||
|
let pos = (state >> offsetPos) & maskP
|
||||||
|
let score = (state >> offsetScore) & maskS
|
||||||
|
|
||||||
|
pos = (((pos + roll) - 1) % 10) + 1
|
||||||
|
score += pos
|
||||||
|
|
||||||
|
if (score >= win) {
|
||||||
|
return turn
|
||||||
|
}
|
||||||
|
|
||||||
|
state &= ~(maskP << offsetPos)
|
||||||
|
state |= pos << offsetPos
|
||||||
|
|
||||||
|
state &= ~(maskS << offsetScore)
|
||||||
|
state |= score << offsetScore
|
||||||
|
|
||||||
|
state ^= 1 << offsetT
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
const rollCombos = [1, 2, 3].cartProduct([1, 2, 3]).cartProduct([1, 2, 3]).map((e) => e.flat().sum())
|
||||||
|
|
||||||
|
function day21(input, part2) {
|
||||||
|
let lines = input.split("\n")
|
||||||
|
|
||||||
|
let pos1 = +lines[0].split(" ").last
|
||||||
|
let pos2 = +lines[1].split(" ").last
|
||||||
|
|
||||||
|
let state = encodeState(0, pos1, pos2, 0, 0)
|
||||||
|
|
||||||
|
if (!part2) {
|
||||||
|
const win = 1000
|
||||||
|
|
||||||
|
let die = 0
|
||||||
|
let rolls = 0
|
||||||
|
|
||||||
|
while (getScore(state, 0) < win && getScore(state, 1) < win) {
|
||||||
|
let roll = ++die
|
||||||
|
die %= 100
|
||||||
|
roll += ++die
|
||||||
|
die %= 100
|
||||||
|
roll += ++die
|
||||||
|
die %= 100
|
||||||
|
|
||||||
|
rolls += 3
|
||||||
|
|
||||||
|
newState = advState(state, roll, win)
|
||||||
|
|
||||||
|
if (newState == 0 || newState == 1) {
|
||||||
|
return getScore(state, 1 - newState) * rolls
|
||||||
|
}
|
||||||
|
|
||||||
|
state = newState
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let universes = {}
|
||||||
|
universes[state] = 1
|
||||||
|
|
||||||
|
let wins = [0, 0]
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
let universesLeft = false
|
||||||
|
|
||||||
|
for (let state in universes) {
|
||||||
|
if (!universes[state]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
universesLeft = true
|
||||||
|
|
||||||
|
state = +state
|
||||||
|
|
||||||
|
for (let roll of rollCombos) {
|
||||||
|
let newState = advState(state, roll, 21)
|
||||||
|
|
||||||
|
if (newState == 0 || newState == 1) {
|
||||||
|
wins[newState] += universes[state]
|
||||||
|
} else {
|
||||||
|
universes[newState] = (universes[newState] || 0) + universes[state]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete universes[state]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!universesLeft) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wins.max()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window == "undefined") {
|
||||||
|
module.exports = day21
|
||||||
|
}
|
||||||
2
out.js
2
out.js
@@ -1244,7 +1244,7 @@ if (typeof window == "undefined" && process.argv[2] == "test") {
|
|||||||
|
|
||||||
const year = "2021"
|
const year = "2021"
|
||||||
|
|
||||||
for (let i = +process.argv[3] || 1; i <= 20; i++) {
|
for (let i = +process.argv[3] || 1; i <= 21; i++) {
|
||||||
const func = require(`./${year}/${i}.js`)
|
const func = require(`./${year}/${i}.js`)
|
||||||
const input = fs.readFileSync(`./${year}/inputs/${i}`, "utf8")
|
const input = fs.readFileSync(`./${year}/inputs/${i}`, "utf8")
|
||||||
const answers = fs.readFileSync(`./${year}/answers/${i}`, "utf8").split("\n-----\n")
|
const answers = fs.readFileSync(`./${year}/answers/${i}`, "utf8").split("\n-----\n")
|
||||||
|
|||||||
2
test.js
2
test.js
@@ -3,7 +3,7 @@ if (typeof window == "undefined" && process.argv[2] == "test") {
|
|||||||
|
|
||||||
const year = "2021"
|
const year = "2021"
|
||||||
|
|
||||||
for (let i = +process.argv[3] || 1; i <= 20; i++) {
|
for (let i = +process.argv[3] || 1; i <= 21; i++) {
|
||||||
const func = require(`./${year}/${i}.js`)
|
const func = require(`./${year}/${i}.js`)
|
||||||
const input = fs.readFileSync(`./${year}/inputs/${i}`, "utf8")
|
const input = fs.readFileSync(`./${year}/inputs/${i}`, "utf8")
|
||||||
const answers = fs.readFileSync(`./${year}/answers/${i}`, "utf8").split("\n-----\n")
|
const answers = fs.readFileSync(`./${year}/answers/${i}`, "utf8").split("\n-----\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user