123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- package main
-
- import (
- "fmt"
- "github.com/csmith/aoc-2019/common"
- "math"
- "strings"
- )
-
- type line struct {
- from int64
- to int64
- perp int64
- steps int64
- }
-
- // readWire reads the instructions for a wire and populates the given slices with the horizontal and vertical lines
- // that make up the wire's path.
- func readWire(wire string, horizontal *[]line, vertical *[]line) {
- moves := strings.Split(wire, ",")
- x := int64(0)
- y := int64(0)
- steps := int64(0)
-
- for _, move := range moves {
- length := int64(common.MustAtoi(move[1:]))
- switch move[0] {
- case 'U':
- *vertical = append(*vertical, line{from: y, to: y - length, perp: x, steps: steps})
- y -= length
- case 'D':
- *vertical = append(*vertical, line{from: y, to: y + length, perp: x, steps: steps})
- y += length
- case 'L':
- *horizontal = append(*horizontal, line{from: x, to: x - length, perp: y, steps: steps})
- x -= length
- case 'R':
- *horizontal = append(*horizontal, line{from: x, to: x + length, perp: y, steps: steps})
- x += length
- }
- steps += length
- }
- }
-
- // checkCrosses checks if any of the given sets of perpendicular lines cross, and returns the
- // smallest Manhattan distance to the origin, and the smallest number of combined steps, of
- // those crosses.
- func checkCrosses(horizontal *[]line, vertical *[]line) (int64, int64) {
- var (
- bestDistance int64 = math.MaxInt64
- bestSteps int64 = math.MaxInt64
- )
-
- for _, h := range *horizontal {
- for _, v := range *vertical {
- var steps int64 = math.MaxInt64
- if h.from <= v.perp && v.perp <= h.to {
- // If the horizontal line goes left-to-right
- if v.from <= h.perp && h.perp <= v.to {
- // If the vertical line goes top-to-bottom
- steps = (h.steps + v.perp - h.from) + (v.steps + h.perp - v.from)
- } else if v.to <= h.perp && h.perp <= v.from {
- // If the vertical line goes bottom-to-top
- steps = (h.steps + v.perp - h.from) + (v.steps + v.from - h.perp)
- } else {
- continue
- }
- } else if h.to <= v.perp && v.perp <= h.from {
- // If the horizontal line goes right-to-left
- if v.from <= h.perp && h.perp <= v.to {
- // If the vertical line goes top-to-bottom
- steps = (h.steps + h.from - v.perp) + (v.steps + h.perp - v.from)
- } else if v.to <= h.perp && h.perp <= v.from {
- // If the vertical line goes bottom-to-top
- steps = (h.steps + h.from - v.perp) + (v.steps + v.from - h.perp)
- } else {
- continue
- }
- } else {
- continue
- }
-
- distance := common.Abs(v.perp) + common.Abs(h.perp)
- if distance < bestDistance {
- bestDistance = distance
- }
- if steps < bestSteps {
- bestSteps = steps
- }
- }
- }
-
- return bestDistance, bestSteps
- }
-
- func traceWires() (int64, int64) {
- var (
- horiz1 []line
- horiz2 []line
- vert1 []line
- vert2 []line
- )
-
- wires := common.ReadFileAsStrings("03/input.txt")
- readWire(wires[0], &horiz1, &vert1)
- readWire(wires[1], &horiz2, &vert2)
-
- d1, s1 := checkCrosses(&horiz1, &vert2)
- d2, s2 := checkCrosses(&horiz2, &vert1)
- return min(d1, d2), min(s1, s2)
- }
-
- func main() {
- part1, part2 := traceWires()
- fmt.Println(part1)
- fmt.Println(part2)
- }
-
- func min(a, b int64) int64 {
- if a < b {
- return a
- } else {
- return b
- }
- }
|