Browse Source

Tidy up and increase performance a bit

master
Chris Smith 5 years ago
parent
commit
56f04d82c2
2 changed files with 67 additions and 69 deletions
  1. 6
    10
      README.md
  2. 61
    59
      day06.nim

+ 6
- 10
README.md View File

@@ -1,19 +1,15 @@
1 1
 # Advent of Code 2018
2 2
 
3 3
 This repository contains my solution to 2018's [Advent of Code](https://adventofcode.com/2018) puzzles. The solutions
4
-are all written in Python 3; one or two may require the [NumPy](http://www.numpy.org/) package, but the rest should
5
-work out-of-the-box.
4
+are a mixture of Python 3 and Nim.
6 5
 
7
-If you have docker installed, simply execute `run.sh` to build a docker image and execute the latest solution
8
-using pypy3. You can specify other days by passing the script names as arguments (e.g. `run.sh 03.py`).
9
-
10
-I tend to focus on short, functional solutions where possible, so they may be a bit hard to read. Some solutions are
11
-commented to some degree to help with that.
6
+The easiest way to run these is using docker -- simply execute `run.sh <day>` to build a docker image and execute the
7
+specific day.
12 8
 
13 9
 I have separate repositories for solutions from previous years:
14
-  - [2017](https://g.c5h.io/archive/aoc-2017)
15
-  - [2016](https://g.c5h.io/archive/aoc-2016)
16
-  - [2015](https://g.c5h.io/archive/aoc-2015)
10
+  - [2017](https://g.c5h.io/archive/aoc-2017) (All python)
11
+  - [2016](https://g.c5h.io/archive/aoc-2016) (All python)
12
+  - [2015](https://g.c5h.io/archive/aoc-2015) (All python)
17 13
 
18 14
 ---
19 15
 

+ 61
- 59
day06.nim View File

@@ -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)