Files
adventofcode/2024/gareth/day14/day14.go
Gareth a5b1227979 Day14
2025-01-11 16:39:58 +00:00

173 lines
4.1 KiB
Go

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
}