Day14
This commit is contained in:
172
2024/gareth/day14/day14.go
Normal file
172
2024/gareth/day14/day14.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package day14
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Robot struct {
|
||||
px, py int // position
|
||||
vx, vy int // velocity
|
||||
}
|
||||
|
||||
func Part1(input string) int {
|
||||
// Parse the input
|
||||
lines := strings.Split(input, "\n")
|
||||
var robots []Robot
|
||||
for _, line := range lines {
|
||||
robot := ParseRobot(line)
|
||||
robots = append(robots, robot)
|
||||
}
|
||||
|
||||
// Define grid size
|
||||
gridWidth := 101
|
||||
gridHeight := 103
|
||||
|
||||
// Update robot positions for 100 seconds
|
||||
for i := 0; i < 100; i++ {
|
||||
for j := range robots {
|
||||
robots[j].UpdatePosition(gridWidth, gridHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// Count the robots in each quadrant
|
||||
q1, q2, q3, q4 := CountRobotsInQuadrants(robots, gridWidth, gridHeight)
|
||||
fmt.Printf("Quadrant counts: Q1=%d, Q2=%d, Q3=%d, Q4=%d\n", q1, q2, q3, q4)
|
||||
|
||||
// Calculate the safety factor
|
||||
safetyFactor := CalculateSafetyFactor(q1, q2, q3, q4)
|
||||
fmt.Printf("Safety Factor: %d\n", safetyFactor)
|
||||
return safetyFactor
|
||||
}
|
||||
|
||||
func Part2(input string) int {
|
||||
// Parse the input
|
||||
lines := strings.Split(input, "\n")
|
||||
var robots []Robot
|
||||
for _, line := range lines {
|
||||
robot := ParseRobot(line)
|
||||
robots = append(robots, robot)
|
||||
}
|
||||
|
||||
// Define grid size
|
||||
gridWidth := 101
|
||||
gridHeight := 103
|
||||
|
||||
// Update robot positions for 100 seconds
|
||||
for i := 0; i < 6285; i++ {
|
||||
for j := range robots {
|
||||
robots[j].UpdatePosition(gridWidth, gridHeight)
|
||||
}
|
||||
}
|
||||
|
||||
DisplayGrid(robots, gridWidth, gridHeight)
|
||||
return 2
|
||||
}
|
||||
|
||||
// ParseRobot takes a line of input and converts it to a Robot struct
|
||||
func ParseRobot(line string) Robot {
|
||||
parts := strings.Split(line, " ")
|
||||
posParts := strings.Split(parts[0][2:], ",") // Extract p=x,y and split
|
||||
velParts := strings.Split(parts[1][2:], ",") // Extract v=x,y and split
|
||||
|
||||
px, _ := strconv.Atoi(posParts[0])
|
||||
py, _ := strconv.Atoi(posParts[1])
|
||||
vx, _ := strconv.Atoi(velParts[0])
|
||||
vy, _ := strconv.Atoi(velParts[1])
|
||||
|
||||
return Robot{px, py, vx, vy}
|
||||
}
|
||||
|
||||
// UpdatePosition updates the position of a robot, considering the wrap-around
|
||||
func (r *Robot) UpdatePosition(gridWidth, gridHeight int) {
|
||||
r.px = (r.px + r.vx + gridWidth) % gridWidth
|
||||
r.py = (r.py + r.vy + gridHeight) % gridHeight
|
||||
}
|
||||
|
||||
// CountRobotsInQuadrants counts the number of robots in each of the four quadrants
|
||||
func CountRobotsInQuadrants(robots []Robot, width, height int) (int, int, int, int) {
|
||||
midX := width / 2
|
||||
midY := height / 2
|
||||
|
||||
q1, q2, q3, q4 := 0, 0, 0, 0
|
||||
|
||||
for _, r := range robots {
|
||||
if r.px == midX || r.py == midY {
|
||||
// Skip robots on the middle line
|
||||
continue
|
||||
}
|
||||
if r.px < midX && r.py < midY {
|
||||
q1++ // Top-left quadrant
|
||||
} else if r.px > midX && r.py < midY {
|
||||
q2++ // Top-right quadrant
|
||||
} else if r.px < midX && r.py > midY {
|
||||
q3++ // Bottom-left quadrant
|
||||
} else if r.px > midX && r.py > midY {
|
||||
q4++ // Bottom-right quadrant
|
||||
}
|
||||
}
|
||||
|
||||
return q1, q2, q3, q4
|
||||
}
|
||||
|
||||
// CalculateSafetyFactor multiplies the number of robots in each quadrant
|
||||
func CalculateSafetyFactor(q1, q2, q3, q4 int) int {
|
||||
return q1 * q2 * q3 * q4
|
||||
}
|
||||
|
||||
// DisplayGrid displays the current state of the grid
|
||||
func DisplayGrid(robots []Robot, width, height int) {
|
||||
grid := make([][]rune, height)
|
||||
for i := range grid {
|
||||
grid[i] = make([]rune, width)
|
||||
for j := range grid[i] {
|
||||
grid[i][j] = '.'
|
||||
}
|
||||
}
|
||||
for _, r := range robots {
|
||||
grid[r.py][r.px] = '#'
|
||||
}
|
||||
for _, row := range grid {
|
||||
fmt.Println(string(row))
|
||||
}
|
||||
}
|
||||
|
||||
// FindEasterEgg determines the fewest number of seconds that must elapse for the robots to display the Easter egg
|
||||
func FindEasterEgg(robots []Robot, width, height int) int {
|
||||
smallestArea := width * height
|
||||
bestTime := 0
|
||||
for t := 6285; t < 6286; t++ { // Large upper limit to search
|
||||
// Update robot positions
|
||||
for i := range robots {
|
||||
robots[i].UpdatePosition(width, height)
|
||||
}
|
||||
// Calculate the bounding box of all robot positions
|
||||
minX, minY := width, height
|
||||
maxX, maxY := 0, 0
|
||||
for _, r := range robots {
|
||||
if r.px < minX {
|
||||
minX = r.px
|
||||
}
|
||||
if r.px > maxX {
|
||||
maxX = r.px
|
||||
}
|
||||
if r.py < minY {
|
||||
minY = r.py
|
||||
}
|
||||
if r.py > maxY {
|
||||
maxY = r.py
|
||||
}
|
||||
}
|
||||
|
||||
area := (maxX - minX + 1) * (maxY - minY + 1)
|
||||
if area < smallestArea {
|
||||
smallestArea = area
|
||||
bestTime = t + 1
|
||||
fmt.Printf("Time: %d\n", bestTime)
|
||||
DisplayGrid(robots, width, height)
|
||||
}
|
||||
}
|
||||
return bestTime
|
||||
}
|
||||
Reference in New Issue
Block a user