156 lines
3.3 KiB
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)
|
|
}
|