Skip to content

Commit

Permalink
Solution for 2024, day 15
Browse files Browse the repository at this point in the history
  • Loading branch information
lucianoq committed Dec 15, 2024
1 parent 87d85c3 commit 4511704
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 0 deletions.
19 changes: 19 additions & 0 deletions 2024/15/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
input:
http "https://adventofcode.com/2024/day/15/input" "Cookie:session=${AOC_SESSION};" >input

main1:
go build -o main1 main1.go common.go

main2:
go build -o main2 main2.go common.go

.PHONY: run1 run2 clean

run1: main1 input
./main1 <input

run2: main2 input
./main2 <input

clean:
rm -f main1 main2 input
82 changes: 82 additions & 0 deletions 2024/15/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"bufio"
"errors"
"os"
)

var (
Width, Height = 50, 50
NotFound = errors.New("not found")
)

func parseInput() (map[P]byte, []byte, P) {
var robot P
m := map[P]byte{}

scanner := bufio.NewScanner(os.Stdin)

for i := 0; scanner.Scan(); i++ {
line := scanner.Text()

if line == "" {
break
}

for j, c := range line {
if c == '@' {
robot = P{i, j}
m[P{i, j}] = '.'
} else {
m[P{i, j}] = byte(c)
}
}
}

moves := []byte{}
for scanner.Scan() {
moves = append(moves, []byte(scanner.Text())...)
}
return m, moves, robot
}

type P struct{ x, y int }

func getDelta(move byte) P {
switch move {
case '<':
return P{0, -1}
case '>':
return P{0, 1}
case '^':
return P{-1, 0}
case 'v':
return P{1, 0}
}
panic("invalid move")
}

func findNextEmpty(m map[P]byte, p, delta P) (P, error) {
for {
p = P{p.x + delta.x, p.y + delta.y}
switch m[p] {
case '.':
return p, nil
case '#':
return P{}, NotFound
}
}
}

func gps(m map[P]byte, char byte) int {
sum := 0
for i := 0; i < Height; i++ {
for j := 0; j < Width; j++ {
if m[P{i, j}] == char {
sum += 100*i + j
}
}
}
return sum
}
27 changes: 27 additions & 0 deletions 2024/15/main1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import "fmt"

func main() {
m, moves, robot := parseInput()
for _, move := range moves {
robot = apply(m, move, robot)
}
fmt.Println(gps(m, 'O'))
}

func apply(m map[P]byte, move byte, robot P) P {
delta := getDelta(move)

nextEmpty, err := findNextEmpty(m, robot, delta)
if err != nil {
return robot
}

closest := P{robot.x + delta.x, robot.y + delta.y}
if m[closest] == 'O' {
m[closest] = '.'
m[nextEmpty] = 'O'
}
return closest
}
107 changes: 107 additions & 0 deletions 2024/15/main2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package main

import "fmt"

func main() {
m, moves, robot := parseInput()
m, robot = grow(m, robot)
for _, move := range moves {
robot = apply(m, move, robot)
}
fmt.Println(gps(m, '['))
}

func grow(m map[P]byte, robot P) (map[P]byte, P) {
newM := make(map[P]byte, len(m)*2)
for i := 0; i < Height; i++ {
for j := 0; j < Width; j++ {
p := P{i, j}
switch m[p] {
case '#':
newM[P{p.x, 2 * p.y}] = '#'
newM[P{p.x, 2*p.y + 1}] = '#'
case 'O':
newM[P{p.x, 2 * p.y}] = '['
newM[P{p.x, 2*p.y + 1}] = ']'
case '.':
newM[P{p.x, 2 * p.y}] = '.'
newM[P{p.x, 2*p.y + 1}] = '.'
case '@':
newM[P{p.x, 2 * p.y}] = '@'
newM[P{p.x, 2*p.y + 1}] = '.'
}
}
}
Width *= 2
return newM, P{robot.x, 2 * robot.y}
}

func apply(m map[P]byte, move byte, robot P) P {
delta := getDelta(move)

nextEmpty, err := findNextEmpty(m, robot, delta)
if err != nil {
return robot
}

if move == '<' || move == '>' {
for curr := nextEmpty; curr != robot; {
closest := P{curr.x, curr.y - delta.y}
m[curr], m[closest] = m[closest], m[curr]
curr = closest
}
return P{robot.x, robot.y + delta.y}
}

if move == '^' || move == 'v' {
affected, maxLevel, err := affectedVertically(m, robot, delta.x)
if err != nil {
return robot
}
for x := maxLevel; x != robot.x; x -= delta.x {
for col := range affected[x] {
m[P{x + delta.x, col}], m[P{x, col}] = m[P{x, col}], m[P{x + delta.x, col}]
}
}

return P{robot.x + delta.x, robot.y}
}

panic("unreachable")
}

func affectedVertically(m map[P]byte, robot P, deltaX int) (map[int]map[int]struct{}, int, error) {
affected := map[int]map[int]struct{}{
robot.x: {robot.y: {}},
}

for currX := robot.x; ; currX += deltaX {
newCols, err := newColumns(m, currX+deltaX, affected[currX])
if err != nil {
return nil, 0, err
}

if len(newCols) == 0 {
return affected, currX, nil
}

affected[currX+deltaX] = newCols
}
}

func newColumns(m map[P]byte, nextX int, columns map[int]struct{}) (map[int]struct{}, error) {
newCols := map[int]struct{}{}
for col := range columns {
switch m[P{nextX, col}] {
case '#':
return nil, NotFound
case '[':
newCols[col] = struct{}{}
newCols[col+1] = struct{}{}
case ']':
newCols[col] = struct{}{}
newCols[col-1] = struct{}{}
}
}
return newCols, nil
}

0 comments on commit 4511704

Please sign in to comment.