/******************************************************************** CGLIB: Constraint-based Graphical Programming in B-Prolog % animate the plan for solving the Towers of Hanoi. *********************************************************************/ go:- go(3,500). handleWindowClosing(Win),{windowClosing(Win)} => cgClose(Win). go(N,Speed):- cgWindow(Win,"Towers of Hanoi"),Win^topMargin #= 30,Win^leftMargin #= 30, handleWindowClosing(Win), createControlPanel(N,Speed,Win,CP), createHanoiWorld(HanoiWorld,CP), generateEventHandlers(CP,HanoiWorld). generateEventHandlers(CP,HanoiWorld):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), handleReset(Reset,CP,HanoiWorld), handleStart(Start,CP,HanoiWorld), handlePause(Pause,CP,HanoiWorld), handleResume(Resume,CP,HanoiWorld). handleReset(Reset,CP,HanoiWorld), {actionPerformed(Reset)} => getWindow(CP,Win), getSize(CP,N), setStatus(CP,stop), % kill the executor of the plan getRate(CP,Rate), cgClose(Win), go(N,Rate). handleStart(Start,CP,HanoiWorld), {actionPerformed(Start)} => disableStart(CP), enablePause(CP), getRate(CP,Rate), disableSpeed(CP), disableSize(CP), setStatus(CP,running), hanoiPlan(HanoiWorld,Plan), executePlan(CP,HanoiWorld,Plan). handlePause(Pause,CP,HanoiWorld),{actionPerformed(Pause)} => enableResume(CP), disablePause(CP), setStatus(CP,waiting). handleResume(Resume,CP,HanoiWorld),{actionPerformed(Resume)} => enablePause(CP), disableResume(CP), setStatus(CP,running). /* operations on control panel */ createControlPanel(N,Rate,Win,CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), cgLabel([LabSize,LabSpeed],["Size:","Rate:"]), number_codes(N,NString), cgTextField(Size), Size^columns #= 5, cgSetText(Size,NString), % cgTextField(Speed), Speed^columns #= 5, number_codes(Rate,RString), cgSetText(Speed,RString), % cgButton([Reset,Start,Pause,Resume],["Reset","Start","Pause","Resume"]), Reset^height #= 20,cgSame([Reset,Start,Pause,Resume],width,40), Pause^x #= Win^width//2, % constrain the components cgTable([[LabSize,Size,LabSpeed,Speed], [Reset,Start,Pause,Resume]],10,3), cgAbove(LabSize,Reset), % Comps=[LabSize,Size,LabSpeed,Speed,Reset,Start,Pause,Resume], cgSame(Comps,window,Win), cgShow(Comps), enableStart(CP), disablePause(CP), disableResume(CP). getWindow(CP,Win):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status). getSize(CP,N):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), cgGetText(Size,NString), catch(number_codes(N,NString),_,N=3). getCenterX(CP,X):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), X #= (Start^rightX+Pause^x)//2. getRate(CP,Rate):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), cgGetText(Speed,NString), catch(number_codes(Rate,NString),_,Rate=200). getStatus(CP,Status):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status). setStatus(CP,running):-!, CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), setarg(8,CP,running), write(post(event(EV))),nl, post(event(EV)). %activate the plan executor setStatus(CP,Status):- setarg(8,CP,Status). getControlPanelHeight(CP,Height):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), Height #= Size^height+Reset^height. disableStart(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), disable(Start). enableStart(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), enable(Start). disablePause(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), disable(Pause). enablePause(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), enable(Pause). disableResume(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), disable(Resume). enableResume(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), enable(Resume). disableSpeed(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), disable(Speed). enableSpeed(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), enable(Speed). disableSize(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), disable(Size). enableSize(CP):- CP=cp(Win,Size,Speed,Reset,Start,Pause,Resume,Status), enable(Size). enable(Comp):-cgSetEnabled(Comp,1), cgShow(Comp). disable(Comp):-cgSetEnabled(Comp,0), cgShow(Comp). /* operations on hanoi world (table, poles, disks) */ createHanoiWorld(HanoiWorld,CP):- HanoiWorld=hanoi(N,Disks,Poles,Table), getSize(CP,N), createTable(Table,CP), createPoles(Poles,Table,CP), createDisks(N,Disks,Poles,Table,CP), showHanoiWorld(HanoiWorld,CP). createTable(Table,CP):- getWindow(CP,Win), cgRectangle(Table),Table^color #= black, Table^window #= Win, Table^height #= 20, Table^width #= Win^width-100, Table^bottomY #= Win^height-100, getCenterX(CP,CX), Table^centerX #= CX. createPoles(Poles,Table,CP):- Poles=poles(pole(P1,TopY1),pole(P2,TopY2),pole(P3,TopY3)), PoleRects = [P1,P2,P3], cgRectangle(PoleRects), getWindow(CP,Win), cgSame(PoleRects,window,Win), cgSame(PoleRects,color,red), Width #= Table^width//20, getControlPanelHeight(CP,CPHeight), Height #= Win^height-Win^topMargin-CPHeight-Table^height-120, cgSame(PoleRects,width,Width), cgSame(PoleRects,height,Height), PoleY #= Win^topMargin+CPHeight+20, cgSame(PoleRects,y,PoleY), P2^centerX #= Table^centerX, P1^centerX #= P2^centerX-Table^width//4, P3^centerX #= P2^centerX+Table^width//4. createDisks(N,Disks,poles(pole(P1,TopY1),pole(P2,TopY2),pole(P3,TopY3)),Table,CP):- new_array(Disks,[N]), DiskHeight #= P1^height//(N+1), Table^y-DiskHeight #= Y, P1^centerX #= X, SmallestDiskWidth #= 2*P1^width, LargestDiskWidth #= Table^width//4, Diff #= (LargestDiskWidth-SmallestDiskWidth)//N, getWindow(CP,Win), createDisks(N,Disks,DiskHeight,LargestDiskWidth,Diff,X,Y,Win), Disks^[1] @= Disk1, TopY1 #= Disk1^y, TopY2 #= Table^y, TopY3 #= Table^y. createDisks(N,Disks,DiskHeight,DiskWidth,Diff,X,Y,Win):-N<1,!. createDisks(N,Disks,DiskHeight,DiskWidth,Diff,X,Y,Win):- Disks^[N] @= Disk, % no, pole no, and comp cgRectangle(Disk),Disk^width#=DiskWidth, Disk^height #= DiskHeight, Disk^window #= Win, Disk^color #= gray, Disk^centerX #= X, Disk^y #= Y, NextY #= Y-DiskHeight, NextDiskWidth #= DiskWidth-Diff, N1 is N-1, createDisks(N1,Disks,DiskHeight,NextDiskWidth,Diff,X,NextY,Win). showHanoiWorld(HW,CP):- HW=hanoi(N,Disks,poles(pole(P1,_),pole(P2,_),pole(P3,_)),Table), array_to_list(Disks,Comps), AllComps=[Table,P1,P2,P3|Comps], cgShow(AllComps). %% find a plan hanoiPlan(hanoi(N,Disks,Poles,Table),Plan):- hanoiPlan(N,1,3,2,Plan,[]). hanoiPlan(0,P1,P2,P3,Plan,PlanR):-!,Plan=PlanR. hanoiPlan(N,P1,P2,P3,Plan,PlanR):- N1 is N-1, hanoiPlan(N1,P1,P3,P2,Plan,Plan1), Plan1 = [move(N,P1,P2)|Plan2], hanoiPlan(N1,P3,P2,P1,Plan2,PlanR). %% execute a plan executePlan(CP,HanoiWorld,[Step|Plan]):- getStatus(CP,running),!, executeStep(HanoiWorld,Step), getRate(CP,Time), cgSleep(Time), executePlan(CP,HanoiWorld,Plan). executePlan(CP,HanoiWorld,Plan):- getStatus(CP,waiting),!, sleep(500), executePlan(CP,HanoiWorld,Plan). executePlan(CP,HanoiWorld,_):- disablePause(CP). %come here when Plan is empty or Status is "stop" % from Pole 1 to Pole 2 executeStep(HanoiWorld,move(I,Pno1,Pno2)):- HanoiWorld=hanoi(_,Disks,Poles,Table), Disks^[I] @= Disk, arg(Pno1,Poles,Pole1), Pole1=pole(Rect1,TopY1), arg(Pno2,Poles,Pole2), Pole2=pole(Rect2,TopY2), NewX #= Rect2^centerX-Disk^width//2, NewY #= TopY2-Disk^height, cgClean(Disk), Disk^x #:= NewX, Disk^y #:= NewY, NewTopY1 #= TopY1+Disk^height, setarg(2,Pole1,NewTopY1), setarg(2,Pole2,NewY), cgShow(Disk).