|
@@ -14,74 +14,76 @@ func bounds(coords: seq[Point]): array[4, int] =
|
14
|
14
|
ys = coords.map(proc(coord: Point): int = coord[1])
|
15
|
15
|
result = [min(xs), max(xs), min(ys), max(ys)]
|
16
|
16
|
|
17
|
|
-func distance(point1: Point, point2: Point): int = abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
|
|
17
|
+func distance(point1: Point, point2: Point): int =
|
|
18
|
+ abs(point1[0] - point2[0]) + abs(point1[1] - point2[1])
|
18
|
19
|
|
19
|
20
|
func nearest(coords: seq[Point], point: Point): int =
|
20
|
|
- var
|
21
|
|
- min = -1
|
22
|
|
- best = -1
|
23
|
|
- dupe = false
|
24
|
|
- i = 0
|
|
21
|
+ let
|
|
22
|
+ distances = coords.map(proc(coord: Point): int = coord.distance(point))
|
|
23
|
+ lowest = min(distances)
|
|
24
|
+ lowest_count = distances.filter(proc (distance: int): bool = distance == lowest).len
|
|
25
|
+ if lowest_count == 1: distances.find(lowest) else: -1
|
25
|
26
|
|
26
|
|
- for coord in coords:
|
27
|
|
- let distance = coord.distance(point)
|
28
|
|
- if min == -1 or distance < min:
|
29
|
|
- min = distance
|
30
|
|
- best = i
|
31
|
|
- dupe = false
|
32
|
|
- elif min == distance:
|
33
|
|
- dupe = true
|
34
|
|
- i += 1
|
35
|
|
-
|
36
|
|
- if dupe:
|
37
|
|
- result = -1
|
38
|
|
- else:
|
39
|
|
- result = best
|
|
27
|
+func inrange(coords: seq[Point], point: Point): bool = coords.map(proc (coord: Point): int =
|
|
28
|
+ coord.distance(point)).sum < 10000
|
40
|
29
|
|
41
|
|
-func inrange(coords: seq[Point], point: Point): bool = coords.map(proc (coord: Point): int = coord.distance(point)).sum < 10000
|
|
30
|
+func part1(coords: seq[Point], extents: array[4, int]): int =
|
|
31
|
+ var
|
|
32
|
+ counts = newSeqWith(coords.len, 0)
|
|
33
|
+ excluded = newSeqWith(coords.len, false)
|
42
|
34
|
|
43
|
|
-let
|
44
|
|
- coords = read_coords(readFile("data/06.txt"))
|
45
|
|
- extents = coords.bounds
|
|
35
|
+ for x in extents[0] .. extents[1]:
|
|
36
|
+ for y in extents[2] .. extents[3]:
|
|
37
|
+ let coord = coords.nearest([x, y])
|
|
38
|
+ if coord != -1:
|
|
39
|
+ counts[coord] += 1
|
|
40
|
+
|
|
41
|
+ # If the area reaches the edge of the grid, it will continue infinitely.
|
|
42
|
+ # Mark that area as excluded.
|
|
43
|
+ if x == extents[0] or x == extents[1] or y == extents[2] or y == extents[3]:
|
|
44
|
+ excluded[coord] = true
|
46
|
45
|
|
47
|
|
-var
|
48
|
|
- counts = newSeqWith(coords.len, 0)
|
49
|
|
- excluded = newSeqWith(coords.len, false)
|
|
46
|
+ zip(counts, excluded)
|
|
47
|
+ .filter(proc(x: tuple[a: int, b: bool]): bool = not x.b)
|
|
48
|
+ .map(proc(x: tuple[a: int, b: bool]): int = x.a)
|
|
49
|
+ .max
|
|
50
|
+
|
|
51
|
+func part2(coords: seq[Point], extents: array[4, int]): int =
|
|
52
|
+ var
|
|
53
|
+ size = 0
|
|
54
|
+ found = false
|
|
55
|
+ let
|
|
56
|
+ extension = int(10000 / coords.len)
|
|
57
|
+ y_start = extents[2] - extension
|
|
58
|
+ y_finish = extents[3] + extension
|
|
59
|
+ y_range = y_finish - y_start
|
50
|
60
|
|
51
|
|
-for x in extents[0] .. extents[1]:
|
52
|
|
- for y in extents[2] .. extents[3]:
|
53
|
|
- let coord = coords.nearest([x, y])
|
54
|
|
- if coord != -1:
|
55
|
|
- counts[coord] += 1
|
56
|
|
- if x == extents[0] or x == extents[1] or y == extents[2] or y == extents[3]:
|
57
|
|
- excluded[coord] = true
|
|
61
|
+ # The region we're in is going to be contiguous so once we've found some
|
|
62
|
+ # 'safe' areas and subsequently hit a row/column with none in, we can abort
|
|
63
|
+ for x in extents[0] - extension .. extents[1] + extension:
|
|
64
|
+ var
|
|
65
|
+ min_y = int.high
|
|
66
|
+ max_y = int.high
|
58
|
67
|
|
59
|
|
-echo zip(counts, excluded)
|
60
|
|
- .filter(proc(x: tuple[a: int, b: bool]): bool = not x.b)
|
61
|
|
- .map(proc(x: tuple[a: int, b: bool]): int = x.a)
|
62
|
|
- .max
|
|
68
|
+ for y in extents[2] - extension .. extents[3] + extension:
|
|
69
|
+ if coords.inrange([x,y]):
|
|
70
|
+ if min_y == int.high:
|
|
71
|
+ min_y = y
|
|
72
|
+ max_y = y
|
|
73
|
+ elif max_y != int.high:
|
|
74
|
+ break
|
|
75
|
+
|
|
76
|
+ if min_y != int.high:
|
|
77
|
+ size += abs(max_y - min_y) + 1
|
|
78
|
+ found = true
|
|
79
|
+ elif found:
|
|
80
|
+ break
|
63
|
81
|
|
|
82
|
+ size
|
64
|
83
|
|
65
|
|
-var size = 0
|
66
|
84
|
let
|
67
|
|
- extension = int(10000 / coords.len)
|
68
|
|
- y_start = extents[2] - extension
|
69
|
|
- y_finish = extents[3] + extension
|
70
|
|
- y_range = y_finish - y_start
|
71
|
|
-
|
72
|
|
-for x in extents[0] - extension .. extents[1] + extension:
|
73
|
|
- var
|
74
|
|
- min_y = 0
|
75
|
|
- max_y = 0
|
76
|
|
- for y in extents[2] - extension .. extents[3] + extension:
|
77
|
|
- if coords.inrange([x,y]):
|
78
|
|
- min_y = y
|
79
|
|
- break
|
80
|
|
- for dy in 0 .. y_range:
|
81
|
|
- var y = y_finish - dy
|
82
|
|
- if coords.inrange([x,y]):
|
83
|
|
- max_y = y + 1
|
84
|
|
- break
|
85
|
|
- size += abs(max_y - min_y)
|
|
85
|
+ coords = read_coords(readFile("data/06.txt"))
|
|
86
|
+ extents = coords.bounds
|
86
|
87
|
|
87
|
|
-echo size
|
|
88
|
+echo part1(coords, extents)
|
|
89
|
+echo part2(coords, extents)
|