Day 20: Jurassic Jigsaw

Data:

VALID_SIDE_RE

Express the edge of a tile

Functions:

reverse_side(side)

Flip the side.

transform_tile(tile)

Produce the tile transformations by rotating and flipping it.

place_remaining_tiles(image, tiles)

Try to assemble the remaining tiles into the image.

place_tiles(tiles)

Assemble the tiles given as ID 🠒 tile transformations into an image.

parse_tile(lines)

Parse the lines into (ID number, tile

parse_tiles(text)

Parse the input text into ID number 🠒 possible tile transformations.

main()

Execute the main routine.

Classes:

Tile(top, right, bottom, left)

Represent a tile of the puzzle.

Image(width, tiles)

Represent a (partially or fully) assembled puzzle of tiles.

ValidTileText(lines)

Represent lines to conform to valid tile text.

VALID_SIDE_RE = re.compile('[.#]{10}')

Express the edge of a tile

reverse_side(side: str) str[source]

Flip the side.

Requires
  • VALID_SIDE_RE.fullmatch(side)

Ensures
  • re.fullmatch(r"[.#]{10}", result)

class Tile(top: str, right: str, bottom: str, left: str)[source]

Represent a tile of the puzzle.

Methods:

__init__(top, right, bottom, left)

Initialize with the given values.

rotate()

Copy the tile and rotate it clock-wise.

flip_vertical()

Copy the tile and flip the it along the vertical axis.

flip_horizontal()

Copy the tile and flip it along the horizontal axis.

__repr__()

Represent the tile as string for easier debugging.

__eq__(other)

Compare by sides, if other is a Tile.

Attributes:

top

Top side

right

Right side

bottom

Bottom side

left

Left side

__init__(top: str, right: str, bottom: str, left: str) None[source]

Initialize with the given values.

Requires
  • left[-1] == top[0]

  • bottom[-1] == left[0]

  • right[-1] == bottom[0]

  • top[-1] == right[0]

  • all(
        VALID_SIDE_RE.fullmatch(side)
        for side in (top, right, bottom, left)
    )
    
top: Final[str]

Top side

right: Final[str]

Right side

bottom: Final[str]

Bottom side

left: Final[str]

Left side

rotate() Tile[source]

Copy the tile and rotate it clock-wise.

flip_vertical() Tile[source]

Copy the tile and flip the it along the vertical axis.

flip_horizontal() Tile[source]

Copy the tile and flip it along the horizontal axis.

__repr__() str[source]

Represent the tile as string for easier debugging.

__eq__(other: object) bool[source]

Compare by sides, if other is a Tile.

Otherwise, by equality.

transform_tile(tile: Tile) Set[Tile][source]

Produce the tile transformations by rotating and flipping it.

class Image(width: int, tiles: List[Tuple[int, Tile]])[source]

Represent a (partially or fully) assembled puzzle of tiles.

Attributes:

width

Total width of the image

tiles

Assembled tiles

Methods:

pop()

Remove the last tile from the puzzle.

attempt_add(tile_id, tile)

Try to add the tile into the image.

__eq__(other)

Return self==value.

__init__(width, tiles)

__repr__()

Return repr(self).

width: int

Total width of the image

tiles: List[Tuple[int, Tile]]

Assembled tiles

pop() Tuple[int, Tile][source]

Remove the last tile from the puzzle.

attempt_add(tile_id: int, tile: Tile) bool[source]

Try to add the tile into the image.

Returns

True if successful

__eq__(other)

Return self==value.

__init__(width: int, tiles: List[Tuple[int, Tile]]) None
__repr__()

Return repr(self).

place_remaining_tiles(image: Image, tiles: Dict[int, Set[Tile]]) bool[source]

Try to assemble the remaining tiles into the image.

Returns

True if there are no more tiles left, or if the assembly was possible.

place_tiles(tiles: Dict[int, Set[Tile]]) Optional[Image][source]

Assemble the tiles given as ID 🠒 tile transformations into an image.

Returns

Image, if possible; None if no puzzle could be assembled

Requires
  • int(math.sqrt(len(tiles))) ** 2 == len(tiles)

    (Number of tiles must be a perfect square)

class ValidTileText(lines: Sequence[str])[source]

Represent lines to conform to valid tile text.

Methods:

__new__(cls, lines)

Ensure the properties on the lines.

__getitem__()

Get the line(s) at the given index.

__len__()

Return the number of the lines.

__iter__()

Iterate over the lines.

static __new__(cls, lines: Sequence[str]) ValidTileText[source]

Ensure the properties on the lines.

Requires
  • len(lines) == 11
    and re.match(r"Tile (\d+)", lines[0]) is not None
    and all(VALID_SIDE_RE.fullmatch(line) for line in lines[1:])
    

    (Raise ValueError)

__getitem__(index: int) str[source]
__getitem__(index: slice) ValidTileText

Get the line(s) at the given index.

__len__() int[source]

Return the number of the lines.

__iter__() Iterator[str][source]

Iterate over the lines.

parse_tile(lines: ValidTileText) Tuple[int, Tile][source]

Parse the lines into (ID number, tile

parse_tiles(text: str) Dict[int, Set[Tile]][source]

Parse the input text into ID number 🠒 possible tile transformations.

main() None[source]

Execute the main routine.