12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- """Convert input data to adjacency information. Implementation based on https://github.com/ikarth/wfc_2019f"""
- from __future__ import annotations
- import numpy as np
- from numpy.typing import NDArray
- def adjacency_extraction(
- pattern_grid: NDArray[np.int64],
- pattern_catalog: dict[int, NDArray[np.int64]],
- direction_offsets: list[tuple[int, tuple[int, int]]],
- pattern_size: tuple[int, int] = (2, 2),
- ) -> list[tuple[tuple[int, int], int, int]]:
- """Takes a pattern grid and returns a list of all of the legal adjacencies found in it."""
- def is_valid_overlap_xy(
- adjacency_direction: tuple[int, int], pattern_1: int, pattern_2: int
- ) -> bool:
- """Given a direction and two patterns, find the overlap of the two patterns
- and return True if the intersection matches."""
- dimensions = (1, 0)
- not_a_number = -1
- # TODO: can probably speed this up by using the right slices, rather than rolling the whole pattern...
- shifted = np.roll(
- np.pad(
- pattern_catalog[pattern_2],
- max(pattern_size),
- mode="constant",
- constant_values=not_a_number,
- ),
- adjacency_direction,
- dimensions,
- )
- compare = shifted[
- pattern_size[0] : pattern_size[0] + pattern_size[0],
- pattern_size[1] : pattern_size[1] + pattern_size[1],
- ]
- left = max(0, 0, +adjacency_direction[0])
- right = min(pattern_size[0], pattern_size[0] + adjacency_direction[0])
- top = max(0, 0 + adjacency_direction[1])
- bottom = min(pattern_size[1], pattern_size[1] + adjacency_direction[1])
- a = pattern_catalog[pattern_1][top:bottom, left:right]
- b = compare[top:bottom, left:right]
- res = np.array_equal(a, b)
- return res
- pattern_list = list(pattern_catalog.keys())
- legal = []
- for pattern_1 in pattern_list:
- for pattern_2 in pattern_list:
- for _direction_index, direction in direction_offsets:
- if is_valid_overlap_xy(direction, pattern_1, pattern_2):
- legal.append((direction, pattern_1, pattern_2))
- return legal
|