Day 4 Part 1
This commit is contained in:
101
day-03/main.nim
Normal file
101
day-03/main.nim
Normal file
@@ -0,0 +1,101 @@
|
||||
import strutils, hashes, sets, sequtils, algorithm
|
||||
|
||||
type Point = object
|
||||
x: int
|
||||
y: int
|
||||
|
||||
type Intersection = object
|
||||
point: Point
|
||||
steps: int
|
||||
|
||||
proc absCmp(x, y: Point): int =
|
||||
## Compate Points by absolute values (-3, -3) nad (3, 3) are equal
|
||||
if (x.x.abs + x.y.abs) < (y.x.abs + y.y.abs):
|
||||
return -1
|
||||
if (x.x.abs + x.y.abs) == (y.x.abs + y.y.abs):
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc hash(x: Point): Hash =
|
||||
## Make Points hashable
|
||||
var h: Hash = 0
|
||||
h = h !& hash(x.x)
|
||||
h = h !& hash(x.y)
|
||||
result = !$h
|
||||
|
||||
proc hash(x: Intersection): Hash =
|
||||
## Make Intersections hashable
|
||||
var h: Hash = 0
|
||||
h = h !& hash(x.point)
|
||||
h = h !& hash(x.steps)
|
||||
result = !$h
|
||||
|
||||
iterator inDirection(cursor: var Point, op: string): Point {.closure.} =
|
||||
## Iterate all Points from the current cursor position to the target of the operation
|
||||
let amount = op.substr(1).parseInt
|
||||
case op[0]: # The directional letter
|
||||
of 'U':
|
||||
for i in cursor.y + 1 .. cursor.y + amount:
|
||||
yield Point(x: cursor.x, y: i)
|
||||
cursor.y += amount
|
||||
of 'R':
|
||||
for i in cursor.x + 1 .. cursor.x + amount:
|
||||
yield Point(x: i, y: cursor.y)
|
||||
cursor.x += amount
|
||||
of 'D':
|
||||
for i in countdown(cursor.y - 1, cursor.y - amount):
|
||||
yield Point(x: cursor.x, y: i)
|
||||
cursor.y -= amount
|
||||
of 'L':
|
||||
for i in countdown(cursor.x - 1, cursor.x - amount):
|
||||
yield Point(x: i, y: cursor.y)
|
||||
cursor.x -= amount
|
||||
else:
|
||||
raise newException(ValueError, "Unrecognized direction")
|
||||
|
||||
proc processOp(cursor: var Point, op: string, compareTo: HashSet[Point], matches: var HashSet[Intersection], steps: var int): seq[Point] =
|
||||
for point in cursor.inDirection(op):
|
||||
result.add(point)
|
||||
steps.inc
|
||||
if compareTo.contains(point):
|
||||
matches.incl(Intersection(point: point, steps: steps))
|
||||
|
||||
proc tracePath(line: seq[string], compareTo: HashSet[Point], matches: var HashSet[Intersection]): seq[Point] =
|
||||
## Moves along the path, given by the line and saves all visited locations.
|
||||
var
|
||||
cursor = Point(x: 0, y:0)
|
||||
steps = 0
|
||||
for op in line:
|
||||
result.add(cursor.processOp(op, compareTo, matches, steps))
|
||||
|
||||
proc findFirstIntersection(matches1, matches2 : HashSet[Intersection]): int =
|
||||
## Compare two sets of intersections and find the steps, woth need to reach the first intersection
|
||||
result = int.high
|
||||
for inter1 in matches1:
|
||||
for inter2 in matches2:
|
||||
if inter1.point == inter2.point and result >= inter1.steps + inter2.steps:
|
||||
result = inter1.steps + inter2.steps
|
||||
|
||||
|
||||
var file = open("input.txt", fmRead)
|
||||
# Assume there are only two wires
|
||||
var line1 = file.readLine.split(",")
|
||||
var line2 = file.readLine.split(",")
|
||||
|
||||
var
|
||||
compare: HashSet[Point]
|
||||
matches: HashSet[Intersection]
|
||||
|
||||
var path1 = line1.tracePath(compare, matches)
|
||||
var path2 = line2.tracePath(compare, matches)
|
||||
|
||||
var intersections: seq[Point] = path1.toHashSet.intersection(path2.toHashSet).toSeq
|
||||
intersections.sort(absCmp)
|
||||
let nearest = intersections[0]
|
||||
echo "Part 1. Distance to nearest intersection -> ", nearest.x.abs + nearest.y.abs
|
||||
|
||||
var path1Matches: HashSet[Intersection]
|
||||
var path2Matches: HashSet[Intersection]
|
||||
discard line1.tracePath(intersections.toHashSet, path1Matches)
|
||||
discard line2.tracePath(intersections.toHashSet, path2Matches)
|
||||
echo "Part 2. Combined steps of both wires to first intersection -> ", findFirstIntersection(path1Matches, path2Matches)
|
||||
Reference in New Issue
Block a user