/*

Taken from the 

       4th Annual Prolog programming contest 
              9 July 1997, Leuven 


You get an NxM (N and M differ from 0) matrix filled with the colours
black and white. The blacks are background; a connected component of
whites form a shape. You are to determine the number of shapes in the
matrix. Two white entries of the matrix belong to the same shape if
there is a path from one to the other over whites; a path consist of
successive points with coordinates (i,j) and (k,l) such that |i-k| =<
1 and |j-l| =< 1.

The matrix is given as a list of lists which contains elements equal
to black or white - this should be obvious from the examples - as the
first argument of the predicate shapes/2 that you have to write. The
second argument should be unified with the number of shapes in the
first argument. Here are some example calls:


?- shapes([[black,white,black], 
          [white,black,black], 
          [white,black,white]],N). 

N = 2 


?- shapes([[white,white,white], 
           [white,black,black], 
           [white,black,black], 
           [white,black,black]],N). 


N = 1 

A hint: you need no arithmetic at all :-) 

----------------------------------------------------

The solution given below assumes the matrix is at least 2x2.

This solution uses the Prolog builtin numbervars/3 which might
be a problem for some termination analyzers. One could either
provide code for this predicate (there is a challange of this
in numbervars.pl); or inform the analyzer that numbervars as
a builtin always terminates

*/

:- shapes(i,o).


shapes(Matrix,N) :- 
        varmat(Matrix,MatrixWithVars),
        unif_matrx(MatrixWithVars),
        numbervars(MatrixWithVars,0,N).

varmat([],[]).
varmat([L|Ls], [VL|VLs]) :-
        varmat(L,VL),
        varmat(Ls,VLs).
varmat([black|Xs],[black|VXs]) :-
        varmat(Xs,VXs).
varmat([white|Xs],[w(_)|VXs]) :-
        varmat(Xs,VXs).

unif_matrx([ L1, L2 | Ls]) :-
        unif_lines(L1,L2),
        unif_matrx([L2|Ls]).
unif_matrx([_]).

unif_lines( [W,X|L1s],
            [Y,Z|L2s]) :-
        unif_pairs([W,X, Y,Z,  W,Y,  X,Z, W,Z, X,Y]),
        unif_lines([X|L1s],
                   [Z|L2s]).
unif_lines( [_],[_] ).


unif_pairs([]).
unif_pairs([A,B| Pairs] ) :-
        unif(A,B),
        unif_pairs(Pairs).

unif(w(A),w(A)).
unif(black,black).
unif(black,w(_)).
unif(w(_),black).

