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) }