summaryrefslogtreecommitdiffstats
path: root/d5.nim
blob: 5c5e94e25f4b32931271ccf2b6fccdb50e04503a (plain)
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
import std/sets, std/strutils, std/sugar, std/sequtils, std/os

type
   Num = range[0..9999999]
   Pos = tuple[x, y: Num]
   Vent = tuple[a, b: Pos]
   VentType = enum vt_horz vt_vert vt_diag

proc parse_pos(pos: string): Pos =
   let xy = pos.split(',', maxsplit=1).map(parse_int)
   return (xy[0].Num, xy[1].Num)

proc read_vents(filename: string): seq[Vent] =
   let f = open(filename)
   defer: f.close()
   result = collect:
      for line in f.lines():
         let ab = line.split(" -> ", maxsplit=1).map(parse_pos)
         (ab[0], ab[1])

func classify(v: Vent): VentType =
   if v.a.x == v.b.x:
      return vt_vert
   if v.a.y == v.b.y:
      return vt_horz
   return vt_diag

iterator intersect(u, v: Vent): Pos =
   var
      uc = classify(u)
      vc = classify(v)
   if uc == vc:
      for x in max(u.a.x, v.a.x) .. min(u.b.x, v.b.x):
         for y in max(u.a.y, v.a.y) .. min(u.b.y, v.b.y):
            yield (x, y)
   else:
      var
         u = u
         v = v
      if uc == vt_vert and vc == vt_horz:
         (u, v) = (v, u)
      let
         x = v.a.x
         y = u.a.y
      if x >= u.a.x and x <= u.b.x and y >= v.a.y and y <= v.b.y:
         yield (x, y)

func normalise(v: Vent): Vent =
   result = v
   if ((classify(v) != vt_vert and v.b.x < v.a.x) or
       (classify(v) == vt_vert and v.b.y < v.a.y)):
      result = (v.b, v.a)

proc part1(vents: seq[Vent]): int =
   var intersections: HashSet[Pos]
   for i, a in vents:
      if classify(a) == vt_diag: continue
      let a = normalise(a)
      for b in vents[i + 1 .. ^1]:
         if classify(b) == vt_diag: continue
         let b = normalise(b)
         for p in intersect(a, b):
            intersections.incl(p)
   return len(intersections)

when is_main_module:
   var filename: string = "5.in"
   if param_count() == 1:
      filename = param_str(1)
   let vents = read_vents(filename)
   echo part1(vents)