aboutsummaryrefslogtreecommitdiffstats
path: root/day18/solution.nim
blob: 0ef81fb4c32c194592dc277e5f87e058695dfec6 (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
import strutils
import sequtils
import sugar
import sets

type Cube = tuple
  x, y, z: int

proc parseLine(line: string): Cube =
  let tokens = map(line.split(","), (e) => e.parseInt())
  (tokens[0], tokens[1], tokens[2])

proc parseFile(content: string): seq[Cube] =
  let lines = content.strip().splitLines()
  result = map(lines, parseLine)

proc nextTo(A, B: Cube): bool =
  let
    dx = abs(A.x - B.x)
    dy = abs(A.y - B.y)
    dz = abs(A.z - B.z)

  dx + dy + dz <= 1 and dx <= 1 and dy <= 1 and dz <= 1

proc part1(cubes: seq[Cube]): int =
  result = 6 * cubes.len()
  for i, cube in cubes[0 .. ^2]:
    for other in cubes[i+1 .. ^1]:
      if cube.nextTo(other):
        result -= 2

var
  solid: HashSet[Cube]
  visited: HashSet[Cube]
  maxn = 0
  minn = -1

proc blocksAround(cube: Cube): int =
  for x in [cube.x-1, cube.x+1]:
    if (x, cube.y, cube.z) in solid:
      result += 1

  for y in [cube.y-1, cube.y+1]:
    if (cube.x, y, cube.z) in solid:
      result += 1

  for z in [cube.z-1, cube.z+1]:
    if (cube.x, cube.y, z) in solid:
      result += 1

proc dfs(curr: Cube): int =
  let maxp = max([curr.x, curr.y, curr.z])
  let minp = min([curr.x, curr.y, curr.z])
  if minp < minn or maxp >= maxn or visited.containsOrIncl(curr):
    return 0

  # if is air block
  if curr notin solid:
    result = blocksAround(curr) +
      dfs((curr.x+1, curr.y, curr.z)) +
      dfs((curr.x-1, curr.y, curr.z)) +
      dfs((curr.x, curr.y+1, curr.z)) +
      dfs((curr.x, curr.y-1, curr.z)) +
      dfs((curr.x, curr.y, curr.z+1)) +
      dfs((curr.x, curr.y, curr.z-1))


proc part2(cubes: seq[Cube]): int =
  # echo cubes
  for cube in cubes:
    maxn = max([cube.x, cube.y, cube.z])
  maxn += 6

  for cube in cubes:
    solid.incl(cube)

  result = dfs((0,0,0))

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

echo part1(input)
echo part2(input)