AoC/2021/day21.swift

101 lines
2.6 KiB
Swift

@main
struct Day21: Puzzle {
func run() {
part1()
part2()
}
let player1 = Player(position: 6)
let player2 = Player(position: 7)
func part1() {
var die = Die()
var player1 = player1
var player2 = player2
while true {
if player1.move(die.roll3()) >= 1000 {
print("Part 1: Player 1 won. ", die.rolls * player2.score)
break
}
if player2.move(die.roll3()) >= 1000 {
print("Part 1: Player 2 won. ", die.rolls * player1.score)
break
}
}
}
func part2() {
var universes: [Universe: Int] = [Universe(player1: player1, player2: player2): 1]
var player1Wins = 0
var player2Wins = 0
while !universes.isEmpty {
var newUniverses: [Universe: Int] = [:]
for (universe, universeCount) in universes {
for (offset, player1RollCount) in rollCounts.enumerated() {
var u = universe
if u.player1.move(offset + minRoll) >= quantumMax {
player1Wins += universeCount * player1RollCount
continue
}
for (offset, player2RollCount) in rollCounts.enumerated() {
var u2 = u
if u2.player2.move(offset + minRoll) >= quantumMax {
player2Wins += universeCount * player1RollCount * player2RollCount
continue
}
newUniverses[u2, default: 0] += universeCount * player1RollCount * player2RollCount
}
}
}
universes = newUniverses
}
print("Part 2: ", max(player1Wins, player2Wins))
}
let quantumMax = 21
let minRoll = 3
// 3 4 5 6 7 8 9
let rollCounts = [1, 3, 6, 7, 6, 3, 1]
struct Universe: Hashable {
var player1: Player
var player2: Player
}
struct Player: Hashable {
var position: Int
var score: Int = 0
mutating func move(_ roll: Int) -> Int {
position = 1 + (position + roll - 1) % 10
score += position
return score
}
}
struct Die {
var rolls = 0
var nextRoll = 1
mutating func roll() -> Int {
defer {
rolls += 1
nextRoll += 1
}
return nextRoll
}
mutating func roll3() -> Int {
roll() + roll() + roll()
}
}
}