Solving Noah’s Ark

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.

solve(Problem) :-
    setup(Problem, State, Animals),
    solve(Animals, State, Solution),
    show(Solution).
solve([], State, State).
solve([A|Animals], State, Solution) :-
    position(P),
    place(A, P, State, State1),
    solve(Animals, State1, Solution).

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):

position(X-Y) :-
    between(1, 4, Y),
    between(1, 7, X),
    \+ 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.

Representation

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:

animal(elephant-1, [1-0]).
animal(elephant-2, [0-1,1-1]).
animal(giraffe-1, [0-1]).
animal(giraffe-2, [0-1,(-1)-1]).
animal(hippo-1, [1-0]).
animal(hippo-2, [1-0,2-0]).
animal(lion-1, [1-0]).
animal(lion-2, [1-0,0-1]).
animal(zebra-1, [1-0]).
animal(zebra-2, [0-1]).

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)]).

Setup

Now we can do the initial setup:

setup(Problem, State, Animals) :-
    findall(a(A,L), animal(A, L), As),
    setup(Problem, [], As, State, Animals).
setup([], State, Animals, State, Animals).
setup([set(A,P)|Problem], S, As, State, Animals) :-
    select(a(A,L), As, As1),
    place(a(A,L), P, S, S1),
    setup(Problem, S1, As1, State, Animals).

Here setup/3 takes all the animals “in hand”, and places them one by one at the specified positions.

Placement

Next we need the rule for placing a tile on the board:

place(a(A-N,L), Pos, State, State1) :-
    place(A-N, [0-0|L], Pos, State, State1),
    check(A, State1), !.
place(_, [], _, State, State).
place(A, [X-Y|L], X0-Y0, State, State1) :-
    X1 is X0 + X, Y1 is Y0 + Y,
    position(X1-Y1),
    \+ member(tile(_,X1-Y1), State),
    place(A, L, X0-Y0, [tile(A,X1-Y1)|State], State1).

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:

  1. Only the one of the male and female is present on the board.

  2. There are two adjacent squares that belong to the male and female of the specified animal.

Translated to Prolog this becomes:

check(A, State) :- \+ member(tile(A-1,_), State).
check(A, State) :- \+ member(tile(A-2,_), State).
check(A, State) :-
    member(tile(A-1,P1), State),
    member(tile(A-2,P2), State),
    adjacent(P1, P2).

where adjacency is

adjacent(X1-Y1, X2-Y2) :- X1 = X2, abs(Y1-Y2) =:= 1.
adjacent(X1-Y1, X2-Y2) :- Y1 = Y2, abs(X1-X2) =:= 1.

Output

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:

show(Tiles) :- nl,
    position(Pos),
    member(tile(Name-N,Pos), Tiles),
    abbreviation(Name, Abbrev),
    ( member(Pos, [2-1,2-4]) -> write('   ') ; true ),
    write(Abbrev), write(N), write(' '),
    ( member(Pos, [6-1,7-2,7-3,6-4]) -> nl ; true ),
    fail.

abbreviation(elephant, 'E').
abbreviation(giraffe, 'G').
abbreviation(hippo, 'H').
abbreviation(lion, 'L').
abbreviation(zebra, 'Z').

Note that special handling is needed for

Tests

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

The whole program

solve(Problem) :-
    setup(Problem, State, Animals),
    solve(Animals, State, Solution),
    show(Solution).
solve([], State, State).
solve([A|Animals], State, Solution) :-
    position(P),
    place(A, P, State, State1),
    solve(Animals, State1, Solution).

position(X-Y) :-
    between(1, 4, Y),
    between(1, 7, X),
    \+ member(X-Y, [1-1,7-1,1-4,7-4]).

animal(elephant-1, [1-0]).
animal(elephant-2, [0-1,1-1]).
animal(giraffe-1, [0-1]).
animal(giraffe-2, [0-1,(-1)-1]).
animal(hippo-1, [1-0]).
animal(hippo-2, [1-0,2-0]).
animal(lion-1, [1-0]).
animal(lion-2, [1-0,0-1]).
animal(zebra-1, [1-0]).
animal(zebra-2, [0-1]).

setup(Problem, State, Animals) :-
    findall(a(A,L), animal(A, L), As),
    setup(Problem, [], As, State, Animals).
setup([], State, Animals, State, Animals).
setup([set(A,P)|Problem], S, As, State, Animals) :-
    select(a(A,L), As, As1),
    place(a(A,L), P, S, S1),
    setup(Problem, S1, As1, State, Animals).

place(a(A-N,L), Pos, State, State1) :-
    place(A-N, [0-0|L], Pos, State, State1),
    check(A, State1), !.
place(_, [], _, State, State).
place(A, [X-Y|L], X0-Y0, State, State1) :-
    X1 is X0 + X, Y1 is Y0 + Y,
    position(X1-Y1),
    \+ member(tile(_,X1-Y1), State),
    place(A, L, X0-Y0, [tile(A,X1-Y1)|State], State1).

check(A, State) :- \+ member(tile(A-1,_), State).
check(A, State) :- \+ member(tile(A-2,_), State).
check(A, State) :-
    member(tile(A-1,P1), State),
    member(tile(A-2,P2), State),
    adjacent(P1, P2).

adjacent(X1-Y1, X2-Y2) :- X1 = X2, abs(Y1-Y2) =:= 1.
adjacent(X1-Y1, X2-Y2) :- Y1 = Y2, abs(X1-X2) =:= 1.

show(Tiles) :- nl,
    position(Pos),
    member(tile(Name-N,Pos), Tiles),
    abbreviation(Name, Abbrev),
    ( member(Pos, [2-1,2-4]) -> write('   ') ; true ),
    write(Abbrev), write(N), write(' '),
    ( member(Pos, [6-1,7-2,7-3,6-4]) -> nl ; true ),
    fail.

abbreviation(elephant, 'E').
abbreviation(giraffe, 'G').
abbreviation(hippo, 'H').
abbreviation(lion, 'L').
abbreviation(zebra, 'Z').

Unique solution with 1 animal?

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 :-
    animal(A, _),
    position(P),
    setup([set(A,P)], I, L),
    findall(S, solve(L, I, S), [X]),
    nl, write('Place '), write(A),
    write(' at '), write(P), write(':'), nl,
    show(X).

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.

Different solutions?

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