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
|
import sys
import numpy as np
import functools
sys.setrecursionlimit(100000)
# Part 1
# cubes←⍎¨⊃⎕NGET'input'1
cubes = [eval(f"({line})") for line in open("input").readlines()]
# movements←{⍵,-⍵}↓(3 3⍴4↑1)
movements = (lambda w: np.vstack([w, -w]))(np.identity(3, dtype=int))
# sides←,cubes∘.+movements
sides = [tuple(c + m) for c in cubes for m in movements]
# ≢sides~cubes
print(sum(1 for side in sides if side not in cubes))
# Part 2
# mins←(↑⌊/cubes)-1 1 1
mins = tuple(min(c) - 1 for c in zip(*cubes))
# maxs←(↑⌈/cubes)+1 1 1
maxs = tuple(max(c) + 1 for c in zip(*cubes))
# in_boundary←{0≡+/((⍵<mins),(⍵>maxs))}
in_boundary = lambda c: 0 == functools.reduce(
lambda a, b: a + b,
(int(c[i] < mins[i] or c[i] > maxs[i]) for i in range(3)),
0,
)
# count←0
count = 0
def rec(left, right):
global count
# 0=≢⍵:count
if not right:
return count
# head←1↑⍵ ⋄ tail←1↓⍵
head, tail = right[0], right[1:]
# neighbors←movements+¨head
neighbors = [tuple(head + m) for m in movements]
# next←{(in_boundary¨⍵)/⍵}neighbors
next = set(filter(in_boundary, neighbors))
# count⊢←count+(+/{(↓⍵)∊cubes}¨neighbors)
count += sum((n in cubes) for n in neighbors)
# (⍺,head)∇((tail∪next)~⍺)
return rec(left | set([head]), list((set(tail) | next) - left))
# cubes{...}↓maxs
print(rec(set(cubes), [maxs]))
|