day08.nim (2670B)
1 # Copyright (c) 2024, Natacha Porté 2 # 3 # Permission to use, copy, modify, and distribute this software for any 4 # purpose with or without fee is hereby granted, provided that the above 5 # copyright notice and this permission notice appear in all copies. 6 # 7 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15 from std/math import gcd 16 from std/sequtils import addUnique, concat, deduplicate, toSeq 17 18 # Read input file 19 20 type Point = tuple 21 x, y: int 22 23 func process_data(data: seq[string]): array[62, seq[Point]] = 24 var i: int 25 for y in 0 ..< len(data): 26 for x in 0 ..< len(data[y]): 27 case data[y][x] 28 of '.': 29 continue 30 of '0' .. '9': 31 i = ord(data[y][x]) - ord('0') 32 of 'A' .. 'Z': 33 i = ord(data[y][x]) - ord('A') + 10 34 of 'a' .. 'z': 35 i = ord(data[y][x]) - ord('a') + 36 36 else: 37 assert(false) 38 39 result[i].add((x, y)) 40 41 let 42 data = stdin.lines().toSeq() 43 nlines = len(data) 44 ncols = len(data[0]) 45 coord = process_data(data) 46 47 # Puzzle 1 48 49 func antinodes(s: seq[Point], corner: Point): seq[Point] = 50 for i in 0 ..< len(s): 51 for j in 0 ..< len(s): 52 if i == j: 53 continue 54 let n = (x: 2*s[i].x - s[j].x, y: 2*s[i].y - s[j].y) 55 if n.x >= 0 and n.y >= 0 and n.x <= corner.x and n.y <= corner.y: 56 result.addUnique(n) 57 58 func all_antinodes(d: openArray[seq[Point]], corner: Point): seq[Point] = 59 for s in d: 60 result = deduplicate(concat(result, antinodes(s, corner))) 61 62 echo "Puzzle 1: ", len(all_antinodes(coord, (ncols - 1, nlines - 1))) 63 64 # Puzzle 2 65 66 func antinodes2(s: seq[Point], corner: Point): seq[Point] = 67 for i in 0 ..< len(s): 68 for j in 0 ..< len(s): 69 if i == j: 70 continue 71 let 72 ld = (x: s[i].x - s[j].x, y: s[i].y - s[j].y) 73 g = gcd(ld.x, ld.y) 74 d = (x: ld.x div g, y: ld.y div g) 75 var p = s[i] 76 while p.x >= 0 and p.y >= 0 and p.x <= corner.x and p.y <= corner.y: 77 result.addUnique(p) 78 p.x += d.x 79 p.y += d.y 80 81 func all_antinodes2(d: openArray[seq[Point]], corner: Point): seq[Point] = 82 for s in d: 83 result = deduplicate(concat(result, antinodes2(s, corner))) 84 85 echo "Puzzle 2: ", len(all_antinodes2(coord, (ncols - 1, nlines - 1)))