173 lines
4.1 KiB
Go
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
|
|
}
|