Created
December 21, 2021 11:07
-
-
Save almendar/bb3ece694ac867549b7d12cb44d0f747 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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