/********************************************************************
    Constraint-based Graphical Programming in B-Prolog
    %
    n-queen puzzle
*********************************************************************/
go:-
    cgWindow(Win,"queens"),Win^topMargin #= 40,
    Win^leftMargin #= 10,
    handleWindowClosing(Win),
    queens(Win).

handleWindowClosing(Win),{windowClosing(Win)} => cgClose(Win).

queens(Win):-
    cgLabel(Lab,"N=?"),
    cgTextField(Tf,"50",4),
    cgLeft(Lab,Tf),
    Tf^bottomY+10 #= Y0, % draw board below Y0
    cgSame([Lab,Tf],window,Win),
    cgShow([Lab,Tf]),
    handleInputN(Tf,Win,Y0),
    searchAndDrawQueens(Tf,Win,Y0).

handleInputN(Tf,Win,Y0),
    {actionPerformed(Tf)}
    =>
    searchAndDrawQueens(Tf,Win,Y0).

searchAndDrawQueens(Tf,Win,Y0):-
    cgCleanDrawing(Win),
    cgGetText(Tf,NString),
    number_codes(N,NString),
    queens(N,Qs),!,
    drawQueens(N,Qs,Comps,Y0),
    cgSame(Comps,window,Win),
    cgShow(Comps).

queens(N,List):-
    length(List,N),
    List in 1..N,
    constrain_queens(List),
    labeling_ff(List).

constrain_queens([]).
constrain_queens([X|Y]):-
    safe(X,Y,1),
    constrain_queens(Y).

safe(_,[],_).
safe(X,[Y|T],K):-
    noattack(X,Y,K),
    K1 is K+1,
    safe(X,T,K1).

noattack(X,Y,K):-
    X #\= Y,
    X+K #\= Y,
    X-K #\= Y.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
drawQueens(N,Qs,Comps,Y0):-
    drawQueens(0,Qs,Comps,Comps1,Y0),
    drawBoard(N,Comps1,[],Y0).

drawBoard(N,Comps,CompsR,Y0):-
    drawHorizontalLines(0,N,Comps,Comps1,Y0),
    drawVerticalLines(0,N,Comps1,CompsR,Y0).

drawHorizontalLines(I,N,Comps,CompsR,Y0):-I>N,!,Comps=CompsR.
drawHorizontalLines(I,N,Comps,CompsR,Y0):-
    cgLine(Line),
    Line^x1 #= 10, Line^y1 #= 5*I+Y0,
    Line^x2 #= 5*N+10, Line^y2 #= Line^y1,
    Comps=[Line|Comps1],
    I1 is I+1,
    drawHorizontalLines(I1,N,Comps1,CompsR,Y0).

drawVerticalLines(I,N,Comps,CompsR,Y0):-I>N,!,Comps=CompsR.
drawVerticalLines(I,N,Comps,CompsR,Y0):-
    cgLine(Line),
    Line^x1 #= 5*I+10, Line^y1 #= Y0,
    Line^x2 #= Line^x1, Line^y2 #= N*5+Y0,
    Comps=[Line|Comps1],
    I1 is I+1,
    drawVerticalLines(I1,N,Comps1,CompsR,Y0).
    
drawQueens(_I,[],Comps,CompsR,Y0):-Comps=CompsR.
drawQueens(I,[J|Js],Comps,CompsR,Y0):-
    cgSquare(S),
    S^x #= I*5+10,
    S^y #= (J-1)*5+Y0,
    S^width #= 5,
    S^height #= 5,
    S^color #= red,
    Comps=[S|Comps1],
    I1 is I+1,
    drawQueens(I1,Js,Comps1,CompsR,Y0).
