2021 - Day 21
This commit is contained in:
parent
c1c4dcd7cf
commit
7b31fa1cbe
9
2021/21/go.mod
Normal file
9
2021/21/go.mod
Normal 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
2
2021/21/go.sum
Normal 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
173
2021/21/main.go
Normal 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]
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user