aoc2023/day-10/one.go
2023-12-11 18:58:13 +00:00

145 lines
3.9 KiB
Go

package main
import (
log "github.com/sirupsen/logrus"
)
type coords struct {
X int
Y int
}
type points struct {
points []point
}
type point struct {
N bool
S bool
E bool
W bool
coords
identifier rune
}
var pointsArray = []points{}
type tracker struct {
init point
point point
last []coords
steps int
}
// newTracker stores the starting point
// it creates a queue for storing past 2 moves
// returns a tracker struct for counting steps
func newTracker() tracker {
tracker := tracker{last: make([]coords, 0)}
for _, each := range pointsArray {
for _, point := range each.points {
if point.identifier == 'S' {
tracker.init = point
tracker.point = tracker.init
tracker.last = make([]coords, 1)
tracker.last = append(tracker.last, tracker.point.coords)
}
}
}
return tracker
}
func (t tracker) X() int {
return t.point.X
}
func (t tracker) Y() int {
return t.point.Y
}
// mapPoints builds the points array mapping connection types for each coordinate
func mapPoints(lines []string) {
pointsArray = make([]points, 0)
for i, line := range lines {
var ps = make([]point, 0)
for j, r := range line {
switch r {
case '|':
ps = append(ps, point{N: true, S: true, E: false, W: false}) // N,S
case '-':
ps = append(ps, point{N: false, S: false, E: true, W: true}) // E, W
case 'L':
ps = append(ps, point{N: true, S: false, E: true, W: false}) // N, E
case 'J':
ps = append(ps, point{N: true, S: false, E: false, W: true}) // N, W
case '7':
ps = append(ps, point{N: false, S: true, E: false, W: true}) // S, W
case 'F':
ps = append(ps, point{N: false, S: true, E: true, W: false}) // S, E
case '.':
ps = append(ps, point{N: false, S: false, E: false, W: false}) // ground
case 'S':
ps = append(ps, point{N: true, S: true, E: true, W: true}) // start
default:
log.Debug("ground point")
}
ps[j].identifier = r
ps[j].coords.Y = i
ps[j].coords.X = j
}
pointsArray = append(pointsArray, points{points: ps})
}
}
// walk moves along the pipes storing points that mark loop locations
// it also keeps a track of last two moves
// returns the number of steps to traverse all pipes
func walk(tracker tracker) int {
for ; tracker.steps == 0 || !comparePoints(tracker.init, tracker.point); tracker.steps++ {
next := checkSouth(tracker.point)
if !inLastMoves(tracker.last, next.coords) {
log.Debug("moving south from ", string(tracker.point.identifier), " to ", string(next.identifier))
tracker.point = next
loop = append(loop, pointsArray[tracker.Y()].points[tracker.X()].coords)
tracker.last = append(tracker.last[1:], next.coords)
continue
}
next = checkEast(tracker.point)
if !inLastMoves(tracker.last, next.coords) {
log.Debug("moving east from ", string(tracker.point.identifier), " to ", string(next.identifier))
tracker.point = next
loop = append(loop, pointsArray[tracker.Y()].points[tracker.X()].coords)
tracker.last = append(tracker.last[1:], next.coords)
continue
}
next = checkNorth(tracker.point)
if !inLastMoves(tracker.last, next.coords) {
log.Debug("moving north from ", string(tracker.point.identifier), " to ", string(next.identifier))
tracker.point = next
loop = append(loop, pointsArray[tracker.Y()].points[tracker.X()].coords)
tracker.last = append(tracker.last[1:], next.coords)
continue
}
next = checkWest(tracker.point)
if !inLastMoves(tracker.last, next.coords) {
log.Debug("moving west from ", string(tracker.point.identifier), " to ", string(next.identifier))
tracker.point = next
loop = append(loop, pointsArray[tracker.Y()].points[tracker.X()].coords)
tracker.last = append(tracker.last[1:], next.coords)
continue
}
tracker.steps++ // the very last move will be back at start
}
return tracker.steps
}
// one returns the number of steps to reach the furthest point from the start
func one(lines []string) int {
mapPoints(lines)
tracker := newTracker()
return walk(tracker) / 2
}