Files
aoc2020/twentytwo/day_twentytwo.go
James Griffin 335ac758e2 Day 21: Part 2
Signed-off-by: James Griffin <james@unsupervised.ca>
2020-12-22 11:58:18 -04:00

180 lines
3.3 KiB
Go

package twentytwo
import (
"bufio"
"fmt"
"os"
"strconv"
)
type player struct {
deck []int
}
func (p *player) score() int {
score := 0
for i := 0; i < len(p.deck); i++ {
score += p.deck[i] * (len(p.deck) - i)
}
return score
}
type combat struct {
one, two player
}
func (c *combat) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
one := false
two := false
scanner := bufio.NewScanner(file)
for scanner.Scan() {
if scanner.Text() == "Player 1:" {
one = true
continue
}
if scanner.Text() == "" {
one = false
two = false
continue
}
if scanner.Text() == "Player 2:" {
two = true
continue
}
card, err := strconv.Atoi(scanner.Text())
if err != nil {
return err
}
if one {
c.one.deck = append(c.one.deck, card)
} else if two {
c.two.deck = append(c.two.deck, card)
}
}
return nil
}
func (c *combat) play() (round int) {
for {
round++
// play cards
played := []int{c.one.deck[0], c.two.deck[0]}
c.one.deck = c.one.deck[1:]
c.two.deck = c.two.deck[1:]
if played[0] > played[1] {
c.one.deck = append(c.one.deck, played[0], played[1])
} else if played[0] < played[1] {
c.two.deck = append(c.two.deck, played[1], played[0])
} else {
panic("TIES ARE LIKELY IN PART 2")
}
if len(c.one.deck) == 0 || len(c.two.deck) == 0 {
break
}
}
return round
}
func (c *combat) recursivePlay() (winner int) {
previousRounds := map[string]bool{}
for {
currentRound := ""
for _, c := range c.one.deck {
currentRound += fmt.Sprintf("%d,", c)
}
currentRound += "|"
for _, c := range c.two.deck {
currentRound += fmt.Sprintf("%d,", c)
}
if previousRounds[currentRound] {
return 1
} else {
previousRounds[currentRound] = true
}
// Draw cards as normal
played := []int{c.one.deck[0], c.two.deck[0]}
c.one.deck = c.one.deck[1:]
c.two.deck = c.two.deck[1:]
w := 0
if len(c.one.deck) >= played[0] && len(c.two.deck) >= played[1] {
rPOne := player{}
for i, c := range c.one.deck {
if i >= played[0] {
break
}
rPOne.deck = append(rPOne.deck, c)
}
rPTwo := player{}
for i, c := range c.two.deck {
if i >= played[1] {
break
}
rPTwo.deck = append(rPTwo.deck, c)
}
rC := combat{
one: rPOne,
two: rPTwo,
}
w = rC.recursivePlay()
} else if played[0] > played[1] {
w = 1
} else if played[1] > played[0] {
w = 2
}
if w == 1 {
c.one.deck = append(c.one.deck, played[0], played[1])
} else if w == 2 {
c.two.deck = append(c.two.deck, played[1], played[0])
}
if len(c.one.deck) == 0 {
return 2
} else if len(c.two.deck) == 0 {
return 1
}
}
}
// PartOne What is the winning player's score
func PartOne() string {
c := combat{}
if err := c.load("twentytwo/input.txt"); err != nil {
return err.Error()
}
rounds := c.play()
return fmt.Sprintf("The game lasted %d rounds with a score of %d - %d", rounds, c.one.score(), c.two.score())
}
// PartTwo What is the winning player's score after recursive combat
func PartTwo() string {
c := combat{}
if err := c.load("twentytwo/input.txt"); err != nil {
return err.Error()
}
winner := c.recursivePlay()
return fmt.Sprintf("The winner was player %d with a score of %d - %d", winner, c.one.score(), c.two.score())
}