The declarative programming language Prolog is a natural choice for solving such combinatorial tasks. Here is a Prolog formulation of the puzzle, using constraint logic programming over integers that ships with typical Prolog systems: binary_puzzle(Rows) :- length(Rows, L), maplist(same_length(Rows), Rows), maplist(only_two_next_to_each_other, Rows), transpose(Rows, Cols), maplist(only_two_next_to_each_other, Cols),…
I like your Prolog solution! I thought I'd take a crack at a Python SAT-solver solution, also done in less than 1 second. from z3 import * # we use '-1' for empty instance = ((-1,-1,-1,-1,-1,1,-1,-1,-1,1), (1,-1,-1,-1,-1,-1,-1,0,-1,-1), (-1,-1,0,-1,-1,-1,-1,0,-1,-1), (-1,0,0,-1,-1,-1,0,-1,-1,1), (1,-1,-1,-1,-1,-1,-1,-1,-1,1), (-1,-1,-1,0,-1,-1,1,-1,-1,-1), (0,-1,-1,-1,-1,1,-1,-1,-1,-1), (-1,-1,-1,-1,-1,-1,-1,0,-1,0),…
I used a conjunction of two constraints, for each triple of cells A, B, C in direct succession:
( A #= B ) #==> ( C #\= B ),
( B #= C ) #==> ( B #\= A )
And you are using only one constraint: B #= A #==> C #\= A
To the SAT purist, the question may now arise: Are these ways really equivalent, do they state the same constraint?One way to check it is to apply CLP(B): Constraint Logic Programming over Boolean variables, which ships for example in SICStus Prolog and is provided as library(clpb).
Using this library, we can ask:
?- taut((((A =:= B) =
This asks whether it is a tautology (taut/2) that the two ways to express the constraint are equivalent.The system answers:
T = 1,
sat(A=:=A),
sat(B=:=B),
sat(C=:=C).
So: Yes, the two ways are in fact equivalent, because this equivalence always holds. Yours being shorter, I would in fact prefer it and could also use it in the Prolog solution! Well done!One additional neat thing about the Prolog solution: Since no further solution is found on backtracking in this case, we have in fact also verified that the reported solution is indeed unique. I suppose this check could also be added to your solution somehow to make such observations possible?
For example, suppose I modify the puzzle to read:
puzzle([[_,_,_,_,_,_,_,_,_,1],
[1,_,_,_,_,_,_,0,_,_],
[_,_,0,_,_,_,_,0,_,_],
[_,0,0,_,_,_,0,_,_,1],
[1,_,_,_,_,_,_,_,_,1],
[_,_,_,0,_,_,1,_,_,_],
[0,_,_,_,_,1,_,_,_,_],
[_,_,_,_,_,_,_,0,_,0],
[0,_,_,_,_,_,_,_,_,0],
[_,0,_,0,_,1,_,_,_,_]]).
Then there are 144 solutions (I have removed the first "1" from the first row), which I can generate with the Prolog solution within a second.