summaryrefslogtreecommitdiffstats
path: root/d11.nim
blob: 811ef9f956e589d750ba40013130d5509966fe41 (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
72
73
74
import std/os, std/sugar, std/sequtils, std/deques

type
   OctoState = Natural
   Map = tuple[map: seq[OctoState], width: int, height: int]

proc read_map(filename: string): Map =
   let f = open(filename)
   defer: f.close()
   result.map = collect:
      for line in f.lines():
         result.width = line.len
         result.height += 1
         for c in line:
            (c.ord - '0'.ord).OctoState

proc print_map(map: Map) =
   for y in countup(0, map.height - 1):
      for x in countup(0, map.width - 1):
         stdout.write(('0'.ord + map.map[x + map.width * y]).char)
      stdout.write('\n')

iterator neighbours(map: Map, i: int): int =
   let
      x = i mod map.width
      y = i div map.width
   for dy in countup(-1, 1):
      for dx in countup(-1, 1):
         if dy == 0 and dx == 0: continue
         let
            x = x + dx
            y = y + dy
         if x < 0 or x >= map.width: continue
         if y < 0 or y >= map.height: continue
         yield x + map.width * y

proc solve(map: Map): tuple[part1, part2: int] =
   var
      current = map.map
      flashed = new_seq[bool](current.len)
      pending = init_deque[int](current.len)
      flashes = 0
   for step in 1..1000:
      flashed.apply(proc(_: bool): bool = false)
      for i, s in current.mpairs:
         inc s
         if s > 9: pending.add_first(i)
      var sum = 0
      while pending.len() > 0:
         let i = pending.pop_last()
         if flashed[i]: continue
         flashed[i] = true
         current[i] = 0
         inc sum
         for i in neighbours(map, i):
            if flashed[i]: continue
            inc current[i]
            if current[i] > 9:
               pending.add_first(i)
      flashes += sum
      if step == 100:
         result.part1 = flashes
      if sum == map.width * map.height:
         result.part2 = step
         break

when is_main_module:
   var filename: string = "11.in"
   if param_count() == 1:
      filename = param_str(1)
   let map = read_map(filename)
   let (part1, part2) = solve(map)
   echo part1
   echo part2