2021 - Day 21

This commit is contained in:
Dreaded_X 2021-12-22 00:32:09 +01:00
parent c1c4dcd7cf
commit 7b31fa1cbe
3 changed files with 184 additions and 0 deletions

9
2021/21/go.mod Normal file
View File

@ -0,0 +1,9 @@
module AoC/2021/21
require AoC/2021/common v0.0.0
require github.com/joho/godotenv v1.4.0 // indirect
replace AoC/2021/common v0.0.0 => ../common
go 1.17

2
2021/21/go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=

173
2021/21/main.go Normal file
View File

@ -0,0 +1,173 @@
package main
import (
aoc "AoC/2021/common"
"bufio"
"fmt"
"regexp"
"strconv"
)
type DeterministicDie struct {
counter int
}
func (d DeterministicDie) Roll(times int) (DeterministicDie, int) {
s := 0
for i := 0; i < times; i++ {
s += d.counter + 1
d.counter++
d.counter %= 100
}
return d, s
}
type Player struct {
position int
score int
rolls int
}
func NewPlayer(position int) Player {
var p Player
p.position = position - 1
return p
}
func (p Player) Move(spaces int) Player {
p.position += spaces
p.position %= 10
p.score += p.Position()
p.rolls += 3
return p
}
func (p Player) Position() int {
// We use a postion from 0 to 9 internally as it is easier to work with
return p.position + 1
}
func (p Player) Score() int {
return p.score
}
func (p Player) Rolls() int {
return p.rolls
}
type GameState struct {
pos [2]int
score [2]int
turn int
}
func main() {
challenge := aoc.New(2021, 21)
challenge.Test(`Player 1 starting position: 4
Player 2 starting position: 8`, []int{739785, 444356092776315})
challenge.Solution(1, func (input *bufio.Scanner) int {
r := regexp.MustCompile("[0-9]+")
var players [2]Player
for i := range players {
input.Scan()
position, _ := strconv.Atoi(r.FindAllString(input.Text(), 2)[1])
players[i] = NewPlayer(position)
}
var die DeterministicDie
game:
for i := 0; true; i++ {
for j, p := range players {
var rolled int
die, rolled = die.Roll(3)
players[j] = p.Move(rolled)
if players[j].Score() >= 1000 {
break game
}
}
}
score := 0
rolls := 0
for _, p := range players {
rolls += p.Rolls()
if p.Score() < 1000 {
score = p.Score()
}
}
fmt.Println(score, rolls)
return score*rolls
})
challenge.Solution(2, func (input *bufio.Scanner) int {
r := regexp.MustCompile("[0-9]+")
var players [2]int
for i := range players {
input.Scan()
position, _ := strconv.Atoi(r.FindAllString(input.Text(), 2)[1])
players[i] = position-1
}
// List of all current states
states := make(map[GameState]int)
states[GameState{players, [2]int{}, 0}] = 1
// Pre compute all possible outcomes and their frequency
outcomes := make(map[int]int)
maxNum := 3
for r := 1; r <= maxNum; r++ {
for s := 1; s <= maxNum; s++ {
for t := 1; t <= maxNum; t++ {
outcomes[r + s + t]++
}
}
}
var victories [2]int
// Keep going as long as there are unfinished games
for i := 0; len(states) > 0; i++ {
statesNext := make(map[GameState]int)
// Update all states
for state, occurs := range states {
// Create all possible outcomes
for outcome, num := range outcomes {
stateNext := state
stateNext.pos[state.turn] += outcome
stateNext.pos[state.turn] %= 10
stateNext.score[state.turn] += stateNext.pos[state.turn] + 1
if stateNext.score[state.turn] >= 21 {
// Player has won
victories[state.turn] += occurs*num
} else {
stateNext.turn = 1 - state.turn
statesNext[stateNext] += occurs*num
}
}
}
states = statesNext
}
fmt.Println(victories)
if victories[1] > victories[0] {
return victories[1]
}
return victories[0]
})
}