Skip to content

Instantly share code, notes, and snippets.

@almendar
Created December 21, 2021 11:07
Show Gist options
  • Save almendar/bb3ece694ac867549b7d12cb44d0f747 to your computer and use it in GitHub Desktop.
Save almendar/bb3ece694ac867549b7d12cb44d0f747 to your computer and use it in GitHub Desktop.
package main
import "fmt"
type Die interface {
roll() int
}
type DeterministicDie struct {
value int
}
type AlwaysRoll int
func (ar AlwaysRoll) String() string {
return fmt.Sprintf("AlwaysRoll(%d)", int(ar))
}
func (dd AlwaysRoll) roll() int {
return int(dd)
}
func (dd *DeterministicDie) roll() int {
dd.value++
return dd.value
}
type GameState struct {
p1Pos, p1Score, p2Pos, p2Score, rolls int
}
func (g GameState) String() string {
return fmt.Sprintf("P1{Score:%d Pos:%d} P2{Score:%d Pos:%d} Rolls:%d", g.p1Score, g.p1Pos, g.p2Score, g.p2Pos, g.rolls)
}
func (gs *GameState) nextState(die Die) {
rollResult := die.roll()
gs.rolls++
fullCircles := rollResult / 10
rollResult -= 10 * fullCircles
turn := (gs.rolls - 1) % 6
playerOneTurn := turn == 0 || turn == 1 || turn == 2
if playerOneTurn {
gs.p1Pos += rollResult
if gs.p1Pos >= 11 {
gs.p1Pos = gs.p1Pos % 10
}
if turn == 2 {
gs.p1Score += gs.p1Pos
}
} else {
gs.p2Pos += rollResult
if gs.p2Pos >= 11 {
gs.p2Pos = gs.p2Pos % 10
}
if turn == 5 {
gs.p2Score += gs.p2Pos
}
}
}
func task1() {
simulate := func(p1Start, p2Start int) int {
var die Die = &DeterministicDie{}
game := GameState{}
game.p1Pos = p1Start
game.p2Pos = p2Start
looserScore := -1
for {
game.nextState(die)
game.nextState(die)
game.nextState(die)
if game.p1Score >= 1000 {
looserScore = game.p2Score
break
}
game.nextState(die)
game.nextState(die)
game.nextState(die)
if game.p2Score >= 1000 {
looserScore = game.p1Score
break
}
}
return looserScore * game.rolls
}
// si
example := simulate(4, 8)
fmt.Printf("Day21 task1 example: %v\n", example)
input := simulate(7, 6)
fmt.Printf("Day21 task1 input: %v\n", input)
}
type Wins struct {
p1Wins, p2Wins int
}
var cache = make(map[GameState]Wins)
func SimulateStep(gs GameState, die Die) Wins {
gs.nextState(die)
turn := (gs.rolls - 1) % 6
if turn == 2 {
if gs.p1Score >= 21 {
return Wins{1, 0}
}
//p1 might have won
} else if turn == 5 {
if gs.p2Score >= 21 {
return Wins{0, 1}
}
}
ans, ok := cache[gs]
if ok {
return ans
}
w1 := SimulateStep(gs, AlwaysRoll(1))
w2 := SimulateStep(gs, AlwaysRoll(2))
w3 := SimulateStep(gs, AlwaysRoll(3))
totalWins := Wins{w1.p1Wins + w2.p1Wins + w3.p1Wins, w1.p2Wins + w2.p2Wins + w3.p2Wins}
cache[gs] = totalWins
return totalWins
}
func task2() {
simulate := func(p1Pos, p2Pos int) int {
gs := GameState{p1Pos: p1Pos, p2Pos: p2Pos}
win1 := SimulateStep(gs, AlwaysRoll(1))
win2 := SimulateStep(gs, AlwaysRoll(2))
win3 := SimulateStep(gs, AlwaysRoll(3))
totalWins := Wins{win1.p1Wins + win2.p1Wins + win3.p1Wins, win1.p2Wins + win2.p2Wins + win3.p2Wins}
// fmt.Printf("totalWins: %v\n", totalWins)
if totalWins.p1Wins > totalWins.p2Wins {
return totalWins.p1Wins
} else {
return totalWins.p2Wins
}
}
example := simulate(4, 8)
fmt.Printf("Day21 task 2 example: %d\n", example)
input := simulate(7, 6)
fmt.Printf("Day21 task 2 example: %d\n", input)
}
func main() {
task1()
task2()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment