/******************************************************************** Constraint-based Graphical Programming in B-Prolog % find tours for a knight, by Wenju Cheng *********************************************************************/ go:- global_set(num,0), cgWindow(W,"Knight by Wen-Ju Cheng"), W^width #= 780, W^height #= 680, cgButton(B,"go"), B^x #= 630, B^y #= 200, B^width #= 100, B^height #= 50, handleButtonClick(W,B), cgButton(R,"reset"), R^x #= 630, R^y #= 400, R^width #= 100, R^height #= 50, drawBoard(8,Comps,[]), Os=[B,R|Comps], cgSame(Os,window,W), handleButtonResetClick(W,R,Os), cgShow(Os), getValue(W). handleButtonClick(Win,B),{actionPerformed(B)} => (global_get(num,2)-> global_get(pos,1,Y), global_get(pos,2,X), solve([(X,[],Cost)],[X],Y,Knights), drawKnights(Win,[Y|Knights]); true). handleButtonResetClick(W,R,Os),{actionPerformed(R)} => cgClean(W), global_set(num,0), cgShow(Os). getValue(W):- handleWindowClosing(W), handleMouseEvent(W). handleMouseEvent(W),{mousePressed(W,E)}=> E^x #= X, E^y #= Y, global_get(num,N), mouseClicked(W,N,X,Y). mouseClicked(Win,N,X,Y):- X > 100, X < 580, Y > 100, Y < 580, Px is (X-100)//60+1, Py is (Y-100)//60+1, !, mouseClicked2(Win,N,Px,Py). mouseClicked(Win,N,X,Y). mouseClicked2(W,N,Px,Py):- N<2,!, N1 is N+1, global_set(pos,N1,(Py,Px)), global_set(num,N1), cgCircle(S),S^window#=W, S^centerX #= (Px-1)*60+100+30, S^centerY #= (Py-1)*60+100+30, S^diameter #= 50, S^color #= red, cgShow(S). mouseClicked2(W,N,Px,Py). solve(A1,A2,Y,Path):- solve1(A1,A2,Y,Path),!. solve1([(Y,Path,Cost)|Open],Closed,Y,Path):-!. solve1([(X,Path,Cost)|Open],Closed,Y,Path1):- next(X,Next), delete(Next,Closed,New), append(New,Closed,Closed1), cost(Y,X,Path,New,New1), insert(New1,Open,Open1), solve1(Open1,Closed1,Y,Path1). next((I,J),[(I1,J1),(I2,J2),(I3,J3),(I4,J4),(I5,J5),(I6,J6),(I7,J7),(I8,J8)]):- I1 is I+1,J1 is J-2,I2 is I+1,J2 is J+2,I3 is I+2,J3 is J-1, I4 is I+2,J4 is J+1,I5 is I-1,J5 is J-2,I6 is I-1,J6 is J+2, I7 is I-2,J7 is J-1,I8 is I-2,J8 is J+1. delete([],_,[]). delete([(I,J)|Next],Closed,[(I,J)|New]):- I>0,J>0,I<9,J<9,not member((I,J),Closed),!,delete(Next,Closed,New). delete([X|Next],Closed,New):- delete(Next,Closed,New). cost(_,_,_,[],[]). cost((I,J),X,Path,[(I1,J1)|New],[((I1,J1),Path1,Cost)|NewNode]):- DI is abs(I1-I), DJ is abs(J1-J), Path1 = [X|Path], length(Path1,N), Cost is DI+DJ+N, cost((I,J),X,Path,New,NewNode). insert([],Open,Open). insert([X|New],Open,Open1):- insert(New,Open,Open2), insert_X(X,Open2,Open1). insert_X((X,Path,Cost),[(Y,YPath,YCost)|Open],[(Y,YPath,YCost)|Open1]):- Cost>YCost,!,insert_X((X,Path,Cost),Open,Open1). insert_X(X,Y,[X|Y]). drawKnights(Win,Knights):- drawLine(Knights,Comps,Comps1), drawKnights(Knights,Comps1,[]),!, cgSame(Comps,window,Win), cgShow(Comps). drawBoard(N,Comps,CompsR):- drawHorizontalLines(0,N,Comps,Comps1), drawVerticalLines(0,N,Comps1,CompsR). drawHorizontalLines(I,N,Comps,CompsR):-I>N,!,Comps=CompsR. drawHorizontalLines(I,N,Comps,CompsR):- cgLine(Line), LM #= 100, TM #= 100, Line^x1 #= LM, Line^y1 #= 60*I+TM, Line^x2 #= 60*N+LM, Line^y2 #= Line^y1, Comps=[Line|Comps1], I1 is I+1, drawHorizontalLines(I1,N,Comps1,CompsR). drawVerticalLines(I,N,Comps,CompsR):-I>N,!,Comps=CompsR. drawVerticalLines(I,N,Comps,CompsR):- cgLine(Line), LM #= 100, TM #= 100, Line^x1 #= 60*I+LM, Line^y1 #= TM, Line^x2 #= Line^x1, Line^y2 #= N*60+TM, Comps=[Line|Comps1], I1 is I+1, drawVerticalLines(I1,N,Comps1,CompsR). drawKnights([],Comps,CompsR):-Comps=CompsR. drawKnights([(J,I)|Knights],Comps,CompsR):- cgCircle(S), LM #= 100, TM #= 100, S^centerX #= (I-1)*60+LM+30, S^centerY #= (J-1)*60+TM+30, S^diameter #= 50, S^color #= red, Comps=[S|Comps1], drawKnights(Knights,Comps1,CompsR). drawLine([_],Comps,CompsR):-Comps=CompsR. drawLine([(J,I),(J1,I1)|Knights],Comps,CompsR):- cgLine(Line), LM #= 100, TM #= 100, Line^x1 #= (I-1)*60+LM+30, Line^y1 #= (J-1)*60+TM+30, Line^x2 #= (I1-1)*60+LM+30, Line^y2 #= (J1-1)*60+TM+30, Line^color #= red, Comps=[Line|Comps1], drawLine([(J1,I1)|Knights],Comps1,CompsR). handleWindowClosing(Win),{windowClosing(Win)} => cgClose(Win).