Carcassonne is a tile-based game, where the objective is to construct Roads, Cities and Monasteries, in order to score points. The game works by players taking turns to draw and place tiles to construct a landscape, then claiming roads, cities and monasteries. An example landscape is:
There are \$19\$ distinct tiles (ignoring rotations), each of which contains at least one feature (Road, City or Monastery):
Also, notice that the landscape must be consistent. This means that roads must connect to other roads, city edges must connect to other city edges and fields must connect to fields. Therefore, these tiles are inconsistent:
To avoid this challenge being about image processing, we can translate each tile into a list containing \$5\$ values, according to this legend:
[North edge, East edge, South edge, West Edge, # of cities]
0: Field
1: Road
2: City
For instance, this tile can be described as [2, 0, 1, 1, 1]
. Using this legend, we can describe each tile uniquely, and it's rotations are rotations of the first four elements. The entire grid can be described as a rectangular matrix, with a \$20^\text{th}\$ distinct value for an empty square. Translating the first landscape into this format, we get:
[
[ [], [], [1, 1, 0, 0, 0], [1, 1, 2, 1, 1], [0, 1, 0, 1, 0], [], []],
[[1, 0, 1, 0, 0], [], [0, 0, 0, 0, 0], [2, 0, 2, 0, 2], [], [0, 2, 2, 2, 1], [0, 0, 0, 2, 1]],
[[1, 1, 0, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], [2, 2, 0, 0, 1], [2, 2, 0, 2, 1], [2, 0, 0, 2, 1], []]
]
using []
to represent an empty square. The complete list of tiles (ignoring rotations) in the same grid as the second image is
[1, 0, 1, 0, 0] [0, 0, 1, 1, 0] [2, 1, 1, 1, 1] [0, 1, 1, 1, 0] [2, 0, 0, 0, 1]
[2, 2, 0, 2, 1] [0, 0, 0, 0, 0] [2, 2, 2, 2, 1] [2, 2, 0, 0, 1] [2, 1, 1, 2, 1]
[2, 2, 0, 0, 2] [0, 0, 1, 0, 0] [2, 0, 1, 1, 1] [2, 1, 1, 0, 1] [0, 2, 0, 2, 1]
[1, 1, 1, 1, 0] [2, 1, 0, 1, 1] [2, 2, 1, 2, 1] [2, 0, 2, 0, 2]
Your task is to take in a rectangular matrix where every element save one is one of the 19 tiles given above or one of their rotations. Tiles can appear more than once, and not every tile will appear in every input. This landscape will be consistent, as defined above. You should take in this input and output the tile that could fill the empty space in the array, keeping the landscape consistent, as defined above. You may output the tile in any rotation.
As the number of cities on a tile is redundant for this task, you may choose instead to only work with 17 tiles (as 2 tiles are duplicated when ignoring cities) and take input as lists in the form [N, E, S, W]
instead, giving this list of tiles
[1, 0, 1, 0] [0, 0, 1, 1] [2, 1, 1, 1] [0, 1, 1, 1] [2, 0, 0, 0] [2, 2, 0, 2]
[0, 0, 0, 0] [2, 2, 2, 2] [2, 2, 0, 0] [2, 1, 1, 2] [0, 0, 1, 0] [2, 0, 1, 1]
[2, 1, 1, 0] [0, 2, 0, 2] [1, 1, 1, 1] [2, 1, 0, 1] [2, 2, 1, 2]
If there are multiple tiles that would work, you may output any number of valid tiles. If no such tile exists, you may produce any output/result that could not be construed as a tile (i.e. it's not in the 19 tiles specified above, nor in any of their rotations). The representation of the "empty space" in the input may be your choice, so long as its consistent, and (although I'm not sure why you would) it isn't one of the 19 tiles above or their rotations, and there will only ever be a single empty space.
This is code-golf, so the shortest code in bytes wins.
Test cases
Landscape -> Potential tiles
[[[]]] -> Any tile
[[[0, 0, 0, 0, 0], []]] -> [1, 0, 1, 0, 0], [0, 0, 1, 1, 0], [0, 1, 1, 1, 0], [2, 0, 0, 0, 1], [2, 2, 0, 2, 1], [0, 0, 0, 0, 0], [2, 2, 0, 0, 1], [2, 2, 0, 0, 2], [0, 0, 1, 0, 0], [2, 0, 1, 1, 1], [2, 1, 1, 0, 1], [0, 2, 0, 2, 1], [2, 1, 0, 1, 1], [2, 0, 2, 0, 2]
[[[], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0]]] -> [0, 0, 1, 1, 0], [1, 0, 1, 0, 0], [2, 1, 1, 2, 1], [2, 1, 0, 1, 1], [0, 1, 1, 1, 0], [2, 0, 1, 1, 1], [2, 1, 1, 1, 1], [2, 1, 1, 0, 1], [2, 2, 1, 2, 1], [0, 0, 1, 0, 0], [1, 1, 1, 1, 0]
[[0, 1, 0, 1, 0], [], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0]] -> [1, 0, 1, 0, 0], [2, 1, 0, 1, 1], [0, 1, 1, 1, 0], [2, 1, 1, 1, 1], [1, 1, 1, 1, 0]
[[[0, 1, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 1, 0]], [[1, 1, 0, 0, 0], [0, 1, 0, 1, 0], []]] -> [0, 0, 1, 1, 0], [2, 1, 1, 2, 1], [0, 1, 1, 1, 0], [2, 0, 1, 1, 1], [2, 1, 1, 1, 1], [2, 1, 1, 0, 1], [1, 1, 1, 1, 0]
[[[2, 0, 0, 0, 1], [0, 2, 2, 0, 2], [0, 2, 0, 2, 1], [0, 0, 0, 2, 1]], [[0, 2, 2, 0, 1], [2, 1, 2, 2, 1], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]], [[2, 1, 1, 2, 1], [], [1, 1, 2, 0, 1], [0, 0, 0, 1, 0]]] -> [2, 0, 1, 1, 1]