Search code examples
prolog

If I ask for X, it generates duplicates, but it fails on duplicates if I ask explicitly


I am trying to generate pieces on a board at specific positions. One requirement is no two pieces can occupy the same position. So the board as a list, cannot contain duplicate entries for it's position value.

I failed to remove the duplicates in generation part, otherwise it correctly fails on duplicates if I ask it explicitly.

role(k).
role(r).

color(w).
color(b).

piece(X-Y) :- color(X), role(Y).

piese(X-Y) :- piece(X), pos_(Y).

piese_pos(X, Y) :- X=_-_-Y.

board(Ps) :- maplist(piese_pos, Ps, Ls), is_set(Ls), maplist(piese, Ps).

pos_(a-1).
pos_(a-2).
/*
When I ask board board(X). This is one of the enumerations:
X = [w-k-(a-1), b-k-(a-2), w-r-(a-2)] ;
as you can see a-2 is duplicated.

But if I ask for a duplicate explicitly, it returns false as correct.
[11]  ?- board([w-k-(a-1), b-r-(a-1)]).
false.

[11]  ?- board([w-k-(a-1), b-r-(a-2)]).
true.
*/

% https://stackoverflow.com/a/9007359/3994249
is_set(Lst) :-
  setof(X, member(X, Lst), Set),
  length(Lst, N),
  length(Set, N).

Solution

  • Assuming that every position on the board must have a piece, you can generate boards with the following code:

    board(Ps) :-
        setof(P, pos_(P), Ls),     
        maplist(piese_pos, Ps, Ls),
        maplist(piese, Ps).
    

    Example:

    ?- board(Ps).
    Ps = [w-k-(a-1), w-k-(a-2)] ;
    Ps = [w-k-(a-1), w-r-(a-2)] ;
    Ps = [w-k-(a-1), b-k-(a-2)] ;
    Ps = [w-k-(a-1), b-r-(a-2)] ;
    Ps = [w-r-(a-1), w-k-(a-2)] ;
    Ps = [w-r-(a-1), w-r-(a-2)] ;
    Ps = [w-r-(a-1), b-k-(a-2)] ;
    Ps = [w-r-(a-1), b-r-(a-2)] ;
    Ps = [b-k-(a-1), w-k-(a-2)] ;
    Ps = [b-k-(a-1), w-r-(a-2)] ;
    Ps = [b-k-(a-1), b-k-(a-2)] ;
    Ps = [b-k-(a-1), b-r-(a-2)] ;
    Ps = [b-r-(a-1), w-k-(a-2)] ;
    Ps = [b-r-(a-1), w-r-(a-2)] ;
    Ps = [b-r-(a-1), b-k-(a-2)] ;
    Ps = [b-r-(a-1), b-r-(a-2)].
    

    Otherwise, you can use this other definition:

    board(Ps) :-
        setof(P, pos_(P), S),
        set_subset(S, Ls),
        maplist(piese_pos, Ps, Ls),
        maplist(piese, Ps).
    
    set_subset([], []).
    set_subset([X|Xs], S) :-
        set_subset(Xs, T),
        (   S = T
        ;   S = [X|T] ).
    

    Example:

    ?- board(Ps).
    Ps = [] ;
    Ps = [w-k-(a-1)] ;
    Ps = [w-r-(a-1)] ;
    Ps = [b-k-(a-1)] ;
    Ps = [b-r-(a-1)] ;
    Ps = [w-k-(a-2)] ;
    Ps = [w-r-(a-2)] ;
    Ps = [b-k-(a-2)] ;
    Ps = [b-r-(a-2)] ;
    Ps = [w-k-(a-1), w-k-(a-2)] ;
    Ps = [w-k-(a-1), w-r-(a-2)] ;
    Ps = [w-k-(a-1), b-k-(a-2)] ;
    Ps = [w-k-(a-1), b-r-(a-2)] ;
    Ps = [w-r-(a-1), w-k-(a-2)] ;
    Ps = [w-r-(a-1), w-r-(a-2)] ;
    Ps = [w-r-(a-1), b-k-(a-2)] ;
    Ps = [w-r-(a-1), b-r-(a-2)] ;
    Ps = [b-k-(a-1), w-k-(a-2)] ;
    Ps = [b-k-(a-1), w-r-(a-2)] ;
    Ps = [b-k-(a-1), b-k-(a-2)] ;
    Ps = [b-k-(a-1), b-r-(a-2)] ;
    Ps = [b-r-(a-1), w-k-(a-2)] ;
    Ps = [b-r-(a-1), w-r-(a-2)] ;
    Ps = [b-r-(a-1), b-k-(a-2)] ;
    Ps = [b-r-(a-1), b-r-(a-2)].