2021 Day 21 Complete
This commit is contained in:
		@@ -1,7 +1,112 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "fmt"
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h "git.bullercodeworks.com/brian/adventofcode/helpers"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								2021/day21/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								2021/day21/input
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					Player 1 starting position: 4
 | 
				
			||||||
 | 
					Player 2 starting position: 2
 | 
				
			||||||
							
								
								
									
										137
									
								
								2021/day21/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								2021/day21/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2
									
								
								2021/day21/testinput
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								2021/day21/testinput
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					Player 1 starting position: 4
 | 
				
			||||||
 | 
					Player 2 starting position: 8
 | 
				
			||||||
		Reference in New Issue
	
	Block a user