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