144 lines
2.7 KiB
Go
144 lines
2.7 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
var playerCount, marbleCount int
|
||
|
var game *Game
|
||
|
|
||
|
func main() {
|
||
|
if len(os.Args) < 3 {
|
||
|
fmt.Println("Usage: day09 <# players> <# marbles>")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
playerCount, marbleCount = Atoi(os.Args[1]), Atoi(os.Args[2])
|
||
|
part1()
|
||
|
}
|
||
|
|
||
|
func part1() {
|
||
|
g := NewGame(playerCount, marbleCount)
|
||
|
for i := 1; i <= marbleCount; i++ {
|
||
|
if i%23 == 0 {
|
||
|
g.score(i)
|
||
|
} else {
|
||
|
g.insertMarble(&Marble{value: i})
|
||
|
}
|
||
|
g.nextPlayer()
|
||
|
}
|
||
|
fmt.Println("* Winner *")
|
||
|
g.printWinner()
|
||
|
}
|
||
|
|
||
|
type Game struct {
|
||
|
playerCount, marbleCount int
|
||
|
currentPlayer int
|
||
|
scores map[int]int
|
||
|
|
||
|
currentMarble *Marble
|
||
|
}
|
||
|
|
||
|
func NewGame(players, marbles int) *Game {
|
||
|
startMarble := &Marble{
|
||
|
value: 0,
|
||
|
}
|
||
|
startMarble.clockwise = startMarble
|
||
|
startMarble.widdershins = startMarble
|
||
|
return &Game{
|
||
|
playerCount: players,
|
||
|
marbleCount: marbles,
|
||
|
currentPlayer: 1,
|
||
|
scores: make(map[int]int),
|
||
|
currentMarble: startMarble,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (g *Game) insertMarble(m *Marble) {
|
||
|
m.clockwise = g.currentMarble.clockwise.clockwise
|
||
|
m.widdershins = g.currentMarble.clockwise
|
||
|
g.currentMarble.clockwise.clockwise.widdershins = m
|
||
|
g.currentMarble.clockwise.clockwise = m
|
||
|
g.currentMarble = m
|
||
|
}
|
||
|
|
||
|
func (g *Game) score(val int) {
|
||
|
g.scores[g.currentPlayer] += val
|
||
|
for i := 0; i < 6; i++ {
|
||
|
g.currentMarble = g.currentMarble.widdershins
|
||
|
}
|
||
|
// Remove g.currentMarble.widdershins
|
||
|
// adding it's value to the current player's score
|
||
|
rem := g.currentMarble.widdershins
|
||
|
g.currentMarble.widdershins = rem.widdershins
|
||
|
g.currentMarble.widdershins.clockwise = g.currentMarble
|
||
|
g.scores[g.currentPlayer] += rem.value
|
||
|
}
|
||
|
|
||
|
func (g *Game) nextPlayer() {
|
||
|
if g.currentPlayer == g.playerCount {
|
||
|
g.currentPlayer = 1
|
||
|
} else {
|
||
|
g.currentPlayer++
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (g *Game) printState() {
|
||
|
fmt.Printf("[%d] ", g.currentPlayer)
|
||
|
p := *g.currentMarble
|
||
|
for p.value != 0 {
|
||
|
// Find the '0' marble
|
||
|
p = *p.clockwise
|
||
|
}
|
||
|
if p.value == g.currentMarble.value {
|
||
|
fmt.Printf("(%d)", p.value)
|
||
|
} else {
|
||
|
fmt.Printf(" %d ", p.value)
|
||
|
}
|
||
|
p = *p.clockwise
|
||
|
for p.value != 0 {
|
||
|
if p.value == g.currentMarble.value {
|
||
|
fmt.Printf("(%d)", p.value)
|
||
|
} else {
|
||
|
fmt.Printf(" %d ", p.value)
|
||
|
}
|
||
|
p = *p.clockwise
|
||
|
}
|
||
|
fmt.Println("")
|
||
|
}
|
||
|
|
||
|
func (g *Game) printScores() {
|
||
|
for i := 1; i <= g.playerCount; i++ {
|
||
|
fmt.Println(i, ":", g.scores[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (g *Game) printWinner() {
|
||
|
var top int
|
||
|
var winner int
|
||
|
for k, v := range g.scores {
|
||
|
if v > top {
|
||
|
top = v
|
||
|
winner = k
|
||
|
}
|
||
|
}
|
||
|
fmt.Println(winner, ":", top)
|
||
|
}
|
||
|
|
||
|
type Marble struct {
|
||
|
value int
|
||
|
clockwise *Marble
|
||
|
widdershins *Marble
|
||
|
}
|
||
|
|
||
|
func Atoi(i string) int {
|
||
|
var ret int
|
||
|
var err error
|
||
|
if ret, err = strconv.Atoi(i); err != nil {
|
||
|
log.Fatal("Invalid Atoi")
|
||
|
}
|
||
|
return ret
|
||
|
}
|