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:
In a normal game of Carcassonne, each feature in the landscape is claimed by a player, and contributes to their final score. However, in this version, we will change the rules slightly (primarily for people who already know the standard Carcassonne rules):
- There will only be \$1\$ player
- The player will automatically own every feature in the landscape
- There will be no "badge" score for cities
- Notice that in some of the tiles in the pictures have badge symbols on them. In this challenge, we're ignoring them.
In a landscape, each feature is either complete or incomplete:
- A complete monastery is one where it's tile is surrounded by \$8\$ tiles. This landscape contains one complete monastery (in the center) and one incomplete monastery (Top center).
- A complete city is one fully enclosed by walls. This landscape has \$2\$ complete cities and \$2\$ incomplete cities.
- A complete road is one where both ends terminate at either a city, village or by forming a loop. This landscape has \$2\$ complete roads and \$2\$ incomplete roads.
A landscape is scored as follows:
- For every complete city, the player scores \$2\$ points for every tile containing that city. Therefore this city scores \$4\$ points, and this city scores \$18\$ points.
- For every complete road, the player scores \$1\$ point for every tile containing that road. Therefore this road scores \$6\$ points, and this road scores \$2\$.
For every complete monastery, the player scores \$9\$ points, such as this monastery.
For every incomplete city, the player scores \$1\$ point for every tile containing that city. This landscape contains two incomplete cities, one scoring \$2\$ and the other \$5\$.
- For every incomplete road, the player scores \$1\$ point for each tile containing that road. This landscape contains three incomplete roads, scoring \$1\$, \$2\$ and \$3\$ points.
- For every incomplete monastery, the player scores \$1\$ point for each tile that neighbours the monastery, plus \$1\$ for the monastery itself. This landscape contains \$3\$ monasteries, scoring \$2\$, \$5\$ and \$7\$.
Take this landscape:
This landscape contains \$1\$ complete city, \$2\$ incomplete cities, \$4\$ complete roads, \$2\$ incomplete roads and \$1\$ incomplete monastery which scores \$4 + (3+3) + (3+2+6+2) + (4+2) + 4 = 33\$ points.
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]
Note that the only way to distinguish tiles with monasteries and villages is by the number of roads/cities on the tile, and that there is no specific indicator that a tile has a monastery/village aside from the roads.
Your task is to take a matrix of lists in the above format representing a landscape and to output the score the player would have if they claimed all the features, complete or incomplete, in the landscape. You may take input in any convenient method, may choose any three consistent values to represent Field, City and Road edges and may use any value to represent the empty squares that isn't already a tile. Output must be an integer represented in your language's most natural format. If you aren't sure about an I/O format, just ask.
In addition, the inputs will always have consistent landscapes, and will always have at least 1 tile. Finally, the tiles will not be constrained by the tile availability (like in the real game).
This is code-golf so the shortest code in bytes wins.
Test cases
Each test case has the matrix followed by the score, with the score breakdown underneath with abbreviations.
[[[], [], [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], []]] -> 32
1 c. city (4), 1 i. city (6), 6 i. roads (10), 2 i. monasteries (12)
[[[0, 2, 2, 2, 1], [1, 0, 1, 2, 1], [0, 1, 1, 0, 0], [2, 2, 2, 1, 1]], [[2, 1, 1, 2, 1], [1, 0, 0, 1, 0], [1, 1, 1, 0, 0], [2, 2, 2, 1, 1]], [[1, 1, 1, 0, 0], [0, 2, 1, 1, 1], [1, 0, 1, 2, 1], [2, 1, 1, 0, 1]], [[1, 0, 0, 0, 0], [1, 1, 0, 0, 0], [1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]] -> 33
1 c. city (4), 2 i. cities (6), 4 c. roads (13), 2 i. roads (6), 1 i. monastery (4)
[[[0, 1, 1, 0, 0], [2, 1, 0, 1, 1], [1, 2, 1, 1, 1], [0, 2, 0, 2, 1], [0, 1, 1, 2, 1]], [[], [], [1, 0, 2, 1, 1], [0, 1, 1, 0, 0], [1, 2, 1, 1, 1]], [[2, 1, 0, 1, 1], [1, 2, 1, 1, 0], [2, 1, 1, 2, 1], [], [1, 1, 0, 1, 0]], [[], [1, 0, 0, 1, 1], [1, 0, 1, 0, 0], [2, 2, 0, 0, 2], [0, 1, 1, 2, 1]]] -> 39
2 c. cities (12), 4 i. cities (5), 1 c. road (2), 12 i. roads (20)
[[[2, 1, 1, 0, 1]]] -> 2
1 i. city (1), 1 i. road (1)
[[[1, 2, 1, 1, 1], [0, 0, 0, 2, 1], [], [1, 1, 0, 1, 0], [2, 2, 2, 1, 1]], [[1, 0, 1, 0, 0], [], [2, 0, 2, 0, 2], [0, 0, 0, 0, 0], []], [[1, 1, 2, 2, 1], [0, 1, 0, 1, 0], [2, 0, 1, 1, 1], [], []], [[], [], [2, 2, 1, 2, 1], [], []]] -> 29
2 c. cities (8), 4 i. cities (4), 2 c. roads (8), 4 i. roads (4), 1 i. monastery (5)
[[[], [0, 0, 2, 0, 1], [], [], [0, 0, 2, 0, 1], [], [], []], [[], [2, 1, 1, 0, 1], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [2, 0, 1, 1, 1], [], [], []], [[], [1, 0, 1, 0, 0], [0, 2, 2, 0, 1], [0, 2, 2, 2, 1], [1, 1, 2, 2, 1], [0, 0, 1, 1, 0], [], []], [[0, 1, 1, 0, 0], [1, 2, 2, 1, 1], [2, 0, 2, 2, 1], [2, 0, 2, 0, 1], [2, 2, 0, 0, 2], [1, 1, 2, 2, 1], [0, 1, 2, 1, 1], [0, 0, 1, 1, 0]], [[1, 1, 1, 0, 0], [2, 2, 2, 1, 1], [2, 2, 2, 2, 1], [2, 1, 2, 2, 1], [0, 0, 0, 1, 0], [2, 2, 0, 0, 1], [2, 1, 2, 2, 1], [1, 0, 1, 1, 0]], [[1, 0, 1, 0, 0], [2, 2, 0, 0, 1], [2, 0, 2, 2, 1], [2, 0, 2, 0, 1], [0, 0, 0, 0, 0], [0, 2, 2, 0, 1], [2, 1, 1, 2, 1], [1, 0, 0, 1, 0]], [[1, 1, 0, 0, 0], [0, 0, 1, 1, 0], [2, 2, 0, 0, 1], [2, 2, 0, 2, 1], [0, 2, 0, 2, 1], [2, 1, 1, 2, 1], [1, 0, 0, 1, 0], []], [[], [1, 1, 0, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 1, 0], [1, 0, 0, 1, 0], [], []]] -> 106
3 c. cities (54), 5 c. roads (34), 2 c. monasteries (18)
Note that in the largest city in the final example, the tile [2, 2, 0, 0, 2]
has two sections of the city, but is only a single tile. Therefore, it only counts for 2 points, not 4.
If you have a copy of Carcassonne, I'd highly recommend building the test cases, if only to help visualise them