This commit is contained in:
parent
89306f4a04
commit
291c627c79
@ -173,7 +173,6 @@ class Solver(BaseSolver):
|
||||
)
|
||||
)
|
||||
|
||||
# 1242 (not working)
|
||||
yield sum(
|
||||
c
|
||||
for _, c in play(
|
||||
|
@ -1,3 +1,5 @@
|
||||
import itertools as it
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Iterator, TypeAlias
|
||||
|
||||
from ..base import BaseSolver
|
||||
@ -6,133 +8,94 @@ Node: TypeAlias = tuple[int, int]
|
||||
Edge: TypeAlias = tuple[Node, Node]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Region:
|
||||
value: str
|
||||
cells: set[tuple[int, int]]
|
||||
edges: set[Edge]
|
||||
sides: list[tuple[Edge, ...]]
|
||||
|
||||
|
||||
def extract_region(grid: list[str], cell: tuple[int, int]):
|
||||
n_rows, n_cols = len(grid), len(grid[0])
|
||||
row, col = cell
|
||||
|
||||
value = grid[row][col]
|
||||
|
||||
cells: set[tuple[int, int]] = set()
|
||||
edges: set[Edge] = set()
|
||||
sides: list[tuple[Edge, ...]] = []
|
||||
|
||||
queue: list[tuple[int, int]] = [(row, col)]
|
||||
while queue:
|
||||
row, col = queue.pop(0)
|
||||
|
||||
if (row, col) in cells:
|
||||
continue
|
||||
|
||||
cells.add((row, col))
|
||||
|
||||
for ur, uc in (
|
||||
(row - 1, col),
|
||||
(row, col + 1),
|
||||
(row + 1, col),
|
||||
(row, col - 1),
|
||||
):
|
||||
if 0 <= ur < n_rows and 0 <= uc < n_cols and grid[ur][uc] == value:
|
||||
queue.append((ur, uc))
|
||||
continue
|
||||
|
||||
if ((row, col), (ur, uc)) in edges:
|
||||
continue
|
||||
|
||||
if col == uc:
|
||||
mid, max = col, n_cols
|
||||
|
||||
def get(v: int):
|
||||
return (row, v, ur, v)
|
||||
else:
|
||||
mid, max = row, n_rows
|
||||
|
||||
def get(v: int):
|
||||
return (v, col, v, uc)
|
||||
|
||||
side: tuple[Edge, ...] = ((((row, col), (ur, uc))),)
|
||||
for rng in (range(mid - 1, -1, -1), range(mid, max)):
|
||||
for r2, c2, ur2, uc2 in map(get, rng):
|
||||
if grid[r2][c2] != value or (
|
||||
0 <= ur2 < n_rows
|
||||
and 0 <= uc2 < n_cols
|
||||
and grid[r2][c2] == grid[ur2][uc2]
|
||||
):
|
||||
break
|
||||
side += ((((r2, c2), (ur2, uc2))),)
|
||||
|
||||
sides.append(side)
|
||||
edges = edges.union(side)
|
||||
|
||||
return Region(value=value, cells=cells, edges=edges, sides=sides)
|
||||
|
||||
|
||||
class Solver(BaseSolver):
|
||||
def solve(self, input: str) -> Iterator[Any]:
|
||||
grid = input.splitlines()
|
||||
n_rows, n_cols = len(grid), len(grid[0])
|
||||
|
||||
marked = {(row, col): False for row in range(n_rows) for col in range(n_cols)}
|
||||
regions: list[Region] = []
|
||||
to_visit: set[tuple[int, int]] = set(
|
||||
it.product(range(len(grid)), range(len(grid[0])))
|
||||
)
|
||||
|
||||
total_1: int = 0
|
||||
total_2: int = 0
|
||||
|
||||
while not all(marked.values()):
|
||||
row, col = next(k for k, v in marked.items() if not v)
|
||||
|
||||
cells: set[tuple[int, int]] = set()
|
||||
perimeter: int = 0
|
||||
value = grid[row][col]
|
||||
queue: list[tuple[int, int]] = [(row, col)]
|
||||
|
||||
edges: set[Edge] = set()
|
||||
sides: list[tuple[Edge, ...]] = []
|
||||
|
||||
while queue:
|
||||
row, col = queue.pop(0)
|
||||
|
||||
if marked[row, col]:
|
||||
continue
|
||||
|
||||
cells.add((row, col))
|
||||
marked[row, col] = True
|
||||
|
||||
if row == 0 or grid[row - 1][col] != value:
|
||||
perimeter += 1
|
||||
|
||||
if ((row, col), (row - 1, col)) not in edges:
|
||||
side: list[Edge] = [(((row, col), (row - 1, col)))]
|
||||
for col2 in list(range(col - 1, -1, -1)):
|
||||
if grid[row][col2] != value or (
|
||||
row > 0 and grid[row][col2] == grid[row - 1][col2]
|
||||
):
|
||||
break
|
||||
side.append((((row, col2), (row - 1, col2))))
|
||||
for col2 in range(col + 1, n_cols):
|
||||
if grid[row][col2] != value or (
|
||||
row > 0 and grid[row][col2] == grid[row - 1][col2]
|
||||
):
|
||||
break
|
||||
side.append((((row, col2), (row - 1, col2))))
|
||||
sides.append(tuple(side))
|
||||
edges = edges.union(side)
|
||||
else:
|
||||
queue.append((row - 1, col))
|
||||
|
||||
if col == 0 or grid[row][col - 1] != value:
|
||||
perimeter += 1
|
||||
|
||||
if ((row, col), (row, col - 1)) not in edges:
|
||||
side: list[Edge] = [(((row, col), (row, col - 1)))]
|
||||
for row2 in range(row - 1, -1, -1):
|
||||
if grid[row2][col] != value or (
|
||||
col > 0 and grid[row2][col] == grid[row2][col - 1]
|
||||
):
|
||||
break
|
||||
side.append((((row2, col), (row2, col - 1))))
|
||||
for row2 in range(row + 1, n_rows):
|
||||
if grid[row2][col] != value or (
|
||||
col > 0 and grid[row2][col] == grid[row2][col - 1]
|
||||
):
|
||||
break
|
||||
side.append((((row2, col), (row2, col - 1))))
|
||||
sides.append(tuple(side))
|
||||
edges = edges.union(side)
|
||||
else:
|
||||
queue.append((row, col - 1))
|
||||
|
||||
if row + 1 == n_rows or grid[row + 1][col] != value:
|
||||
perimeter += 1
|
||||
|
||||
if ((row, col), (row + 1, col)) not in edges:
|
||||
side: list[Edge] = [(((row, col), (row + 1, col)))]
|
||||
for col2 in list(range(col - 1, -1, -1)):
|
||||
if grid[row][col2] != value or (
|
||||
row + 1 < n_rows
|
||||
and grid[row][col2] == grid[row + 1][col2]
|
||||
):
|
||||
break
|
||||
side.append((((row, col2), (row + 1, col2))))
|
||||
for col2 in range(col + 1, n_cols):
|
||||
if grid[row][col2] != value or (
|
||||
row + 1 < n_rows
|
||||
and grid[row][col2] == grid[row + 1][col2]
|
||||
):
|
||||
break
|
||||
side.append((((row, col2), (row + 1, col2))))
|
||||
sides.append(tuple(side))
|
||||
edges = edges.union(side)
|
||||
else:
|
||||
queue.append((row + 1, col))
|
||||
|
||||
if col + 1 == n_cols or grid[row][col + 1] != value:
|
||||
perimeter += 1
|
||||
|
||||
if ((row, col), (row, col + 1)) not in edges:
|
||||
side: list[Edge] = [(((row, col), (row, col + 1)))]
|
||||
for row2 in range(row - 1, -1, -1):
|
||||
if grid[row2][col] != value or (
|
||||
col + 1 < n_cols
|
||||
and grid[row2][col] == grid[row2][col + 1]
|
||||
):
|
||||
break
|
||||
side.append((((row2, col), (row2, col + 1))))
|
||||
for row2 in range(row + 1, n_rows):
|
||||
if grid[row2][col] != value or (
|
||||
col + 1 < n_cols
|
||||
and grid[row2][col] == grid[row2][col + 1]
|
||||
):
|
||||
break
|
||||
side.append((((row2, col), (row2, col + 1))))
|
||||
sides.append(tuple(side))
|
||||
edges = edges.union(side)
|
||||
else:
|
||||
queue.append((row, col + 1))
|
||||
while to_visit:
|
||||
region = extract_region(grid, next(iter(to_visit)))
|
||||
|
||||
self.logger.info(
|
||||
f"region with {value}: {len(cells)} * {perimeter} = {len(cells) * perimeter}, {len(cells)} * {len(sides)} = {len(cells) * len(sides)}"
|
||||
f"region with {region.value}: "
|
||||
f"{len(region.cells)} * {len(region.edges)} = {len(region.cells) * len(region.edges)}, "
|
||||
f"{len(region.cells)} * {len(region.sides)} = {len(region.cells) * len(region.sides)}"
|
||||
)
|
||||
total_1 += len(cells) * perimeter
|
||||
total_2 += len(cells) * len(sides)
|
||||
|
||||
yield total_1
|
||||
yield total_2
|
||||
to_visit.difference_update(region.cells)
|
||||
regions.append(region)
|
||||
|
||||
yield sum(len(region.cells) * len(region.edges) for region in regions)
|
||||
yield sum(len(region.cells) * len(region.sides) for region in regions)
|
||||
|
Loading…
Reference in New Issue
Block a user