diff options
Diffstat (limited to 'day18/solution.nim')
| -rw-r--r-- | day18/solution.nim | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/day18/solution.nim b/day18/solution.nim new file mode 100644 index 0000000..0ef81fb --- /dev/null +++ b/day18/solution.nim | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | import strutils | ||
| 2 | import sequtils | ||
| 3 | import sugar | ||
| 4 | import sets | ||
| 5 | |||
| 6 | type Cube = tuple | ||
| 7 | x, y, z: int | ||
| 8 | |||
| 9 | proc parseLine(line: string): Cube = | ||
| 10 | let tokens = map(line.split(","), (e) => e.parseInt()) | ||
| 11 | (tokens[0], tokens[1], tokens[2]) | ||
| 12 | |||
| 13 | proc parseFile(content: string): seq[Cube] = | ||
| 14 | let lines = content.strip().splitLines() | ||
| 15 | result = map(lines, parseLine) | ||
| 16 | |||
| 17 | proc nextTo(A, B: Cube): bool = | ||
| 18 | let | ||
| 19 | dx = abs(A.x - B.x) | ||
| 20 | dy = abs(A.y - B.y) | ||
| 21 | dz = abs(A.z - B.z) | ||
| 22 | |||
| 23 | dx + dy + dz <= 1 and dx <= 1 and dy <= 1 and dz <= 1 | ||
| 24 | |||
| 25 | proc part1(cubes: seq[Cube]): int = | ||
| 26 | result = 6 * cubes.len() | ||
| 27 | for i, cube in cubes[0 .. ^2]: | ||
| 28 | for other in cubes[i+1 .. ^1]: | ||
| 29 | if cube.nextTo(other): | ||
| 30 | result -= 2 | ||
| 31 | |||
| 32 | var | ||
| 33 | solid: HashSet[Cube] | ||
| 34 | visited: HashSet[Cube] | ||
| 35 | maxn = 0 | ||
| 36 | minn = -1 | ||
| 37 | |||
| 38 | proc blocksAround(cube: Cube): int = | ||
| 39 | for x in [cube.x-1, cube.x+1]: | ||
| 40 | if (x, cube.y, cube.z) in solid: | ||
| 41 | result += 1 | ||
| 42 | |||
| 43 | for y in [cube.y-1, cube.y+1]: | ||
| 44 | if (cube.x, y, cube.z) in solid: | ||
| 45 | result += 1 | ||
| 46 | |||
| 47 | for z in [cube.z-1, cube.z+1]: | ||
| 48 | if (cube.x, cube.y, z) in solid: | ||
| 49 | result += 1 | ||
| 50 | |||
| 51 | proc dfs(curr: Cube): int = | ||
| 52 | let maxp = max([curr.x, curr.y, curr.z]) | ||
| 53 | let minp = min([curr.x, curr.y, curr.z]) | ||
| 54 | if minp < minn or maxp >= maxn or visited.containsOrIncl(curr): | ||
| 55 | return 0 | ||
| 56 | |||
| 57 | # if is air block | ||
| 58 | if curr notin solid: | ||
| 59 | result = blocksAround(curr) + | ||
| 60 | dfs((curr.x+1, curr.y, curr.z)) + | ||
| 61 | dfs((curr.x-1, curr.y, curr.z)) + | ||
| 62 | dfs((curr.x, curr.y+1, curr.z)) + | ||
| 63 | dfs((curr.x, curr.y-1, curr.z)) + | ||
| 64 | dfs((curr.x, curr.y, curr.z+1)) + | ||
| 65 | dfs((curr.x, curr.y, curr.z-1)) | ||
| 66 | |||
| 67 | |||
| 68 | proc part2(cubes: seq[Cube]): int = | ||
| 69 | # echo cubes | ||
| 70 | for cube in cubes: | ||
| 71 | maxn = max([cube.x, cube.y, cube.z]) | ||
| 72 | maxn += 6 | ||
| 73 | |||
| 74 | for cube in cubes: | ||
| 75 | solid.incl(cube) | ||
| 76 | |||
| 77 | result = dfs((0,0,0)) | ||
| 78 | |||
| 79 | let content = readFile("./input.txt") | ||
| 80 | let input = parseFile(content) | ||
| 81 | |||
| 82 | echo part1(input) | ||
| 83 | echo part2(input) | ||
