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 } 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}) } } // initializeTracker stores the starting point, creates coords array for tracking last moves func initializeTracker() 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 } // walk moves along the pipes storing poinst 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 { var steps int for steps := 0; steps == 0 || !comparePoints(tracker.init, tracker.point); 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 } steps++ } return steps } // one returns the number of steps to reach the furthest point from the start func one(lines []string) int { mapPoints(lines) tracker := initializeTracker() return walk(tracker) / 2 }