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