home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-25 | 6.2 KB | 217 lines | [TEXT/3PRM] |
- module Hanoi
-
- /* The Towers of Hanoi (graphical version).
- This program requires the 0.8 I/O library.
- Run the program using the "No Console" option (Application options).
- */
-
- import StdEnv
- import deltaEventIO, deltaMenu, deltaDialog, deltaTimer, deltaWindow, deltaPicture
-
- :: Tower :== [Int]
- :: Moves :== [Int]
- :: Towers
- = { moves :: !Moves
- , tower1 :: !Tower
- , tower2 :: !Tower
- , tower3 :: !Tower
- }
- :: *IO :== IOState *Towers
-
- FileID :== 1
- RunID :== 11
- HaltID :== 12
- ContID :== 13
- SpeedID :== 14
- VerSID :== 141
- SlowID :== 142
- NormID :== 143
- FastID :== 144
- VerFID :== 145
- QuitID :== 15
-
- TimerID :== 1
-
- WindowID :== 1
- PicDomain :== ((50,0),(480,180))
- Speed1 :== TicksPerSecond / 2
- Speed2 :== TicksPerSecond / 3
- Speed3 :== TicksPerSecond / 6
- Speed4 :== TicksPerSecond / 12
- Speed5 :== 0
-
- MinDisks :== 2
- MaxDisks :== 12
- XOffs :== inc MaxDisks * 10
-
- // Starting the program
-
- Start :: *World -> *World
- Start world
- # (events,world) = OpenEvents world
- (_,events) = StartIO [menus,windows,timers] (InitTowers 0) [] events
- world = CloseEvents events world
- = world
- where
- menus = MenuSystem
- [ PullDownMenu FileID "File" Able
- [ SubMenuItem RunID "Run (nr disks)" Able
- [ MenuItem (1000+i) (toString i) NoKey Able (Run i) \\ i<-[MinDisks..MaxDisks] ]
- , MenuItem HaltID "Halt" (Key '.') Unable Halt
- , MenuItem ContID "Continue" (Key ',') Unable Continue
- , SubMenuItem SpeedID "Speed" Able
- [ MenuRadioItems NormID
- [ MenuRadioItem VerSID "Very Slow" (Key 'A') Able (SetSpeed Speed1)
- , MenuRadioItem SlowID "Slow" (Key 'S') Able (SetSpeed Speed2)
- , MenuRadioItem NormID "Normal" (Key 'D') Able (SetSpeed Speed3)
- , MenuRadioItem FastID "Fast" (Key 'F') Able (SetSpeed Speed4)
- , MenuRadioItem VerFID "Very Fast" (Key 'G') Able (SetSpeed Speed5)
- ]
- ]
- , MenuItem QuitID "Quit" (Key 'Q') Able Quit
- ]
- ]
-
- windows = WindowSystem
- [ FixedWindow WindowID (0,0) "Hanoi" PicDomain Update
- [GoAway Quit]
- ]
-
- timers = TimerSystem
- [ Timer TimerID Unable Speed3 StepHanoi
- ]
-
-
- InitTowers :: Int -> *Towers
- InitTowers nr_disks
- = {moves=Hanoi nr_disks 1 2 3, tower1=[1..nr_disks], tower2=[], tower3=[]}
- where
- Hanoi :: Int Int Int Int -> Moves // The function that calculates the list of disk moves
- Hanoi n start end via
- | n==0 = []
- | otherwise = Hanoi m start via end ++ [start,end : Hanoi m via end start]
- where
- m = n-1
-
-
- // The function for the Run command
-
- Run :: Int *Towers IO -> (*Towers,IO)
- Run nr_disks _ io
- # io = EnableMenuItems [HaltID] io
- io = DisableMenuItems [RunID,ContID] io
- io = EnableTimer TimerID io
- = DrawInActiveWindowFrame Update (InitTowers nr_disks) io
-
-
- // The function for the Halt command
-
- Halt :: *Towers IO -> (*Towers,IO)
- Halt towers io
- # io = DisableMenuItems [HaltID] io
- io = EnableMenuItems [RunID,ContID] io
- io = DisableTimer TimerID io
- = (towers,io)
-
-
- // The function for the Continue command
-
- Continue :: !*Towers IO -> (!*Towers,IO)
- Continue towers io
- # io = EnableMenuItems [HaltID] io
- io = DisableMenuItems [RunID,ContID] io
- io = EnableTimer TimerID io
- = (towers,io)
-
-
- // The function for the Quit command
-
- Quit :: *Towers IO -> (*Towers,IO)
- Quit towers io
- = (towers,QuitIO io)
-
-
- // Set the speed of a (possibly running) Hanoi simulation
-
- SetSpeed :: Int *Towers IO -> (*Towers,IO)
- SetSpeed speed towers io
- = (towers, SetTimerInterval TimerID speed io)
-
-
- // The timer function: take a move from the list of all moves and show it in the window
-
- StepHanoi :: TimerState *Towers IO -> (*Towers,IO)
- StepHanoi _ towers=:{moves=[]} io
- # io = DisableMenuItems [HaltID] io
- io = EnableMenuItems [RunID] io
- io = DisableTimer TimerID io
- = (towers, io)
- StepHanoi _ towers io
- # (drawfs,towers) = ChangeTowers towers
- io = DrawInActiveWindow drawfs io
- = (towers,io)
- where
- ChangeTowers :: Towers -> ([DrawFunction],*Towers)
- ChangeTowers towers=:{moves=[1,2:moves],tower1=[f1:r1],tower2=t2}
- = (DrawMove 1 2 f1 (length r1) (length t2),{towers & moves=moves,tower1=r1,tower2=[f1:t2]})
- ChangeTowers towers=:{moves=[1,3:moves],tower1=[f1:r1],tower3=t3}
- = (DrawMove 1 3 f1 (length r1) (length t3),{towers & moves=moves,tower1=r1,tower3=[f1:t3]})
- ChangeTowers towers=:{moves=[2,1:moves],tower2=[f2:r2],tower1=t1}
- = (DrawMove 2 1 f2 (length r2) (length t1),{towers & moves=moves,tower2=r2,tower1=[f2:t1]})
- ChangeTowers towers=:{moves=[2,3:moves],tower2=[f2:r2],tower3=t3}
- = (DrawMove 2 3 f2 (length r2) (length t3),{towers & moves=moves,tower2=r2,tower3=[f2:t3]})
- ChangeTowers towers=:{moves=[3,1:moves],tower3=[f3:r3],tower1=t1}
- = (DrawMove 3 1 f3 (length r3) (length t1),{towers & moves=moves,tower3=r3,tower1=[f3:t1]})
- ChangeTowers towers=:{moves=[3,2:moves],tower3=[f3:r3],tower2=t2}
- = (DrawMove 3 2 f3 (length r3) (length t2),{towers & moves=moves,tower3=r3,tower2=[f3:t2]})
-
- DrawMove :: Int Int Int Int Int -> [DrawFunction]
- DrawMove start end disk lenfr lento
- = [ EraseDisk ((fx-w,fy),(fx+w,fy+10))
- , DrawDisk ((tx-w,ty),(tx+w,ty+10))
- ]
- where
- tx = end *XOffs; ty = 10+10*(MaxDisks-lento)
- fx = start*XOffs; fy = 10+10*(MaxDisks-lenfr)
- w = disk *5
-
- EraseDisk :: Rectangle -> DrawFunction
- EraseDisk rectangle = EraseRectangle rectangle
-
- DrawDisk :: Rectangle -> DrawFunction
- DrawDisk rectangle
- = seq
- [ SetPenColour (RGB 0.5 0.6 0.7)
- , FillRectangle rectangle
- , SetPenColour BlackColour
- , DrawRectangle rectangle
- ]
-
-
- // The update function: erase the window and redraw the towers
-
- Update :: UpdateArea *Towers -> (*Towers, [DrawFunction])
- Update _ towers=:{tower1,tower2,tower3}
- = ( towers
- , [ EraseRectangle PicDomain
- , DrawTower 1 (MaxDisks-length tower1) tower1
- , DrawTower 2 (MaxDisks-length tower2) tower2
- , DrawTower 3 (MaxDisks-length tower3) tower3
- ]
- )
- where
- DrawTower :: Int Int Tower Picture -> Picture
- DrawTower nr i [f:r] pic
- = DrawTower nr (i+1) r disk
- where
- disk = DrawDisk ((x-w,y),(x+w,y+10)) pic
- x = nr*XOffs
- w = f *5
- y = 20+10*i
- DrawTower nr _ _ pic
- | nr==1 = DrawString "from" (MovePenTo ( XOffs-14,y) pic)
- | nr==2 = DrawString "to" (MovePenTo (2*XOffs-6, y) pic)
- | nr==3 = DrawString "via" (MovePenTo (3*XOffs-9, y) pic)
- where
- y = 35+10*MaxDisks
-