diff --git a/2020/day22/input b/2020/day22/input new file mode 100644 index 0000000..8c6c1e4 --- /dev/null +++ b/2020/day22/input @@ -0,0 +1,53 @@ +Player 1: +4 +25 +3 +11 +2 +29 +41 +23 +30 +21 +50 +8 +1 +24 +27 +10 +42 +43 +38 +15 +18 +13 +32 +37 +34 + +Player 2: +12 +6 +36 +35 +40 +47 +31 +9 +46 +49 +19 +16 +5 +26 +39 +48 +7 +44 +45 +20 +17 +14 +33 +28 +22 diff --git a/2020/day22/main.go b/2020/day22/main.go new file mode 100644 index 0000000..0a64715 --- /dev/null +++ b/2020/day22/main.go @@ -0,0 +1,193 @@ +package main + +import ( + "fmt" + "strings" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +var debugLevel int + +const ( + debugLo = 1 + debugMd = 2 + debugHi = 3 + debugNo = -1 +) + +func main() { + fmt.Println("# Day 22") + inp := h.StdinToStringSlice() + + debugLevel = h.Atoi(h.OptArgNumber(2, "-1")) + + solve(inp, h.Atoi(h.OptArgNumber(1, "2"))) +} + +func print(s string, lvl int) { + if debugLevel != -1 && lvl >= debugLevel { + fmt.Print(s) + } +} + +func solve(inp []string, part int) { + var player int + decks := make(map[int]*Deck) + for k := range inp { + if strings.TrimSpace(inp[k]) == "" { + continue + } else if strings.HasPrefix(inp[k], "Player ") { + player = h.Atoi(inp[k][7 : len(inp[k])-1]) + decks[player] = &Deck{Player: player} + continue + } else { + decks[player].Add(h.Atoi(inp[k])) + } + } + + if part == 1 { + solveNormal(decks[1], decks[2]) + } else { + solveRecursive(decks[1], decks[2]) + } +} + +func solveNormal(deck1, deck2 *Deck) { + round := 1 + winner := Winner(deck1, deck2) + for winner == -1 { + + print(fmt.Sprintf("-- Round %d --\n%s\n%s\n", round, deck1, deck2), debugLo) + + cmp1 := deck1.Draw() + cmp2 := deck2.Draw() + print(fmt.Sprintf("Player 1 plays: %d\nPlayer 2 plays: %d\n", cmp1, cmp2), debugLo) + if cmp1 > cmp2 { + print(fmt.Sprintln("Player 1 wins the round!"), debugLo) + deck1.Add(cmp1, cmp2) + } else if cmp2 > cmp1 { + print(fmt.Sprintln("Player 2 wins the round!"), debugLo) + deck2.Add(cmp2, cmp1) + } + round++ + winner = Winner(deck1, deck2) + } + fmt.Printf("== Post-game results ==\n%s\n%s\n", deck1, deck2) + var score int + if winner == 1 { + score = deck1.Score() + } else { + score = deck2.Score() + } + + fmt.Println("## Part 1:\nAnswer: ", score) +} + +func solveRecursive(deck1, deck2 *Deck) { + winner := RPlayGame(deck1, deck2) + + fmt.Printf("== Post-game results ==\n%s\n%s\n", deck1, deck2) + var score int + if winner == 1 { + score = deck1.Score() + } else { + score = deck2.Score() + } + fmt.Println("## Part 2:\nAnswer: ", score) +} + +var totalGames int + +func RPlayGame(deck1, deck2 *Deck) int { + var history []string + var repeat bool + for deck1.Len() > 0 && deck2.Len() > 0 { + history, repeat = RPlayRound(deck1, deck2, history) + if repeat { + return 1 + } + } + return Winner(deck1, deck2) +} + +func RPlayRound(deck1, deck2 *Deck, history []string) ([]string, bool) { + status := fmt.Sprintf("%s%s", deck1, deck2) + if h.StringSliceContains(history, status) { + return history, true + } + nextHistory := append(history, status) + c1, c2 := deck1.Draw(), deck2.Draw() + if deck1.Len() >= c1 && deck2.Len() >= c2 { + winner := RPlayGame(deck1.Copy(c1), deck2.Copy(c2)) + switch winner { + case 1: + deck1.Add(c1, c2) + case 2: + deck2.Add(c2, c1) + } + return nextHistory, false + } + if c1 > c2 { + deck1.Add(c1, c2) + } else { + deck2.Add(c2, c1) + } + + return nextHistory, false +} + +func Winner(deck1, deck2 *Deck) int { + if deck2.Empty() { + return 1 + } else if deck1.Empty() { + return 2 + } + return -1 +} + +type Deck struct { + Player int + cards []int +} + +func (d *Deck) Add(card ...int) { + d.cards = append(d.cards, card...) +} + +func (d *Deck) Draw() int { + var ret int + ret, d.cards = d.cards[0], d.cards[1:] + return ret +} + +func (d *Deck) Empty() bool { + return len(d.cards) == 0 +} + +func (d *Deck) Len() int { + return len(d.cards) +} + +func (d *Deck) Score() int { + var ret int + for k := len(d.cards) - 1; k >= 0; k-- { + ret = ret + (d.cards[k] * (len(d.cards) - k)) + } + return ret +} + +func (d *Deck) Copy(num int) *Deck { + ret := Deck{ + Player: d.Player, + } + for k := 0; k < num && k < len(d.cards); k++ { + ret.Add(d.cards[k]) + } + return &ret + +} + +func (d Deck) String() string { + return fmt.Sprintf("Player %d's deck: %v", d.Player, d.cards) +} diff --git a/2020/day22/testinput b/2020/day22/testinput new file mode 100644 index 0000000..391cd24 --- /dev/null +++ b/2020/day22/testinput @@ -0,0 +1,13 @@ +Player 1: +9 +2 +6 +3 +1 + +Player 2: +5 +8 +4 +7 +10 diff --git a/2020/day22/testinput2 b/2020/day22/testinput2 new file mode 100644 index 0000000..a29e13a --- /dev/null +++ b/2020/day22/testinput2 @@ -0,0 +1,8 @@ +Player 1: +43 +19 + +Player 2: +2 +29 +14