view 3-Prolog/day3-8queens.pl @ 65:69eb40c46798

Add some "Eight Queens" solving Still trying to get my head in quite the right space.
author IBBoard <dev@ibboard.co.uk>
date Sun, 01 Oct 2017 19:59:48 +0100
parents
children
line wrap: on
line source

% Eight Queens problem, written from just the rules and a few hints on available approaches
% which includes the "member/2" and other useful functions.
% This will be MUCH more succinct than defining the entire board and trying
% to operate on that! Half of the problem is approaching the problem correctly.

eight_queens(List) :-
    % Check we've got the right length
    length(List, 8),
    % Check our values are all valid positions
    valid_board(List),
    % Pull out the rows
    rows(List, Rows),
    % Pull out the columns
    columns(List, Cols),
    % Pull out the diagonals (North-East/South-West)
    diagonals_sw_ne(List, Diags1),
    % Pull out the diagonals (North-West/South-East)
    diagonals_nw_se(List, Diags2),

    % Make sure we have no duplicates - based on the simple Sudoku solver
    fd_all_different(Rows),
    fd_all_different(Cols),
    fd_all_different(Diags1),
    fd_all_different(Diags2).

valid_board([]).
valid_board([Head|Tail]) :- valid_queen(Head), valid_board(Tail).

% Queen location defined as a tuple
valid_queen((Row, Col)) :-
    Range = [1,2,3,4,5,6,7,8],
    member(Row, Range), member(Col, Range).

rows([], []).
% This is a bit weird - Tail on the left matches and populates Tail on the right
% Then we invoke the sub-goal and generate RowTail recursively, which populates
% RowTail on the left. Easier than assignment, and probably tail recursive.
rows([(Row, _)|Tail], [Row|RowTail]) :- rows(Tail, RowTail).

columns([], []).
columns([(_, Col)|Tail], [Col|ColTail]) :- columns(Tail, ColTail).

diagonals_nw_se([], []).
% Diagonals intersec the axis at consistent places, which we can approximate with Row + Col
diagonals_nw_se([(Row,Col)|Tail], [Diag|DiagTail]) :- Diag is Row + Col, diagonals_nw_se(Tail, DiagTail).

diagonals_sw_ne([], []).
% Ditto the other diagonal, but use Row - Col because they slope the other way
diagonals_sw_ne([(Row,Col)|Tail], [Diag|DiagTail]) :- Diag is Row - Col, diagonals_sw_ne(Tail, DiagTail).