summaryrefslogtreecommitdiffstats
path: root/d11.nim
blob: 73ddfe305ac0d4ecb5e6fd07b33d8e959efed2c4 (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
75
76
import std/os, std/sugar, std/strutils, std/sequtils

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')

proc solve(map: Map): tuple[part1, part2: int] =
   var
      current = map.map
      flashed = new_seq[bool](current.len)
      flash = new_seq[bool](current.len)
      flashes = 0
   for step in 1..1000:
      #print_map((current, map.width, map.height))
      #echo ""
      flashed.apply(proc(_: bool): bool = false)
      current.apply(proc(s: OctoState): OctoState = s + 1)
      while true:
         var any = false
         flash.apply(proc(_: bool): bool = false)
         for i, s in current:
            if flashed[i] or s <= 9: continue
            flashed[i] = true
            flash[i] = true
            any = true
         if not any: break
         for i, s in flash:
            if not s: continue
            let
               x = i mod map.width
               y = i div map.width
            for dy in countup(-1, 1):
               for dx in countup(-1, 1):
                  if dx == 0 and dy == 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
                  inc current[x + map.width * y]
      var sum = 0
      for i, s in flashed:
         if not s: continue
         current[i] = 0
         inc sum
      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