2023.22
This commit is contained in:
parent
40d9e5c684
commit
da18f184d5
7 changed files with 165 additions and 0 deletions
1
challenges/2023/22-sandSlabs/README.md
Normal file
1
challenges/2023/22-sandSlabs/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# [Day 22: Sand Slabs](https://adventofcode.com/2023/day/22)
|
146
challenges/2023/22-sandSlabs/main.py
Normal file
146
challenges/2023/22-sandSlabs/main.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
import sys
|
||||
import gridutil.coord as cu
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
Brick = tuple[cu.Coordinate3, cu.Coordinate3]
|
||||
|
||||
|
||||
def parse(instr: str) -> set[Brick]:
|
||||
# (sorry)
|
||||
return set(
|
||||
sorted(
|
||||
[
|
||||
tuple(
|
||||
sorted(
|
||||
map(
|
||||
lambda x: cu.Coordinate3(*map(int, x.split(","))),
|
||||
line.split("~"),
|
||||
)
|
||||
)
|
||||
)
|
||||
for line in instr.splitlines()
|
||||
],
|
||||
key=lambda x: x[0].z,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def are_bricks_overlapping(a: Brick, b: Brick) -> bool:
|
||||
x_overlaps = a[0].x <= b[1].x and b[0].x <= a[1].x
|
||||
y_overlaps = a[0].y <= b[1].y and b[0].y <= a[1].y
|
||||
return x_overlaps and y_overlaps
|
||||
|
||||
|
||||
def lower_bricks(
|
||||
bricks: set[Brick], start_at: int = 2, return_early: bool = False
|
||||
) -> int:
|
||||
max_z = max([x[1].z for x in bricks]) + 1
|
||||
n = 0
|
||||
for level in range(start_at, max_z if not return_early else start_at + 1):
|
||||
present_below = []
|
||||
on_this_level = []
|
||||
|
||||
for brick in bricks:
|
||||
if brick[1].z == level - 1:
|
||||
present_below.append(brick)
|
||||
elif brick[0].z == level:
|
||||
on_this_level.append(brick)
|
||||
|
||||
for brick in on_this_level:
|
||||
overlaps = False
|
||||
for lower_brick in present_below:
|
||||
if are_bricks_overlapping(brick, lower_brick):
|
||||
overlaps = True
|
||||
break
|
||||
|
||||
if not overlaps:
|
||||
n += 1
|
||||
# This is what lowering a brick looks like
|
||||
bricks.remove(brick)
|
||||
bricks.add(
|
||||
(
|
||||
cu.Coordinate3(brick[0].x, brick[0].y, brick[0].z - 1),
|
||||
cu.Coordinate3(brick[1].x, brick[1].y, brick[1].z - 1),
|
||||
)
|
||||
)
|
||||
|
||||
return n
|
||||
|
||||
|
||||
def collapse_tower(bricks: set[Brick]):
|
||||
changed = 1
|
||||
while changed != 0:
|
||||
changed = lower_bricks(bricks)
|
||||
|
||||
|
||||
def generate_openscad(bricks: set[Brick]) -> str:
|
||||
"""
|
||||
This was for debugging
|
||||
"""
|
||||
lines = []
|
||||
for brick in bricks:
|
||||
lines.append(
|
||||
"translate(["
|
||||
+ (", ".join(map(str, brick[0])))
|
||||
+ "]) { cube(["
|
||||
+ (
|
||||
", ".join(
|
||||
map(str, map(lambda x: 1 + brick[1][x] - brick[0][x], range(3)))
|
||||
)
|
||||
)
|
||||
+ "], center=false); };"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def one(instr: str):
|
||||
bricks = parse(instr)
|
||||
|
||||
_debug("Building initial state", end="\r")
|
||||
|
||||
collapse_tower(bricks)
|
||||
|
||||
acc = 0
|
||||
for brick in tqdm(bricks, desc="Testing individual bricks", file=sys.stderr, leave=False):
|
||||
bc = bricks.copy()
|
||||
bc.remove(brick)
|
||||
v = lower_bricks(bc, start_at=brick[1].z + 1, return_early=True)
|
||||
if v == 0:
|
||||
acc += 1
|
||||
|
||||
return acc
|
||||
|
||||
|
||||
def two(instr: str):
|
||||
bricks = parse(instr)
|
||||
|
||||
_debug("Building initial state", end="\r")
|
||||
|
||||
collapse_tower(bricks)
|
||||
|
||||
acc = 0
|
||||
for brick in tqdm(bricks, desc="Testing individual bricks", file=sys.stderr, leave=False):
|
||||
bc = bricks.copy()
|
||||
bc.remove(brick)
|
||||
v = lower_bricks(bc, start_at=brick[1].z + 1)
|
||||
if v != 0:
|
||||
acc += v
|
||||
|
||||
return acc
|
||||
|
||||
|
||||
def _debug(*args, **kwargs):
|
||||
kwargs["file"] = sys.stderr
|
||||
print(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]:
|
||||
print("Missing day argument", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
inp = sys.stdin.read().strip()
|
||||
if sys.argv[1] == "1":
|
||||
print(one(inp))
|
||||
else:
|
||||
print(two(inp))
|
14
challenges/2023/22-sandSlabs/tests.json
Normal file
14
challenges/2023/22-sandSlabs/tests.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"1": [
|
||||
{
|
||||
"is": "5",
|
||||
"input": "1,0,1~1,2,1\n0,0,2~2,0,2\n0,2,3~2,2,3\n0,0,4~0,2,4\n2,0,5~2,2,5\n0,1,6~2,1,6\n1,1,8~1,1,9\n\n"
|
||||
}
|
||||
],
|
||||
"2": [
|
||||
{
|
||||
"is": "7",
|
||||
"input": "1,0,1~1,2,1\n0,0,2~2,0,2\n0,2,3~2,2,3\n0,0,4~0,2,4\n2,0,5~2,2,5\n0,1,6~2,1,6\n1,1,8~1,1,9\n\n"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -35,3 +35,4 @@ A day denoted with a star means it has a visualisation.
|
|||
| 19 - Aplenty | ★ ★ | Python | So maybe I *can* do range maths? |
|
||||
| 20 - Pulse Propagation | ☆ ☆ | Python | Too much reading. |
|
||||
| 21 - Step Counter | ★ ☆ | Python | ??? |
|
||||
| 21 - Sand Slabs | ★ ★ | Python | I maintain that OpenSCAD is the best AoC 3D debugging tool |
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
|
@ -37,3 +37,5 @@
|
|||
{"day": 19, "part": 2, "runner": "py", "min": 0.026041030883789062, "max": 0.03458356857299805, "avg": 0.028042428493499756, "n": 100}
|
||||
{"day": 19, "part": 1, "runner": "py", "min": 0.023969173431396484, "max": 0.03136777877807617, "avg": 0.026349050998687742, "n": 100}
|
||||
{"day": 19, "part": 2, "runner": "py", "min": 0.024805068969726562, "max": 0.03318047523498535, "avg": 0.027637341022491456, "n": 100}
|
||||
{"day": 22, "part": 1, "runner": "py", "min": 7.400631666183472, "max": 7.400631666183472, "avg": 7.400631666183472, "n": 1}
|
||||
{"day": 22, "part": 2, "runner": "py", "min": 30.386138439178467, "max": 30.386138439178467, "avg": 30.386138439178467, "n": 1}
|
||||
|
|
|
@ -4,6 +4,7 @@ from numbers import Number
|
|||
|
||||
|
||||
Coordinate = namedtuple("Coordinate", ["x", "y"])
|
||||
Coordinate3 = namedtuple("Coordinate3", ["x", "y", "z"])
|
||||
|
||||
|
||||
def add(a: Coordinate, b: Coordinate) -> Coordinate:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue