diff --git a/2021/day19/main.go b/2021/day19/main.go index 50e8d8d..5f12a3d 100644 --- a/2021/day19/main.go +++ b/2021/day19/main.go @@ -1,7 +1,112 @@ package main -import "fmt" +import ( + "errors" + "fmt" + "os" + "strings" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) func main() { - fmt.Println("vim-go") + inp := h.StdinToStringSlice() + scanners := parseScanners(inp) + foundBeacons := scanners[0].beacons + foundScannerPositions := []beacon{{0, 0, 0}} + + remaining := scanners[1:] + for len(remaining) > 0 { + var wrk scanner + wrk, remaining = remaining[0], remaining[1:] + s := NewScanner(foundBeacons).getScannerFromOverlap(wrk) + if s == nil { + remaining = append(remaining, s) + } else { + foundBeacons = append(foundBeacons, s.beacons...) + //foundScannerPositions = append(foundScannerPositions, + } + } +} + +func parseScanners(inp []string) []scanner { + var scanners []scanner + for i := range inp { + if strings.HasPrefix(inp[i], "---") { + // Find the next empty line + end := i + for ; end < len(inp); end++ { + if inp[end] == "" { + break + } + } + // a new scanner + wrk, err := NewScannerFromInput(inp[i:end]) + if err == nil { + scanners = append(scanners, wrk) + } else { + fmt.Println("Error parsing scanners") + os.Exit(1) + } + } + } + return scanners +} + +type scanner struct { + number int + region map[h.Coordinate]bool + beacons []beacon +} + +func NewScanner(b []beacon) scanner { + return scanner{beacons: b} +} + +func NewScannerFromInput(inp []string) (scanner, error) { + s := scanner{} + r := strings.NewReader(inp[0]) + _, err := fmt.Fscanf(r, "--- scanner %d ---", &s.number) + if err != nil { + return s, errors.New("No Scanner ID") + } + for _, v := range inp[1:] { + r = strings.NewReader(v) + b := beacon{} + _, err := fmt.Fscanf(r, "%d,%d,%d", &b.x, &b.y, &b.z) + if err == nil { + s.beacons = append(s.beacons, b) + } + } + return s, nil +} + +func (s scanner) allRotations() [][]beacon { + var beacons [][]beacon + for i := range s.beacons { + beacons = append(beacons, s.beacons[i].allRotations()) + } + return beacons +} + +func (s scanner) String() string { + return fmt.Sprintf("-- Scanner %d (%d beacons)---", s.number, len(s.beacons)) +} + +type beacon struct { + x, y, z int +} + +func (b beacon) allRotations() []beacon { + return []beacon{ + {b.x, b.y, b.z}, {b.x, -b.z, b.y}, {b.x, -b.y, -b.z}, {b.x, b.z, -b.y}, {-b.x, -b.y, b.z}, + {-b.x, -b.z, -b.y}, {-b.x, b.y, -b.z}, {-b.x, b.z, b.y}, {-b.z, b.x, -b.y}, {b.y, b.x, -b.z}, + {b.z, b.x, b.y}, {-b.y, b.x, b.z}, {b.z, -b.x, -b.y}, {b.y, -b.x, b.z}, {-b.z, -b.x, b.y}, + {-b.y, -b.x, -b.z}, {-b.y, -b.z, b.x}, {b.z, -b.y, b.x}, {b.y, b.z, b.x}, {-b.z, b.y, b.x}, + {b.z, b.y, -b.x}, {-b.y, b.z, -b.x}, {-b.z, -b.y, -b.x}, {b.y, -b.z, -b.x}, + } +} + +func (b beacon) String() string { + return fmt.Sprintf("{%d,%d,%d}", b.x, b.y, b.z) } diff --git a/2021/day21/input b/2021/day21/input new file mode 100644 index 0000000..94d668d --- /dev/null +++ b/2021/day21/input @@ -0,0 +1,2 @@ +Player 1 starting position: 4 +Player 2 starting position: 2 diff --git a/2021/day21/main.go b/2021/day21/main.go new file mode 100644 index 0000000..a44495a --- /dev/null +++ b/2021/day21/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "fmt" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +func main() { + inp := h.StdinToStringSlice() + var starting []int + for i := range inp { + starting = append(starting, int(inp[i][len(inp[i])-1]-'0')) + } + part1(starting) + fmt.Println() + part2(starting) +} + +type player struct { + number int + position, score int +} + +func (p *player) move(spaces int) { + p.position = (p.position + spaces) % 10 + if p.position == 0 { + p.position = 10 + } + p.score += p.position +} + +type die struct { + value int + rolls int +} + +func (d *die) roll() int { + d.rolls++ + d.value++ + if d.value > 100 { + d.value = 1 + } + return d.value +} + +func part1(pos []int) { + var players []player + for i := range pos { + players = append(players, player{number: i + 1, position: pos[i]}) + } + die := die{value: 0} + pTurn := 0 + for players[0].score < 1000 && players[1].score < 1000 { + turn := die.roll() + die.roll() + die.roll() + players[pTurn].move(turn) + pTurn = (pTurn + 1) % len(players) + } + var loser player + for i := range players { + if loser.number == 0 || players[i].score < loser.score { + loser = players[i] + } + } + fmt.Println("# Part 1") + fmt.Printf("Player %d loses, score %d\n", (loser.number), loser.score*die.rolls) +} + +func part2(pos []int) { + var players []player + for i := range pos { + players = append(players, player{number: i + 1, position: pos[i]}) + } + + diracIt(pos[0], pos[1]) +} + +type gameState struct { + p1, p2 int + s1, s2 int +} + +// Run the games with the dirac die. +func diracIt(p1, p2 int) { + move := func(pos, roll int) int { + pos += roll + pos = pos % 10 + if pos == 0 { + return 10 + } + return pos + } + + states := map[gameState]int64{{p1, p2, 0, 0}: 1} + rolls := map[int]int64{} + for r1 := 1; r1 <= 3; r1++ { + for r2 := 1; r2 <= 3; r2++ { + for r3 := 1; r3 <= 3; r3++ { + rolls[r1+r2+r3] += 1 + } + } + } + var p1w, p2w int64 = 0, 0 + for len(states) != 0 { + for turn := 1; turn <= 2; turn++ { + nextStates := map[gameState]int64{} + for state, count := range states { + for roll, rCount := range rolls { + p1, p2 := state.p1, state.p2 + s1, s2 := state.s1, state.s2 + n := count * rCount + + if turn == 1 { + p1 = move(p1, roll) + s1 += p1 + if s1 > 20 { + p1w += n + } else { + nextStates[gameState{p1, p2, s1, s2}] += n + } + } else { + p2 = move(p2, roll) + s2 += p2 + if s2 > 20 { + p2w += n + } else { + nextStates[gameState{p1, p2, s1, s2}] += n + } + } + } + } + states = nextStates + } + } + fmt.Println("# Part 2") + fmt.Printf("Player 1 Wins: %d\nPlayer 2 Wins: %d\n", p1w, p2w) +} diff --git a/2021/day21/testinput b/2021/day21/testinput new file mode 100644 index 0000000..3f69194 --- /dev/null +++ b/2021/day21/testinput @@ -0,0 +1,2 @@ +Player 1 starting position: 4 +Player 2 starting position: 8