prolog

Prolog - Applying predicate with one fixed arguments over list


I'm trying to write a program to solve the n-queens problem. To check if a queen attacks the other that are stored in a list L as lists with their coordinates ([X,Y], etc...), I wrote this piece of code :

safe_queens([X1,Y1],[X2,Y2]) :-
    X1 \== X2,
    Y1 \== Y2,
    abs(X1 - X2) \== abs(Y1 - Y2).

no_attack([_,_],[]).
no_attack(R0,[R|L]) :-
    maplist(safe_queens(R0,_),L)
    no_attack(R,L).

safe_queens checks if 2 queens cannot attack each other. I want to apply safe_queens for a queen R0 over the rest of the list.

How can I freeze R0 as one argument of the predicate, and let the other takes its value in the list L ?


Solution

  • You can do so by building another predicate to loop through the list and apply safe_queens on each element with R0 Like This:

    safe_queens([X1,Y1],[X2,Y2]) :-
        X1 \== X2,
        Y1 \== Y2,
        abs(X1 - X2) \== abs(Y1 - Y2).
    
    mapThroughList(_,[]).
    mapThroughList(R0,[H|T]):-
        safe_queens(R0,H),
        mapThroughList(R0,T).
    
    no_attack([_,_],[]).
    no_attack(R0,[R|L]) :-
        mapThroughList(R0,[R|L]),
        no_attack(R,L).
    

    Also, this is a solution for the N-Queen Problem you can find this code:

    solve(N,P) :-
        numlist(0,N,NL),
        permutation(NL,P),
        diagonals(NL,P,S,D),
        all_diff(S),
        all_diff(D). 
    
    diagonals([],[],[],[]).
    diagonals([X1|X],[Y1|Y],[S1|S],[D1|D]):- 
        S1 is X1 + Y1,
        D1 is X1- Y1,
        diagonals(X,Y,S,D).
    
    all_diff([_]).
    all_diff([X|Y]) :-
        \+member(X,Y),
        all_diff(Y).