Sitemap
Pascal Bercker

Pascal Bercker

Philosophy | philosophy of science | logic | Bayesian networks and logic puzzles | keen on the use of Bayesian networks to solve Smullyan-type logic puzzles

TILE THEM ALL! Problem #2 of The 2024 LP-Contest — A Constraint Satisfaction Problem

7 min readNov 3, 2025
Press enter or click to view image in full size
This was the second problem in the 2024 Logic Programming Contest

Can we model this with a Bayesian Network? Yes, but it does require some patience (and some help. I could not have done this without my assistant, aka GPT5!). This all comes down to the Constraint Satisfaction Problem.

We will need a way to represent what we are trying to do, but in the context of a Bayesian network, so that we can think more clearly about what we are after. The first step is to create 20 nodes to represent the cells and the numbers they contain, as in the grid above.

Press enter or click to view image in full size
A representation of the 4x5 grid in terms of nodes for the Bayesian Network

In this context, the notion of a “tile” is only possible between any two nodes along the edges, either vertically or horizontally. There are 4 horizontal edges in each row, for a total of 16, and there are 3 vertical edges in each column, for a total of 15. This gives us 31 nodes in total. Each will be a boolean node (true/false), where “true” will mean that it is a true tile between the two numbers, while “false” will mean that the tile is eliminated. The idea is to impose constraints in such a way that, once activated, Netica will find the 10 tiles that meet the stated condition, namely that they uniquely contain each of the 10 unordered pairs from {0, 1, 2, 3} x {0, 1, 2, 3}. Let’s first display the possible horizontal tiles (in pink).

Press enter or click to view image in full size
The pink nodes represent the horizontal edges and are possible tiles between each number

And we add the possible vertical tiles (bluish teal):

Press enter or click to view image in full size
In blue are the vertical edges between each number and each a possible tile (hence true/false)

The general idea is that each of these is only a hypothetical tile since there can only be a total of exactly 10 tiles, but we have 31 tiles above. We will need to find various constraints not only to get exactly 10 tiles, but to get the right 10 tiles that correspond to one instance of each unordered pair for {0, 1, 2, 3} x {0, 1, 2, 3}.

(Note that the yellow numbered nodes are inert and only there as a graphical overlay for reference.)

The very first constraint is that each number will only have one neighbor (since only two numbers exist on a tile). Let’s use a coordinate system to represent and locate each number. For example, the corner number “1” (C_1_1) can only be on the horizontal tile (H_1_1) with “3” as its neighbor, or be on the vertical tile (V_1_1) with another “3” as its neighbor.

Press enter or click to view image in full size
Each dark-blue node represents each number and they have as many arrows going into them as they have neighbors

Here is a fragment to see more clearly

The corner number has only two neighbors ( arrows) and the interior numbers have 4 neighbors (hence 4 arrows, one from each neighbor)

For each number, we want to say that it can only be on one tile. Each corner number could be on just one of two tiles, but interior numbers must be on just one of four possible tiles (2 horizontal and 2 vertical). Here are two example equations:

Press enter or click to view image in full size
Each node is allowed exactly one neighbor (i.e. can only be on exactly one tile)

These equations are repeated for the number node.

C_2_2 (H_2_1, V_1_2, H_2_2, V_2_2) = 

ExactlyOneTrue(H_2_1, V_1_2, H_2_2, V_2_2)

C_2_3 (V_1_3, V_2_3, H_2_2, H_2_3) =

plus (V_1_3, V_2_3, H_2_2, H_2_3) == 1

C_2_4 (V_2_4, H_2_3, V_1_4, H_2_4) =

plus (V_2_4, H_2_3, V_1_4, H_2_4) == 1

C_2_5 (V_2_5, H_2_4, V_1_5) =

plus (V_2_5, H_2_4, V_1_5) == 1

C_3_1 (V_3_1, H_3_1, V_2_1) =

plus (V_3_1, H_3_1, V_2_1) == 1

C_3_2 (V_3_2, H_3_1, H_3_2, V_2_2) =

plus (V_3_2, H_3_1, H_3_2, V_2_2) == 1

C_3_3 (V_3_3, H_3_2, V_2_3, H_3_3) =

plus (V_3_3, H_3_2, V_2_3, H_3_3) == 1

C_3_4 (V_3_4, H_3_3, H_3_4, V_2_4) =

plus (V_3_4, H_3_3, H_3_4, V_2_4) == 1

C_3_5 (V_2_5, H_3_4, V_3_5) =

plus (V_2_5, H_3_4, V_3_5) == 1

C_4_1 (V_3_1, H_4_1) =

plus (V_3_1, H_4_1) == 1

C_4_2 (H_4_1, H_4_2, V_3_2) =

plus (H_4_1, H_4_2, V_3_2) == 1

C_4_3 (H_4_2, H_4_3, V_3_3) =

plus (H_4_2, H_4_3, V_3_3) == 1

C_4_4 (H_4_3, V_3_4, H_4_4) =

plus (H_4_3, V_3_4, H_4_4) == 1

C_4_5 (H_4_4, V_3_5) =

plus (H_4_4, V_3_5) == 1

Once compiled, we will set each of these “cell cover” nodes to “true” to enforce that constraint. Notice that if all we wanted were any 10 tiling arrangement, we would be basically done. But not just any 10 tiles will do. The tiles have to exactly match each unordered pair from {0, 1, 2, 3} x {0, 1, 2, 3}. There are 10 such pairs. The next step is a bit more tedious. We have to find each such pair in the given grid and create a constraint node for each one.

Get Pascal Bercker’s stories in your inbox

Join Medium for free to get updates from this writer.

For example, there are 6 instances of the pair {2,3} ( the same as {3,2}), which we connect to the constraint node called “TypeUsed_T23”.

There are 6 instances of the pair {2, 3} in the grid
Press enter or click to view image in full size
We only want exactly one instance of the pair {2, 3}

The constraint node TypeUsed_T23 is linked to each horizontal (H_1_1, etc) and vertical node (V_1_1, etc) where an instance of that pair occurs.

TypeUsed_T23 (H_2_1, V_1_2, V_1_5, 
V_2_2, V_3_1, V_3_2) =

ExactlyOneTrue(H_2_1, V_1_2, V_1_5,
V_2_2, V_3_1, V_3_2)

Since there are 10 unordered pairs, we theoretically have 10 such TypeUsed nodes. But we have a bit fewer than that because some are singletons, meaning the pair occurs only once, as with {2, 2} in the left-hand corner. Since that’s the only possible tile, we don’t need to worry about that one.

Press enter or click to view image in full size
We need constraint nodes (in deep blue) for only 7 of the 10 possible pairs

Only one kind of equation is needed for each TypeUsed_T constraint node (x and y are the coordinates for each horizontal (H_x_y) and Vertical (V_x_y) tile.

TypeUsed_T00 (H_3_3, V_1_3, V_2_3) =        // H_x_y and V_x_y - possible tiles

ExactlyOneTrue (H_3_3, V_1_3, V_2_3)

TypeUsed_T01 (H_1_3, H_2_3, H_3_4, V_2_4, V_3_3, V_3_5) =

ExactlyOneTrue (H_1_3, H_2_3, H_3_4, V_2_4, V_3_3, V_3_5)

TypeUsed_T02 (H_2_2, H_4_4, V_3_4) =

ExactlyOneTrue (H_2_2, H_4_4, V_3_4)

TypeUsed_T03 (H_1_2, H_3_2) =

ExactlyOneTrue (H_1_2, H_3_2)

TypeUsed_T12 (H_1_4, H_4_2, H_4_3) =

ExactlyOneTrue (H_1_4, H_4_2, H_4_3)

TypeUsed_T13 (H_1_1, H_2_4, V_1_1, V_2_5) =

ExactlyOneTrue(H_1_1, H_2_4, V_1_1, V_2_5)

TypeUsed_T23 (H_2_1, V_1_2, V_1_5,
V_2_2, V_3_1, V_3_2) =

ExactlyOneTrue(H_2_1, V_1_2, V_1_5,
V_2_2, V_3_1, V_3_2)

(We have omitted {1, 1}, {2, 2}, both singletons, and {3, 3} with only two possible tiles).

Press enter or click to view image in full size
The 4x5 grid displaying just the numbers to be paired in a unique tile

It is a very handy feature of Netica that we can choose which nodes to display and which nodes and links to make invisible. This avoids a cluttered view with very busy networks.

All that remains to be done now is simply to activate the 20 cellcover nodes by setting them to “true”, and to activate the 7 TypeUsed nodes also by setting them to “true”, and the hope is that exactly 10 “tiles” get updated to “true”, meaning some combination of the H_x_y nodes and V_x_y nodes.

Press enter or click to view image in full size
Activating the CellCover and typeUsed nodes (in green)

Let’s have a look

Press enter or click to view image in full size
6 Horizontal Tiles (H_x_y) become “true”

Let’s add the vertical tiles and the numbers:

Press enter or click to view image in full size

This is a cluttered network, so let’s just show the relevant horizontal and vertical tiles and hide the rest.

Press enter or click to view image in full size
These are the 10 tiles wanted corresponding to the unique solution
The unique solution

I found it somewhat remarkable that essentially only one kind of equation was needed for the entire network, namely ExactlyOneTrue (or its equivalent), so as to impose the relevant constraints on various nodes. Though it works, it’s not the most elegant solution, but still instructive. There’s a certain amount of pre-processing done by the user, which ideally would be better if entirely done by the network itself. In particular, I had to locate each instance where the unordered pair occurred in the grid to tell Netica what to constrain and limit to a single instance. Ideally, one should be able to just submit a list of the unordered pairs and let the network figure out the rest.

The PICAT solution from Professor Zhou is further below (Source and reference section). I ran the PICAT version, where “tiles.dat” is just a list of the coordinates of the grid and what number is located there. The output returns the two coordinates of each of the 10 tiles.

The coordinates of the 10 tiles

--

--

Pascal Bercker
Pascal Bercker

Written by Pascal Bercker

Philosophy | philosophy of science | logic | Bayesian networks and logic puzzles | keen on the use of Bayesian networks to solve Smullyan-type logic puzzles