aboutsummaryrefslogtreecommitdiffstats
path: root/day14/solution.nim
blob: 7816d25703870784fc830b7cd89b9d8b57cd2e41 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import strutils
import sequtils
import sets
import strformat

type Point = tuple[row: int, col: int]

proc has(occupied: HashSet[Point], point: Point): bool =
  point in occupied

proc parsePoint(point: string): Point =
  let tokens = point.split(",")
  assert(tokens.len() == 2)
  Point((tokens[1].parseInt(), tokens[0].parseInt()))

proc parseLine(line: string): seq[Point] =
  map(line.replace("-> ").split(" "), parsePoint)

var maxRow = -1
var maxCol = -1
var minCol = 10000
proc parseFile(content: string): HashSet[Point] =
  let lines = content.strip.splitLines()
  var rockLists = map(lines, parseLine)

  for row in rockLists:
    for point in row:
      maxRow = max(maxRow, point.row)
      maxCol = max(maxCol, point.col)
      minCol = min(minCol, point.col)
  
  for rocks in rockLists:
    # a = begin, b = end
    for i, a in rocks[0..^2]:
      let b = rocks[i+1]
      # echo fmt"a = {a}, b = {b}"
      for col in min(a.col, b.col) .. max(a.col, b.col):
        let toPush = Point((a.row, col))
        result.incl(toPush)

      for row in min(a.row, b.row) .. max(a.row, b.row):
        let toPush = Point((row, a.col))
        result.incl(toPush)

proc draw(occupied: HashSet[Point]): void =
  for row in 0 .. maxRow:
    var line = ""
    for col in minCol .. maxCol:
      let current = Point((row, col))
      line &= (if occupied.has(current): '#' else: '.')

    echo line

proc below(point: Point): Point =
  Point((point.row+1, point.col))

proc rbelow(point: Point): Point =
  Point((point.row+1, point.col+1))

proc lbelow(point: Point): Point =
  Point((point.row+1, point.col-1))

proc outOfBounds(point: Point): bool =
  point.row > maxRow

var part2 = false
proc drop(occupied: var HashSet[Point], col: int): bool =
  var point = Point((0, col))
  
  if part2 and occupied.has(point):
    return false

  while true:
    let
      below = point.below()
      rbelow = point.rbelow()
      lbelow = point.lbelow()

    if point.outOfBounds():
      if part2:
        break
      return false

    if not occupied.has(below):
      point = below
      continue
    if not occupied.has(lbelow):
      point = lbelow
      continue

    if not occupied.has(rbelow):
      point = rbelow
      continue

    break
  occupied.incl(point)
  return true

proc solve(occupied: HashSet[Point]): int =
  var occupied = occupied
  while drop(occupied, 500):
    result += 1

let content = readFile("./input.txt")
let occupied = parseFile(content)

occupied.draw()
# echo fmt"{maxRow}, {minCol}-{maxCol}"
echo solve(occupied)
part2 = true
echo solve(occupied)