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