2

I am studying Prolog for an universitary exame and I have some problem with the following exercise.

I have the following classic solution of 8-Queens problem (and this is not a problem for me), Modifying this solution I have to create a new solution for the more generic n-Queens problem that handle a variable number of queens.

solution([]).

solution([X/Y|Others]) :- solution(Others),
                          member(Y,[1,2,3,4,5,6,7,8]),
                          noattack(X/Y, Others).

noattack(_,[]).

noattack(X/Y, [X1/Y1 | Others]) :-
                      Y =\= Y1,       % Q e Q1 sono su righe diverse
                      % Q e Q1 sono su diagonali diverse:
                      Y1-Y =\= X1-X,
                      Y1-Y =\= X-X1,
                      % Q non attacca regine nella sottolista Others:
                      noattack( X/Y, Others).

% TEMPLATE DELLE SOLUZIONI: c'è una regina su ogni colonna:
template([1/Y1,2/Y2,3/Y3,4/Y4,5/Y5,6/Y6,7/Y7,8/Y8]).

Ok, this program look pretty simple: I have a list of queen that have that they must not attack each other.

If the list of queen is empty there is not the possibility that a queen attack another queen in the list, so the empty list is a solution of the problem (it is the base case of the solution)

*If the list of queen is not empty I can divide it into [X/Y|Others] where X/Y rappresent position on the board of the first queen in the list *(the position is rappresentend by the couple (X,Y) where X is the column and Y the line)

So, it is TRUE that the list [X/Y|Others] is a SOLUTION of the problem if the following relations are true:

  1. The sublist Others is itself a solution (Others don't contain queen that attack some other queen in the list)

  2. Y belongs belongs to an integer value between 1 and 8 (because I have 8 line)

  3. The first queen of the list don't attacck the others queens in the sublist Others

Then it is defined the noattack relation that specify when I can say that it is true that a queen don't attack another queen (this is pretty simple: they can't stay on the same line, on the same column, on the same diagonal)

Finally I have a solution template that simplify my life constraining the X value with value from 1 to 8 (because I know that 2 queens can't stay on the same columns...so every queen in the solution stay on a different column from all others queens)

So I think that the biggest problem it is on the line in which I specify the number of columns:

member(Y,[1,2,3,4,5,6,7,8])

and on the line in which I define the solution template:

template([1/Y1,2/Y2,3/Y3,4/Y4,5/Y5,6/Y6,7/Y7,8/Y8]).

I have no idea about how to extend the previous solution to handle a variable number of queens.

false
  • 10,264
  • 13
  • 101
  • 209
AndreaNobili
  • 40,955
  • 107
  • 324
  • 596

1 Answers1

2

seems easy, passing around the size:

solution(_, []).
solution(N, [X/Y|Others]) :-
    solution(N, Others),
    between(1, N, Y),
    noattack(X/Y, Others).

noattack(_,[]).
noattack(X/Y, [X1/Y1 | Others]) :-
    Y =\= Y1,       % Q e Q1 sono su righe diverse
    Y1-Y =\= X1-X,  % Q e Q1 sono su diagonali diverse
    Y1-Y =\= X-X1,
    noattack( X/Y, Others). % Q non attacca regine nella sottolista Others

% TEMPLATE DELLE SOLUZIONI: c'è una regina su ogni colonna:
template(N, L) :-
    findall(I/_, between(1,N,I), L).

test:

?- N=6, template(N, L), solution(N, L).
N = 6,
L = [1/5, 2/3, 3/1, 4/6, 5/4, 6/2] ;
N = 6,
L = [1/4, 2/1, 3/5, 4/2, 5/6, 6/3] ;
N = 6,
L = [1/3, 2/6, 3/2, 4/5, 5/1, 6/4] ;
N = 6,
L = [1/2, 2/4, 3/6, 4/1, 5/3, 6/5] ;
false.

(I should draw it to say if it's ok...)

CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Tnx so much. Thank you for the help and for your time. I have just two dobuts about how it work: – AndreaNobili Apr 06 '13 at 15:19
  • 1) To be true that solution(N, [X/Y|Others]) (the list [X/Y|Others] composed by N queens is a solution) you add that have to be true that: between(1, N, Y) in place of the member(Y,[1,2,3,4,5,6,7,8]). This simply day that Y (the number of columns) ar to be >1 and – AndreaNobili Apr 06 '13 at 15:26
  • 2) The second doubt is related to how you build the solution template in the N queens case...I think that the meaning it is similar to the hold template in which I had a list like: [1/Y1,2/Y2,....,8/Y8]. But in this case I can't have a "static" list but the list have to be instantiated with a variable number of positions (N positions). So you do: template(N, L) :- findall(I/_, between(1,N,I), L). but what exactly mean? I think that findall create dinamically the list...the list is composed by couple (X,Y) where X rappresent the line index and Y the column index. – AndreaNobili Apr 06 '13 at 15:35
  • Ok...as in the old 8 queen example I have a template list (created by findall? is it right?) that every queen is on a different line so I have that every queen are in position I/_ where I is a number from 1 to N (so if N=3 I have a template list like [1/_,2/,3/_]. The doubts are: why the Y value are _ and not Y? and the second doubts are: L rappresent the List created by findall? Tnx so much – AndreaNobili Apr 06 '13 at 15:40
  • 1
    1) in Prolog we have *relations*, and happens that both member/2, as you wrote it, and between/3 denote the same relation. It was possible to use `numlist(1, N, L), member(Y, L)`, but I prefer simpler solutions, when I know of. 2) each `_` resulting in the output list of findall is independent, exactly as Y1,Y2, etc..., and the essential purpose of them it that of 'free' slots to valorize by search. So findall/3 is handy. It's the 'list comprehension' of Prolog.... – CapelliC Apr 06 '13 at 15:51