AdventOfCode2020/22/main.go

156 lines
3.3 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
type deck struct {
cards []int
}
type cacheKey struct {
one int
two int
}
func countWinningDeck(deck []int) int {
sum := 0
for i := range deck {
sum = sum + ((len(deck) - i) * deck[i])
}
return sum
}
// return values is who won/their score: true for player one, false for player two
func playCombat(one, two []int) (bool, int) {
round := 0
for len(one) > 0 && len(two) > 0 {
round = round + 1
if one[0] > two[0] {
one = append(one[1:], one[0], two[0])
two = two[1:]
} else if one[0] < two[0] {
two = append(two[1:], two[0], one[0])
one = one[1:]
}
}
if len(one) == 0 {
return false, countWinningDeck(two)
}
return true, countWinningDeck(one)
}
func playRecursiveCombat(one, two []int) (bool, int) {
loopCache := make(map[cacheKey]bool, 0)
round := 0
for len(one) > 0 && len(two) > 0 {
// check for loops
if loopCache[cacheKey{one: countWinningDeck(one), two: countWinningDeck(two)}] {
return true, countWinningDeck(one)
}
loopCache[cacheKey{one: countWinningDeck(one), two: countWinningDeck(two)}] = true
// otherwise, play a round
round = round + 1
if len(one[1:]) >= one[0] && len(two[1:]) >= two[0] {
// fuckin' go slice internals
subDeckOne := make([]int, len(one))
subDeckTwo := make([]int, len(two))
copy(subDeckOne, one)
copy(subDeckTwo, two)
winner, _ := playRecursiveCombat(subDeckOne[1:one[0]+1], subDeckTwo[1:two[0]+1])
if winner { // p1 wins
one = append(one[1:], one[0], two[0])
two = two[1:]
} else { // p2 wins
two = append(two[1:], two[0], one[0])
one = one[1:]
}
} else if one[0] > two[0] {
one = append(one[1:], one[0], two[0])
two = two[1:]
} else if one[0] < two[0] {
two = append(two[1:], two[0], one[0])
one = one[1:]
}
}
if len(one) == 0 {
return false, countWinningDeck(two)
}
return true, countWinningDeck(one)
}
func partOne() {
f, _ := os.Open("input")
reader := bufio.NewReader(f)
scanner := bufio.NewScanner(reader)
// deal the decks
playerone := deck{}
for scanner.Scan() {
line := scanner.Text()
if line == "" {
break
}
i, err := strconv.Atoi(line)
if err == nil {
playerone.cards = append(playerone.cards, i)
}
}
playertwo := deck{}
for scanner.Scan() {
line := scanner.Text()
i, err := strconv.Atoi(line)
if err == nil {
playertwo.cards = append(playertwo.cards, i)
}
}
// play a game and determine a winner
_, score := playCombat(playerone.cards, playertwo.cards)
fmt.Println(score)
}
func partTwo() {
f, _ := os.Open("input")
reader := bufio.NewReader(f)
scanner := bufio.NewScanner(reader)
// deal the decks
playerone := deck{}
for scanner.Scan() {
line := scanner.Text()
if line == "" {
break
}
i, err := strconv.Atoi(line)
if err == nil {
playerone.cards = append(playerone.cards, i)
}
}
playertwo := deck{}
for scanner.Scan() {
line := scanner.Text()
i, err := strconv.Atoi(line)
if err == nil {
playertwo.cards = append(playertwo.cards, i)
}
}
_, score := playRecursiveCombat(playerone.cards, playertwo.cards)
fmt.Println(score)
}