Noah’s Ark by Smart Games is a logic puzzle not unlike Katamino, but with a twist: tiles of the same color (depicting the male and female of one species) need to be placed adjacent to each other (on the other hand, it is much simpler, as the tiles cannot be rotated).
Let’s try a top-down solution.
Problem) :-
solve(Problem, State, Animals),
setup(Animals, State, Solution),
solve(Solution).
show(, State, State).
solve([]A|Animals], State, Solution) :-
solve([P),
position(A, P, State, State1),
place(Animals, State1, Solution). solve(
The main rule, solve/1
, is called with the problem
specification (to be defined later). It sets up the initial state, and
the list of animals to place on the board, then calls the solver
(solve/3
), and finally shows the solution. The solver takes
each of the animals, one by one, and tries to place them to a valid
position according to the game rules.
A position is any square on the board (the top-left corner being
1-1
):
X-Y) :-
position(1, 4, Y),
between(1, 7, X),
between(\+ member(X-Y, [1-1,7-1,1-4,7-4]).
Valid placements also need to check the partner-adjacency rule, and
that all squares of a tile fall on empty positions, but these will be
checked by place/4
.
For now, first let us think about how to represent the animals. Each
animal has two tiles (a male and a female), so we may refer to them by
something like lion-1
or hippo-2
. (It would be
better to use lion-m
and lion-f
, but that is
the only animal where I can tell which is which.) They also have a
distinctive shape, which can be described by a list of positions
relative to the anchor position. We will choose the anchor
position to be always part of the tile, so the (0,0) position
is always in the list, and can be omitted.
In the definitions below, the anchor point is always leftmost square of the top row of the tile:
-1, [1-0]).
animal(elephant-2, [0-1,1-1]).
animal(elephant-1, [0-1]).
animal(giraffe-2, [0-1,(-1)-1]).
animal(giraffe-1, [1-0]).
animal(hippo-2, [1-0,2-0]).
animal(hippo-1, [1-0]).
animal(lion-2, [1-0,0-1]).
animal(lion-1, [1-0]).
animal(zebra-2, [0-1]). animal(zebra
Here the x coordinate goes from left to right, and the y coordinate from top to bottom.
So for example elephant-2
is the shape
O .
X X
where O
is the anchor. Similarly, giraffe-2
is
. O
X X
In the problem specifications we can place animal tiles by giving a
list containing set(Animal,Position)
elements, e.g. problem
#25 places a lion and a hippo:
. LLL . .
. . . . . . .
. . . . . . .
HHHHH . .
which translates to the query
?- solve([set(lion-1,3-1),set(hippo-2,2-4)]).
Now we can do the initial setup:
Problem, State, Animals) :-
setup(A,L), animal(A, L), As),
findall(a(Problem, [], As, State, Animals).
setup(, State, Animals, State, Animals).
setup([]A,P)|Problem], S, As, State, Animals) :-
setup([set(A,L), As, As1),
select(a(A,L), P, S, S1),
place(a(Problem, S1, As1, State, Animals). setup(
Here setup/3
takes all the animals “in hand”, and places
them one by one at the specified positions.
Next we need the rule for placing a tile on the board:
A-N,L), Pos, State, State1) :-
place(a(A-N, [0-0|L], Pos, State, State1),
place(A, State1), !.
check(_, [], _, State, State).
place(A, [X-Y|L], X0-Y0, State, State1) :-
place(X1 is X0 + X, Y1 is Y0 + Y,
X1-Y1),
position(\+ member(tile(_,X1-Y1), State),
A, L, X0-Y0, [tile(A,X1-Y1)|State], State1). place(
place/4
just calls place/5
(adding the
omitted 0-0
to the list of relative positions), and then
checks (by check/2
) if the animal satisfies the adjacency
rule. place/5
goes through the relative positions, checks
that those squares are empty, and fills the current state with elements
of the form tile(Animal,Pos)
.
The adjacency check can be satisfied in two ways:
Only the one of the male and female is present on the board.
There are two adjacent squares that belong to the male and female of the specified animal.
Translated to Prolog this becomes:
A, State) :- \+ member(tile(A-1,_), State).
check(A, State) :- \+ member(tile(A-2,_), State).
check(A, State) :-
check(A-1,P1), State),
member(tile(A-2,P2), State),
member(tile(P1, P2). adjacent(
where adjacency is
X1-Y1, X2-Y2) :- X1 = X2, abs(Y1-Y2) =:= 1.
adjacent(X1-Y1, X2-Y2) :- Y1 = Y2, abs(X1-X2) =:= 1. adjacent(
Finally, we need a nice(r) output. An easy solution is to use 2 letters for each square - the abbreviated name of the animal and the tile number:
Tiles) :- nl,
show(Pos),
position(Name-N,Pos), Tiles),
member(tile(Name, Abbrev),
abbreviation(Pos, [2-1,2-4]) -> write(' ') ; true ),
( member(write(Abbrev), write(N), write(' '),
Pos, [6-1,7-2,7-3,6-4]) -> nl ; true ),
( member(fail.
, 'E').
abbreviation(elephant, 'G').
abbreviation(giraffe, 'H').
abbreviation(hippo, 'L').
abbreviation(lion, 'Z'). abbreviation(zebra
Note that special handling is needed for
the first and last lines, where the x = 1 square is missing
the last squares of all lines, where we need to write a newline
Let us test it on the first and last problems:
?- solve([set(lion-1,2-1),
set(zebra-1,3-3),
set(zebra-2,5-2),
set(giraffe-2,7-2),
set(hippo-2,4-4)]).
L1 L1 L2 L2 G1
E2 E1 E1 L2 Z2 G1 G2
E2 E2 Z1 Z1 Z2 G2 G2
H1 H1 H2 H2 H2
?- solve([set(zebra-2,4-2)]).
G2 Z1 Z1 L2 L2
G2 G2 G1 Z2 L2 L1 L1
H1 H1 G1 Z2 E2 E1 E1
H2 H2 H2 E2 E2
Note that if there are multiple solutions, the solver prints all of them:
?- solve([set(hippo-1,5-1),set(elephant-2,2-3)]).
H2 H2 H2 H1 H1
L2 L2 L1 L1 Z1 Z1 Z2
L2 E2 E1 E1 G2 G1 Z2
E2 E2 G2 G2 G1
H2 H2 H2 H1 H1
Z2 Z1 Z1 G2 G1 L1 L1
Z2 E2 G2 G2 G1 L2 L2
E2 E2 E1 E1 L2
Problem) :-
solve(Problem, State, Animals),
setup(Animals, State, Solution),
solve(Solution).
show(, State, State).
solve([]A|Animals], State, Solution) :-
solve([P),
position(A, P, State, State1),
place(Animals, State1, Solution).
solve(
X-Y) :-
position(1, 4, Y),
between(1, 7, X),
between(\+ member(X-Y, [1-1,7-1,1-4,7-4]).
-1, [1-0]).
animal(elephant-2, [0-1,1-1]).
animal(elephant-1, [0-1]).
animal(giraffe-2, [0-1,(-1)-1]).
animal(giraffe-1, [1-0]).
animal(hippo-2, [1-0,2-0]).
animal(hippo-1, [1-0]).
animal(lion-2, [1-0,0-1]).
animal(lion-1, [1-0]).
animal(zebra-2, [0-1]).
animal(zebra
Problem, State, Animals) :-
setup(A,L), animal(A, L), As),
findall(a(Problem, [], As, State, Animals).
setup(, State, Animals, State, Animals).
setup([]A,P)|Problem], S, As, State, Animals) :-
setup([set(A,L), As, As1),
select(a(A,L), P, S, S1),
place(a(Problem, S1, As1, State, Animals).
setup(
A-N,L), Pos, State, State1) :-
place(a(A-N, [0-0|L], Pos, State, State1),
place(A, State1), !.
check(_, [], _, State, State).
place(A, [X-Y|L], X0-Y0, State, State1) :-
place(X1 is X0 + X, Y1 is Y0 + Y,
X1-Y1),
position(\+ member(tile(_,X1-Y1), State),
A, L, X0-Y0, [tile(A,X1-Y1)|State], State1).
place(
A, State) :- \+ member(tile(A-1,_), State).
check(A, State) :- \+ member(tile(A-2,_), State).
check(A, State) :-
check(A-1,P1), State),
member(tile(A-2,P2), State),
member(tile(P1, P2).
adjacent(
X1-Y1, X2-Y2) :- X1 = X2, abs(Y1-Y2) =:= 1.
adjacent(X1-Y1, X2-Y2) :- Y1 = Y2, abs(X1-X2) =:= 1.
adjacent(
Tiles) :- nl,
show(Pos),
position(Name-N,Pos), Tiles),
member(tile(Name, Abbrev),
abbreviation(Pos, [2-1,2-4]) -> write(' ') ; true ),
( member(write(Abbrev), write(N), write(' '),
Pos, [6-1,7-2,7-3,6-4]) -> nl ; true ),
( member(fail.
, 'E').
abbreviation(elephant, 'G').
abbreviation(giraffe, 'H').
abbreviation(hippo, 'L').
abbreviation(lion, 'Z'). abbreviation(zebra
The last problems in the official game only place one tile on the board. It is natural to ask: How can I place only one tile such that there should be a unique solution?
The following program answers this question:
:-
unique A, _),
animal(P),
position(A,P)], I, L),
setup([set(S, solve(L, I, S), [X]),
findall(nl, write('Place '), write(A),
write(' at '), write(P), write(':'), nl,
X). show(
Let’s see the output:
?- unique.
Place elephant-1 at 5-1:
G2 G1 E2 E1 E1
G2 G2 G1 E2 E2 L1 L1
H1 H1 Z1 Z1 Z2 L2 L2
H2 H2 H2 Z2 L2
Place elephant-1 at 4-2:
L2 L2 L1 L1 E2
G1 L2 G2 E1 E1 E2 E2
G1 G2 G2 Z2 H2 H2 H2
Z1 Z1 Z2 H1 H1
Place elephant-1 at 3-4:
L1 L1 H1 H1 G1
L2 L2 H2 H2 H2 G1 G2
L2 Z2 Z1 Z1 E2 G2 G2
Z2 E1 E1 E2 E2
Place elephant-2 at 4-1:
G2 G1 E2 E1 E1
G2 G2 G1 E2 E2 L1 L1
H1 H1 Z1 Z1 Z2 L2 L2
H2 H2 H2 Z2 L2
Place giraffe-1 at 5-1:
L1 L1 G2 G1 E2
L2 L2 G2 G2 G1 E2 E2
L2 Z2 H2 H2 H2 E1 E1
Z2 Z1 Z1 H1 H1
Place giraffe-1 at 3-2:
G2 Z1 Z1 L2 L2
G2 G2 G1 Z2 L2 L1 L1
H1 H1 G1 Z2 E2 E1 E1
H2 H2 H2 E2 E2
Place giraffe-2 at 4-1:
L1 L1 G2 G1 E2
L2 L2 G2 G2 G1 E2 E2
L2 Z2 H2 H2 H2 E1 E1
Z2 Z1 Z1 H1 H1
Place hippo-1 at 2-2:
L1 L1 L2 L2 G2
E2 H1 H1 L2 G2 G2 G1
E2 E2 H2 H2 H2 Z2 G1
E1 E1 Z1 Z1 Z2
Place hippo-1 at 6-2:
L1 L1 H2 H2 H2
L2 L2 Z2 Z1 Z1 H1 H1
L2 G1 Z2 G2 E2 E1 E1
G1 G2 G2 E2 E2
Place hippo-1 at 4-3:
L2 L2 L1 L1 G1
E2 L2 Z2 Z1 Z1 G1 G2
E2 E2 Z2 H1 H1 G2 G2
E1 E1 H2 H2 H2
Place hippo-1 at 5-3:
L1 L1 L2 L2 G2
Z2 Z1 Z1 L2 G2 G2 G1
Z2 E2 E1 E1 H1 H1 G1
E2 E2 H2 H2 H2
Place hippo-2 at 4-2:
E2 E1 E1 H1 H1
Z2 E2 E2 H2 H2 H2 G1
Z2 Z1 Z1 L2 L2 G2 G1
L1 L1 L2 G2 G2
Place hippo-2 at 5-2:
L1 L1 G1 H1 H1
L2 L2 G2 G1 H2 H2 H2
L2 G2 G2 Z2 E2 E1 E1
Z1 Z1 Z2 E2 E2
Place lion-1 at 3-3:
G2 G1 L2 L2 E2
G2 G2 G1 L2 Z2 E2 E2
H1 H1 L1 L1 Z2 E1 E1
H2 H2 H2 Z1 Z1
Place lion-1 at 2-4:
E2 E1 E1 H1 H1
Z2 E2 E2 H2 H2 H2 G1
Z2 Z1 Z1 L2 L2 G2 G1
L1 L1 L2 G2 G2
Place lion-2 at 4-3:
E2 E1 E1 H1 H1
Z2 E2 E2 H2 H2 H2 G1
Z2 Z1 Z1 L2 L2 G2 G1
L1 L1 L2 G2 G2
Place zebra-2 at 4-2:
G2 Z1 Z1 L2 L2
G2 G2 G1 Z2 L2 L1 L1
H1 H1 G1 Z2 E2 E1 E1
H2 H2 H2 E2 E2
So there are 17 such problems:
Animal | Type 1 | Type 2 | Problems |
---|---|---|---|
Elephant | 3 | 1 | (46),42,41 ; 46 |
Giraffe | 2 | 1 | 35,(48) ; (35) |
Hippo | 4 | 2 | 40,45,47,26 ; 32,39 |
Lion | 2 | 1 | -,(32/38) ; 38 |
Zebra | 0 | 1 | ; 48 |
There were 5 cases missing (4 of these have the same solutions as other 1-animal problems - #32/#38, in particular, can be defined by the large hippo or either lion), but there is also one completely new.
We have seen in the previous section that some problems had the same solution. So how many different solutions are there?
Let’s see (I also added the associated problem numbers):
?- solve([]).
(~43)
E2 E1 E1 L1 L1
Z2 E2 E2 L2 L2 G2 G1
Z2 Z1 Z1 L2 G2 G2 G1
H1 H1 H2 H2 H2
#43:
E2 E1 E1 L1 L1
Z2 E2 E2 L2 L2 G2 G1
Z2 Z1 Z1 L2 G2 G2 G1
H2 H2 H2 H1 H1
#32/#38:
E2 E1 E1 H1 H1
Z2 E2 E2 H2 H2 H2 G1
Z2 Z1 Z1 L2 L2 G2 G1
L1 L1 L2 G2 G2
(~14)
L1 L1 E1 E1 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 G1 Z2 Z1 Z1
H1 H1 H2 H2 H2
#14:
L1 L1 E1 E1 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 G1 Z2 Z1 Z1
H2 H2 H2 H1 H1
#21:
L1 L1 E1 E1 E2
L2 L2 Z2 Z1 Z1 E2 E2
L2 G1 Z2 G2 H2 H2 H2
G1 G2 G2 H1 H1
#46:
G2 G1 E2 E1 E1
G2 G2 G1 E2 E2 L1 L1
H1 H1 Z1 Z1 Z2 L2 L2
H2 H2 H2 Z2 L2
#12:
L1 L1 L2 L2 G1
E1 E1 E2 L2 Z2 G1 G2
H1 H1 E2 E2 Z2 G2 G2
H2 H2 H2 Z1 Z1
#19:
Z1 Z1 Z2 L1 L1
E1 E1 E2 Z2 L2 L2 G1
H1 H1 E2 E2 L2 G2 G1
H2 H2 H2 G2 G2
#34:
L1 L1 L2 L2 G1
E2 E1 E1 L2 Z2 G1 G2
E2 E2 H1 H1 Z2 G2 G2
H2 H2 H2 Z1 Z1
#1:
L1 L1 L2 L2 G1
E2 E1 E1 L2 Z2 G1 G2
E2 E2 Z1 Z1 Z2 G2 G2
H1 H1 H2 H2 H2
(~1)
L1 L1 L2 L2 G1
E2 E1 E1 L2 Z2 G1 G2
E2 E2 Z1 Z1 Z2 G2 G2
H2 H2 H2 H1 H1
#A1:
H1 H1 H2 H2 H2
E2 E1 E1 G1 Z2 L1 L1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 Z1 Z1 L2
(~8/36)
H1 H1 H2 H2 H2
E2 E1 E1 G1 Z2 Z1 Z1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 L1 L1 L2
(~A1)
H2 H2 H2 H1 H1
E2 E1 E1 G1 Z2 L1 L1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 Z1 Z1 L2
#8/#36:
H2 H2 H2 H1 H1
E2 E1 E1 G1 Z2 Z1 Z1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 L1 L1 L2
#11:
L1 L1 L2 L2 G2
E2 E1 E1 L2 G2 G2 G1
E2 E2 H2 H2 H2 Z2 G1
H1 H1 Z1 Z1 Z2
#A2:
Z1 Z1 Z2 L1 L1
E2 E1 E1 Z2 L2 L2 G1
E2 E2 H1 H1 L2 G2 G1
H2 H2 H2 G2 G2
#4:
H1 H1 H2 H2 H2
E2 E1 E1 Z1 Z1 L1 L1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 G1 Z2 L2
(~4)
H2 H2 H2 H1 H1
E2 E1 E1 Z1 Z1 L1 L1
E2 E2 G2 G1 Z2 L2 L2
G2 G2 G1 Z2 L2
#17:
Z1 Z1 Z2 L2 L2
E2 E1 E1 Z2 L2 L1 L1
E2 E2 G2 G1 H2 H2 H2
G2 G2 G1 H1 H1
#42:
L2 L2 L1 L1 E2
G1 L2 G2 E1 E1 E2 E2
G1 G2 G2 Z2 H2 H2 H2
Z1 Z1 Z2 H1 H1
#6/(~22):
H1 H1 H2 H2 H2
Z2 Z1 Z1 E2 E1 E1 G1
Z2 L2 L2 E2 E2 G2 G1
L2 L1 L1 G2 G2
#22/(~6):
H2 H2 H2 H1 H1
Z2 Z1 Z1 E2 E1 E1 G1
Z2 L2 L2 E2 E2 G2 G1
L2 L1 L1 G2 G2
#3/(~16):
L2 L2 L1 L1 G1
E2 L2 Z1 Z1 Z2 G1 G2
E2 E2 E1 E1 Z2 G2 G2
H1 H1 H2 H2 H2
#7:
L2 L2 Z1 Z1 G1
E2 L2 L1 L1 Z2 G1 G2
E2 E2 E1 E1 Z2 G2 G2
H1 H1 H2 H2 H2
#16/(~3):
L2 L2 L1 L1 G1
E2 L2 Z1 Z1 Z2 G1 G2
E2 E2 E1 E1 Z2 G2 G2
H2 H2 H2 H1 H1
(~7)
L2 L2 Z1 Z1 G1
E2 L2 L1 L1 Z2 G1 G2
E2 E2 E1 E1 Z2 G2 G2
H2 H2 H2 H1 H1
(~13)
L2 L2 Z1 Z1 Z2
E2 L2 L1 L1 G1 Z2 G2
E2 E2 E1 E1 G1 G2 G2
H1 H1 H2 H2 H2
#13:
L2 L2 Z1 Z1 Z2
E2 L2 L1 L1 G1 Z2 G2
E2 E2 E1 E1 G1 G2 G2
H2 H2 H2 H1 H1
(~25)
Z2 L1 L1 L2 L2
E2 Z2 Z1 Z1 L2 G2 G1
E2 E2 E1 E1 G2 G2 G1
H1 H1 H2 H2 H2
(~9)
Z2 Z1 Z1 L2 L2
E2 Z2 L1 L1 L2 G2 G1
E2 E2 E1 E1 G2 G2 G1
H1 H1 H2 H2 H2
#25:
Z2 L1 L1 L2 L2
E2 Z2 Z1 Z1 L2 G2 G1
E2 E2 E1 E1 G2 G2 G1
H2 H2 H2 H1 H1
#9:
Z2 Z1 Z1 L2 L2
E2 Z2 L1 L1 L2 G2 G1
E2 E2 E1 E1 G2 G2 G1
H2 H2 H2 H1 H1
#26:
L1 L1 L2 L2 G2
Z2 Z1 Z1 L2 G2 G2 G1
Z2 E2 E1 E1 H1 H1 G1
E2 E2 H2 H2 H2
#2/(~20):
H1 H1 H2 H2 H2
L2 L2 L1 L1 Z1 Z1 Z2
L2 E2 E1 E1 G2 G1 Z2
E2 E2 G2 G2 G1
#20/(~2):
H2 H2 H2 H1 H1
L2 L2 L1 L1 Z1 Z1 Z2
L2 E2 E1 E1 G2 G1 Z2
E2 E2 G2 G2 G1
#23:
L1 L1 H2 H2 H2
L2 L2 H1 H1 Z1 Z1 Z2
L2 E2 E1 E1 G2 G1 Z2
E2 E2 G2 G2 G1
#31:
L1 L1 H1 H1 G1
L2 L2 H2 H2 H2 G1 G2
L2 Z2 E1 E1 E2 G2 G2
Z2 Z1 Z1 E2 E2
#A3:
G2 G1 L2 L2 E2
G2 G2 G1 L2 Z2 E2 E2
H1 H1 L1 L1 Z2 E1 E1
H2 H2 H2 Z1 Z1
(~37)
L1 L1 G1 Z2 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 Z1 Z1 E1 E1
H1 H1 H2 H2 H2
#37:
L1 L1 G1 Z2 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 Z1 Z1 E1 E1
H2 H2 H2 H1 H1
#35:
L1 L1 G2 G1 E2
L2 L2 G2 G2 G1 E2 E2
L2 Z2 H2 H2 H2 E1 E1
Z2 Z1 Z1 H1 H1
#5:
L1 L1 Z1 Z1 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 G1 Z2 E1 E1
H1 H1 H2 H2 H2
(~5)
L1 L1 Z1 Z1 E2
L2 L2 G2 G1 Z2 E2 E2
L2 G2 G2 G1 Z2 E1 E1
H2 H2 H2 H1 H1
#44:
L1 L1 L2 L2 E2
H2 H2 H2 L2 Z2 E2 E2
H1 H1 G2 G1 Z2 E1 E1
G2 G2 G1 Z1 Z1
#30:
Z2 Z1 Z1 L2 L2
G1 Z2 G2 E2 L2 L1 L1
G1 G2 G2 E2 E2 E1 E1
H1 H1 H2 H2 H2
(~30)
Z2 Z1 Z1 L2 L2
G1 Z2 G2 E2 L2 L1 L1
G1 G2 G2 E2 E2 E1 E1
H2 H2 H2 H1 H1
#27:
G2 G1 Z2 L2 L2
G2 G2 G1 Z2 L2 L1 L1
H1 H1 Z1 Z1 E2 E1 E1
H2 H2 H2 E2 E2
#39:
L1 L1 G1 H1 H1
L2 L2 G2 G1 H2 H2 H2
L2 G2 G2 Z2 E2 E1 E1
Z1 Z1 Z2 E2 E2
#48:
G2 Z1 Z1 L2 L2
G2 G2 G1 Z2 L2 L1 L1
H1 H1 G1 Z2 E2 E1 E1
H2 H2 H2 E2 E2
#45:
L1 L1 H2 H2 H2
L2 L2 Z2 Z1 Z1 H1 H1
L2 G1 Z2 G2 E2 E1 E1
G1 G2 G2 E2 E2
#24:
Z1 Z1 Z2 L2 L2
H2 H2 H2 Z2 L2 L1 L1
H1 H1 G2 G1 E2 E1 E1
G2 G2 G1 E2 E2
#18:
L2 L2 L1 L1 G1
E2 L2 Z1 Z1 Z2 G1 G2
E2 E2 H1 H1 Z2 G2 G2
E1 E1 H2 H2 H2
#15:
L2 L2 Z1 Z1 G1
E2 L2 L1 L1 Z2 G1 G2
E2 E2 H1 H1 Z2 G2 G2
E1 E1 H2 H2 H2
#47:
L2 L2 L1 L1 G1
E2 L2 Z2 Z1 Z1 G1 G2
E2 E2 Z2 H1 H1 G2 G2
E1 E1 H2 H2 H2
#10:
L2 L2 Z1 Z1 Z2
E2 L2 L1 L1 G1 Z2 G2
E2 E2 H1 H1 G1 G2 G2
E1 E1 H2 H2 H2
#40:
L1 L1 L2 L2 G2
E2 H1 H1 L2 G2 G2 G1
E2 E2 H2 H2 H2 Z2 G1
E1 E1 Z1 Z1 Z2
#29:
L2 L2 L1 L1 G2
E2 L2 H1 H1 G2 G2 G1
E2 E2 H2 H2 H2 Z2 G1
E1 E1 Z1 Z1 Z2
#A4:
Z2 L1 L1 L2 L2
E2 Z2 Z1 Z1 L2 G2 G1
E2 E2 H1 H1 G2 G2 G1
E1 E1 H2 H2 H2
#33:
Z2 Z1 Z1 L2 L2
E2 Z2 L1 L1 L2 G2 G1
E2 E2 H1 H1 G2 G2 G1
E1 E1 H2 H2 H2
#41:
L1 L1 H1 H1 G1
L2 L2 H2 H2 H2 G1 G2
L2 Z2 Z1 Z1 E2 G2 G2
Z2 E1 E1 E2 E2
#28:
H1 H1 H2 H2 H2
Z2 Z1 Z1 G2 G1 L1 L1
Z2 E2 G2 G2 G1 L2 L2
E2 E2 E1 E1 L2
(~28)
H2 H2 H2 H1 H1
Z2 Z1 Z1 G2 G1 L1 L1
Z2 E2 G2 G2 G1 L2 L2
E2 E2 E1 E1 L2
So there are 64 solutions, 46 of which are in the official problem set (two twice), there are 4 additional solutions (marked by #An), and 14 more are just transpositions of the two hippos in the same row (marked by ~n). Since there are 3 hippo-pairs in the official set, as well, there are 46 - 3 + 4 = 47 (substantively) different solutions.
Minimal problems for the additional solutions:
[A1]
. . HHHHH
. . . . . . .
. . . . . . .
. . ZZZ .
[A2]
. . Z . .
. . . Z . . .
. . HHH . . .
. . . . .
[A3]
. . . . .
. . . . . . .
. . LLL . . .
. . . . .
[A4]
. . . . .
. . HHH . . .
. . . . . Z .
. . . . Z