119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
package day09
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"adventofcode2022/utils"
|
|
sparsegrid "adventofcode2022/utils/sparseGrid"
|
|
)
|
|
|
|
type rope struct {
|
|
size int
|
|
posX []int
|
|
posY []int
|
|
}
|
|
|
|
func Part1(input string) int {
|
|
rope := newRope(2)
|
|
grid := sparsegrid.NewGrid(false)
|
|
grid.Set(rope.posX[rope.size-1], rope.posY[rope.size-1], true)
|
|
for _, line := range strings.Split(input, "\n") {
|
|
dx := 0
|
|
dy := 0
|
|
switch line[0] {
|
|
case 'R':
|
|
dx = 1
|
|
case 'U':
|
|
dy = -1
|
|
case 'D':
|
|
dy = 1
|
|
case 'L':
|
|
dx = -1
|
|
}
|
|
n := utils.MustAtoi(line[2:])
|
|
for i := 0; i < n; i++ {
|
|
// move head
|
|
rope.posX[0] += dx
|
|
rope.posY[0] += dy
|
|
|
|
// update tail
|
|
rope.updateTail()
|
|
grid.Set(rope.posX[rope.size-1], rope.posY[rope.size-1], true)
|
|
}
|
|
}
|
|
return grid.Visited()
|
|
}
|
|
|
|
func Part2(input string) int {
|
|
rope := newRope(10)
|
|
grid := sparsegrid.NewGrid(false)
|
|
grid.Set(rope.posX[rope.size-1], rope.posY[rope.size-1], true)
|
|
for _, line := range strings.Split(input, "\n") {
|
|
dx := 0
|
|
dy := 0
|
|
switch line[0] {
|
|
case 'R':
|
|
dx = 1
|
|
case 'U':
|
|
dy = -1
|
|
case 'D':
|
|
dy = 1
|
|
case 'L':
|
|
dx = -1
|
|
}
|
|
n := utils.MustAtoi(line[2:])
|
|
for i := 0; i < n; i++ {
|
|
// move head
|
|
rope.posX[0] += dx
|
|
rope.posY[0] += dy
|
|
|
|
// update tail
|
|
rope.updateTail()
|
|
grid.Set(rope.posX[rope.size-1], rope.posY[rope.size-1], true)
|
|
}
|
|
}
|
|
return grid.Visited()
|
|
}
|
|
|
|
func newRope(size int) *rope {
|
|
return &rope{
|
|
size: size,
|
|
posX: make([]int, size),
|
|
posY: make([]int, size),
|
|
}
|
|
}
|
|
|
|
func (r *rope) updateTail() {
|
|
outer:
|
|
for i := 1; i < r.size; i++ {
|
|
diffX := utils.Abs(r.posX[i-1] - r.posX[i])
|
|
diffY := utils.Abs(r.posY[i-1] - r.posY[i])
|
|
if diffX <= 1 && diffY <= 1 {
|
|
// no need to update node if it's touching
|
|
continue
|
|
}
|
|
moves := [][]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
|
|
for _, move := range moves {
|
|
t := utils.Max(
|
|
utils.Abs(r.posX[i-1]-r.posX[i]+move[0]),
|
|
utils.Abs(r.posY[i-1]-r.posY[i]+move[1]))
|
|
if t == 1 {
|
|
r.posX[i] = r.posX[i-1] + move[0]
|
|
r.posY[i] = r.posY[i-1] + move[1]
|
|
continue outer
|
|
}
|
|
}
|
|
moves = [][]int{{1, 1}, {-1, 1}, {1, -1}, {-1, -1}}
|
|
for _, move := range moves {
|
|
t := utils.Max(
|
|
utils.Abs(r.posX[i-1]-r.posX[i]+move[0]),
|
|
utils.Abs(r.posY[i-1]-r.posY[i]+move[1]))
|
|
if t == 1 {
|
|
r.posX[i] = r.posX[i-1] + move[0]
|
|
r.posY[i] = r.posY[i-1] + move[1]
|
|
continue outer
|
|
}
|
|
}
|
|
panic("unreachable")
|
|
}
|
|
} |