2022-18
Signed-off-by: AKP <tom@tdpain.net>
This commit is contained in:
parent
552a951365
commit
7846d9675f
7 changed files with 149 additions and 1 deletions
1
challenges/2022/18-boilingBoulders/README.md
Normal file
1
challenges/2022/18-boilingBoulders/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# [Day 18: Boiling Boulders](https://adventofcode.com/2022/day/18)
|
15
challenges/2022/18-boilingBoulders/benchmark.json
Normal file
15
challenges/2022/18-boilingBoulders/benchmark.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"day": 18,
|
||||
"dir": "challenges/2022/18-boilingBoulders",
|
||||
"implementations": {
|
||||
"Python": {
|
||||
"part.1.avg": 0.02251845836639404,
|
||||
"part.1.max": 0.03545045852661133,
|
||||
"part.1.min": 0.018925189971923828,
|
||||
"part.2.avg": 0.12088701725006104,
|
||||
"part.2.max": 0.1763911247253418,
|
||||
"part.2.min": 0.10623359680175781
|
||||
}
|
||||
},
|
||||
"numRuns": 200
|
||||
}
|
17
challenges/2022/18-boilingBoulders/info.json
Normal file
17
challenges/2022/18-boilingBoulders/info.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"inputFile": "input.txt",
|
||||
"testCases": {
|
||||
"one": [
|
||||
{
|
||||
"input": "2,2,2\n1,2,2\n3,2,2\n2,1,2\n2,3,2\n2,2,1\n2,2,3\n2,2,4\n2,2,6\n1,2,5\n3,2,5\n2,1,5\n2,3,5\n",
|
||||
"expected": "64"
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "2,2,2\n1,2,2\n3,2,2\n2,1,2\n2,3,2\n2,2,1\n2,2,3\n2,2,4\n2,2,6\n1,2,5\n3,2,5\n2,1,5\n2,3,5\n",
|
||||
"expected": "58"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
12
challenges/2022/18-boilingBoulders/openscad-generate.py
Normal file
12
challenges/2022/18-boilingBoulders/openscad-generate.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import sys
|
||||
|
||||
inp = sys.stdin.read()
|
||||
|
||||
print(len(inp), file=sys.stderr)
|
||||
|
||||
print("union(){")
|
||||
|
||||
for line in inp.strip().splitlines():
|
||||
print(f"\ttranslate([{line}]) cube(1);")
|
||||
|
||||
print("};")
|
102
challenges/2022/18-boilingBoulders/py/__init__.py
Normal file
102
challenges/2022/18-boilingBoulders/py/__init__.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
from typing import *
|
||||
from aocpy import BaseChallenge, foldl
|
||||
|
||||
Coordinate = Tuple[int, int, int]
|
||||
CubeMap = Dict[Coordinate, bool]
|
||||
|
||||
|
||||
ADJACENT_LOCATIONS = (
|
||||
(1, 0, 0), (-1, 0, 0),
|
||||
(0, 1, 0), (0, -1, 0),
|
||||
(0, 0, 1), (0, 0, -1),
|
||||
)
|
||||
|
||||
|
||||
def sum_coordinates(ca: Coordinate, cb: Coordinate) -> Coordinate:
|
||||
return tuple(a + b for (a, b) in zip(ca, cb))
|
||||
|
||||
|
||||
def parse(instr: str) -> CubeMap:
|
||||
res: CubeMap = {}
|
||||
for line in instr.strip().splitlines():
|
||||
res[tuple(map(int, line.split(",")))] = False
|
||||
|
||||
for coord in res:
|
||||
is_completely_surrounded = True
|
||||
for modifier in ADJACENT_LOCATIONS:
|
||||
combined = sum_coordinates(coord, modifier)
|
||||
is_completely_surrounded = is_completely_surrounded and combined in res
|
||||
res[coord] = is_completely_surrounded
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def count_exposed_faces(targets: Iterable[Coordinate], all_cubes: CubeMap) -> int:
|
||||
n = 0
|
||||
for coord in targets:
|
||||
for modifier in ADJACENT_LOCATIONS:
|
||||
if sum_coordinates(coord, modifier) not in all_cubes:
|
||||
n += 1
|
||||
return n
|
||||
|
||||
|
||||
def min_max(x: Iterable[int]) -> Tuple[int, int]:
|
||||
mini, maxi = None, 0
|
||||
|
||||
for item in x:
|
||||
if item > maxi:
|
||||
maxi = item
|
||||
if mini is None or item < mini:
|
||||
mini = item
|
||||
|
||||
if mini is None:
|
||||
raise ValueError("empty set")
|
||||
|
||||
return mini, maxi
|
||||
|
||||
|
||||
def is_coord_in_range(c: Coordinate, min_c: Coordinate, max_c: Coordinate) -> bool:
|
||||
return foldl(
|
||||
lambda x, y: x and y,
|
||||
((a <= b <= c) for (a, b, c) in zip(min_c, c, max_c)),
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
class Challenge(BaseChallenge):
|
||||
|
||||
@staticmethod
|
||||
def one(instr: str) -> int:
|
||||
inp = parse(instr)
|
||||
return count_exposed_faces([p for p in inp if not inp[p]], inp)
|
||||
|
||||
@staticmethod
|
||||
def two(instr: str) -> int:
|
||||
inp = parse(instr)
|
||||
|
||||
min_x, max_x = min_max(c[0] for c in inp)
|
||||
min_y, max_y = min_max(c[1] for c in inp)
|
||||
min_z, max_z = min_max(c[2] for c in inp)
|
||||
min_coord = (min_x - 1, min_y - 1, min_z - 1)
|
||||
max_coord = (max_x + 1, max_y + 1, max_z + 1)
|
||||
|
||||
visited: Dict[Coordinate, None] = {}
|
||||
touchable_faces = 0
|
||||
scan_points = [min_coord]
|
||||
while len(scan_points) != 0:
|
||||
current = scan_points.pop()
|
||||
if current in visited:
|
||||
continue
|
||||
visited[current] = None
|
||||
|
||||
for modifier in ADJACENT_LOCATIONS:
|
||||
combined = sum_coordinates(current, modifier)
|
||||
if (not is_coord_in_range(combined, min_coord, max_coord)):
|
||||
continue
|
||||
|
||||
if combined in inp:
|
||||
touchable_faces += 1
|
||||
else:
|
||||
scan_points.append(combined)
|
||||
|
||||
return touchable_faces
|
|
@ -32,4 +32,5 @@ The red dotted line denotes 15 seconds.
|
|||
| 14 - Regolith Reservoir | ★ ★ | [Python](14-regolithReservoir/py/__init__.py) | Simulating falling sand |
|
||||
| 15 - Beacon Exclusion Zone | ★ ★ | [Python](15-beaconExclusionZone/py/__init__.py) | Searching through a 4000000^2 size grid for a literal single empty spot |
|
||||
| 16 - Proboscidea Volcanium | ★ ★ | [Python](16-proboscideaVolcanium/py/__init__.py) | Nasty combinatorics |
|
||||
| 17 - Pyroclastic Flow | ★ ★ | [Python](17-pyroclasticFlow/py/__init__.py) | Detecting cycles in a large amount of knock-off Tetris. |
|
||||
| 17 - Pyroclastic Flow | ★ ★ | [Python](17-pyroclasticFlow/py/__init__.py) | Detecting cycles in a large amount of knock-off Tetris. |
|
||||
| 18 - Boiling Boulders | ★ ★ | [Python](18-boilingBoulders/py/__init__.py) | Finding the surface area of a shape specified by a list of unit cubes. |
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 60 KiB |
Loading…
Add table
Add a link
Reference in a new issue