My solutions to 2018's advent of code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

day06.nim 3.0KB

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