diff options
| author | An0nSaiko <porfeas12@gmail.com> | 2022-12-15 17:49:09 +0200 |
|---|---|---|
| committer | An0nSaiko <porfeas12@gmail.com> | 2022-12-15 17:49:09 +0200 |
| commit | f18f1e47ff95e036c119734b7b792042cbb9246d (patch) | |
| tree | fee46c655506c7f6e7a573469380c2a6d79a2741 | |
| parent | Day 14 (diff) | |
| download | aoc22-f18f1e47ff95e036c119734b7b792042cbb9246d.tar.gz aoc22-f18f1e47ff95e036c119734b7b792042cbb9246d.zip | |
Day 15
| -rw-r--r-- | day15/example.txt | 14 | ||||
| -rw-r--r-- | day15/input.txt | 32 | ||||
| -rw-r--r-- | day15/solution.nim | 117 |
3 files changed, 163 insertions, 0 deletions
diff --git a/day15/example.txt b/day15/example.txt new file mode 100644 index 0000000..a612424 --- /dev/null +++ b/day15/example.txt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | Sensor at x=2, y=18: closest beacon is at x=-2, y=15 | ||
| 2 | Sensor at x=9, y=16: closest beacon is at x=10, y=16 | ||
| 3 | Sensor at x=13, y=2: closest beacon is at x=15, y=3 | ||
| 4 | Sensor at x=12, y=14: closest beacon is at x=10, y=16 | ||
| 5 | Sensor at x=10, y=20: closest beacon is at x=10, y=16 | ||
| 6 | Sensor at x=14, y=17: closest beacon is at x=10, y=16 | ||
| 7 | Sensor at x=8, y=7: closest beacon is at x=2, y=10 | ||
| 8 | Sensor at x=2, y=0: closest beacon is at x=2, y=10 | ||
| 9 | Sensor at x=0, y=11: closest beacon is at x=2, y=10 | ||
| 10 | Sensor at x=20, y=14: closest beacon is at x=25, y=17 | ||
| 11 | Sensor at x=17, y=20: closest beacon is at x=21, y=22 | ||
| 12 | Sensor at x=16, y=7: closest beacon is at x=15, y=3 | ||
| 13 | Sensor at x=14, y=3: closest beacon is at x=15, y=3 | ||
| 14 | Sensor at x=20, y=1: closest beacon is at x=15, y=3 | ||
diff --git a/day15/input.txt b/day15/input.txt new file mode 100644 index 0000000..ec728e8 --- /dev/null +++ b/day15/input.txt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | Sensor at x=3428425, y=2345067: closest beacon is at x=3431988, y=2379841 | ||
| 2 | Sensor at x=928237, y=25774: closest beacon is at x=1212315, y=-161555 | ||
| 3 | Sensor at x=2061220, y=2396791: closest beacon is at x=2038311, y=2495160 | ||
| 4 | Sensor at x=1830400, y=2994568: closest beacon is at x=1910058, y=3117415 | ||
| 5 | Sensor at x=2485733, y=2625804: closest beacon is at x=2038311, y=2495160 | ||
| 6 | Sensor at x=1855873, y=3971916: closest beacon is at x=1910058, y=3117415 | ||
| 7 | Sensor at x=119582, y=3929652: closest beacon is at x=311197, y=4221202 | ||
| 8 | Sensor at x=1069031, y=3509672: closest beacon is at x=1910058, y=3117415 | ||
| 9 | Sensor at x=3368023, y=2213635: closest beacon is at x=3431988, y=2379841 | ||
| 10 | Sensor at x=3713877, y=2460862: closest beacon is at x=3431988, y=2379841 | ||
| 11 | Sensor at x=3593503, y=2174008: closest beacon is at x=3507689, y=2000000 | ||
| 12 | Sensor at x=501760, y=93436: closest beacon is at x=1212315, y=-161555 | ||
| 13 | Sensor at x=3712703, y=214999: closest beacon is at x=3507689, y=2000000 | ||
| 14 | Sensor at x=1594824, y=2790273: closest beacon is at x=1910058, y=3117415 | ||
| 15 | Sensor at x=2539549, y=3190814: closest beacon is at x=1910058, y=3117415 | ||
| 16 | Sensor at x=3522790, y=2671548: closest beacon is at x=3431988, y=2379841 | ||
| 17 | Sensor at x=1001452, y=1327490: closest beacon is at x=1212315, y=-161555 | ||
| 18 | Sensor at x=629209, y=2451628: closest beacon is at x=-416149, y=2226089 | ||
| 19 | Sensor at x=2636827, y=1146266: closest beacon is at x=3507689, y=2000000 | ||
| 20 | Sensor at x=3909, y=625124: closest beacon is at x=1212315, y=-161555 | ||
| 21 | Sensor at x=3950231, y=3688780: closest beacon is at x=3888160, y=3226725 | ||
| 22 | Sensor at x=3449978, y=2328058: closest beacon is at x=3431988, y=2379841 | ||
| 23 | Sensor at x=3974214, y=2582925: closest beacon is at x=3888160, y=3226725 | ||
| 24 | Sensor at x=82663, y=3225533: closest beacon is at x=311197, y=4221202 | ||
| 25 | Sensor at x=1958305, y=2292045: closest beacon is at x=2038311, y=2495160 | ||
| 26 | Sensor at x=3465738, y=2123353: closest beacon is at x=3507689, y=2000000 | ||
| 27 | Sensor at x=2940758, y=3884337: closest beacon is at x=2746166, y=4800483 | ||
| 28 | Sensor at x=3429173, y=2275591: closest beacon is at x=3431988, y=2379841 | ||
| 29 | Sensor at x=1527349, y=38565: closest beacon is at x=1212315, y=-161555 | ||
| 30 | Sensor at x=3049925, y=2498038: closest beacon is at x=3431988, y=2379841 | ||
| 31 | Sensor at x=1593202, y=3335178: closest beacon is at x=1910058, y=3117415 | ||
| 32 | Sensor at x=3175520, y=3230234: closest beacon is at x=3888160, y=3226725 | ||
diff --git a/day15/solution.nim b/day15/solution.nim new file mode 100644 index 0000000..58e2aab --- /dev/null +++ b/day15/solution.nim | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | import strutils | ||
| 2 | import sequtils | ||
| 3 | import re | ||
| 4 | import sugar | ||
| 5 | import algorithm | ||
| 6 | import sets | ||
| 7 | |||
| 8 | type | ||
| 9 | Point = tuple | ||
| 10 | x: int | ||
| 11 | y: int | ||
| 12 | |||
| 13 | Range = tuple | ||
| 14 | b: int | ||
| 15 | l: int | ||
| 16 | |||
| 17 | Entry = tuple | ||
| 18 | sensor: Point | ||
| 19 | beacon: Point | ||
| 20 | distance: int | ||
| 21 | |||
| 22 | proc distance(A, B: Point): int = | ||
| 23 | result = abs(A.x - B.x) + abs(A.y - B.y) | ||
| 24 | |||
| 25 | proc disjoinWith(A, B: Range): bool = | ||
| 26 | return A.b + A.l < B.b | ||
| 27 | |||
| 28 | proc rangeContains(r: Range, y: int, p: Point): bool = | ||
| 29 | p.y == y and r.b <= p.x and p.x <= r.b + r.l - 1 | ||
| 30 | |||
| 31 | proc unite(A, B: Range): Range = | ||
| 32 | assert(A.b <= B.b) | ||
| 33 | assert(not A.disjoinWith(B)) | ||
| 34 | result = (A.b, max(A.l, B.b - A.b + B.l)) | ||
| 35 | |||
| 36 | proc rangeComparator(A, B: Range): int = | ||
| 37 | if A.b < B.b or (A.b == B.b and A.l <= B.l): | ||
| 38 | return -1 | ||
| 39 | else: | ||
| 40 | return 1 | ||
| 41 | |||
| 42 | proc parsePoint(strPoint: string): Point = | ||
| 43 | let tokens = strPoint.split(",") | ||
| 44 | Point((tokens[0].parseInt(), tokens[1].parseInt())) | ||
| 45 | |||
| 46 | proc parseEntry(strEntry: string): Entry = | ||
| 47 | let tokens = strEntry.split(":") | ||
| 48 | let points = @[tokens[0].parsePoint(), tokens[1].parsePoint()] | ||
| 49 | Entry((points[0], points[1], distance(points[0], points[1]))) | ||
| 50 | |||
| 51 | proc parseFile(content: string): seq[Entry] = | ||
| 52 | let lines = content.strip().splitLines() | ||
| 53 | |||
| 54 | let strEntries = map( | ||
| 55 | lines, | ||
| 56 | (line) => line.replace(re"[^0-9\-,:]") | ||
| 57 | ) | ||
| 58 | |||
| 59 | result = map( | ||
| 60 | strEntries, | ||
| 61 | parseEntry | ||
| 62 | ) | ||
| 63 | |||
| 64 | proc emptyRanges(entries: seq[Entry], criticalLine: int): seq[Range] = | ||
| 65 | var emptyRanges: seq[Range] | ||
| 66 | for entry in entries: | ||
| 67 | let | ||
| 68 | distFromLine = abs(entry.sensor.y - criticalLine) | ||
| 69 | rangeFromMid = entry.distance - distFromLine | ||
| 70 | b = entry.sensor.x - rangeFromMid | ||
| 71 | e = entry.sensor.x + rangeFromMid | ||
| 72 | l = e - b + 1 | ||
| 73 | if l > 0: | ||
| 74 | emptyRanges.add((b, l)) | ||
| 75 | |||
| 76 | emptyRanges.sort(rangeComparator) | ||
| 77 | var | ||
| 78 | curr = emptyRanges[0] | ||
| 79 | lastPushed = true | ||
| 80 | |||
| 81 | for other in emptyRanges[1..^1]: | ||
| 82 | lastPushed = false | ||
| 83 | if curr.disjoinWith(other): | ||
| 84 | result.add(curr) | ||
| 85 | lastPushed = true | ||
| 86 | curr = other | ||
| 87 | else: | ||
| 88 | curr = curr.unite(other) | ||
| 89 | |||
| 90 | if not lastPushed: | ||
| 91 | result.add(curr) | ||
| 92 | |||
| 93 | proc part1(entries: seq[Entry], criticalLine = 2_000_000): int = | ||
| 94 | # List of all beacons | ||
| 95 | var beacons: HashSet[Point] | ||
| 96 | for entry in entries: | ||
| 97 | beacons.incl(entry.beacon) | ||
| 98 | |||
| 99 | let empty = emptyRanges(entries, criticalLine) | ||
| 100 | for r in empty: | ||
| 101 | result += r.l | ||
| 102 | for b in beacons: | ||
| 103 | if r.rangeContains(criticalLine, b): | ||
| 104 | result -= 1 | ||
| 105 | |||
| 106 | proc part2(entries: seq[Entry], criticalLength = 4_000_000): int = | ||
| 107 | for y in 0 .. criticalLength: | ||
| 108 | let empty = emptyRanges(entries, y) | ||
| 109 | if empty.len() == 2: | ||
| 110 | let x = empty[0].b + empty[0].l | ||
| 111 | return x * 4_000_000 + y | ||
| 112 | |||
| 113 | let content = readFile("./input.txt") | ||
| 114 | let entries = parseFile(content) | ||
| 115 | |||
| 116 | echo part1(entries) | ||
| 117 | echo part2(entries) | ||
