Code : Tout sélectionner
;
; Hanoi towers in a thread and the drawing in the main program
; =====================================
; Les tours de Hanoï dans un thread et le dessin dans le programme principal
;
; F.Weil 20040628
;
; No API here, full PureBasic, strong and stable code
; Interesting use of gadgets with Spin and TrackBar in Frame3D, the one used with TrackBar being updated when the TrackBar is changed
; Drawing is screen based to have a good window stability (no flickering). I use a windowedscreen with no autostretch and a flipbufers(0)
; for maximum velocity of the screen.
; The towers procedure is independant of the screen refresh. It considers the drawing and the calculation as asynchronous processes.
; Hanoi towers algorithm is an old school workshop which exist in recursive and non recursive writing. I use here an old non recursive.
; ========================================================================================
; Pas d'API utilisée, un code PureBasic solide et stable
; Une utilisation intéressante des gadgets avec un Spin et un TrackBar encadrés par des Frame3D, celui utilisé avec le TrackBar se mettant à jour lorsque l'on change
; l'état du TrackBar.
; Le dessin est effectué mode screen pour assurer une bonne stabilité de la fenêtre (pas de scintillement). J'utilise un windowedscreen sans autostretch
; et un flipbuffers(0) pour une vitesse maximale de raffraichissement de l'écran.
; La procédure des tours et le raffraichissment de l'écran sont indépendants. Le dessin et le calcul sont considérés comme des
; processus asynchrones.
; L'algorithme des tours de Hanoï est un vieux cas d'étude bien connu qui peut être résolu en récursif ou non récursif. J'utilise ici le non récursif.
;
Enumeration
#Window_Main
#Gadget_Frame3D1
#Gadget_TrackBar
#Gadget_Frame3D2
#Gadget_Spin
#Gadget_Button
EndEnumeration
Global WindowXSize.l, WindowYSize.l, ScreenXSize.l, ScreenYSize.l, ThreadID.l
Global MaxTowers.l, NMoves.l, TotalMoves.l
MaxTowers = 12
Dim Stack(4096)
Dim Towers.l(3, MaxTowers)
Dim Colors.l(MaxTowers)
;
; The procedure calculates positions, moves. Results are stored in arrays used in the main program
; ======================================================================================
; La procedure calcule les positions, les mouvements. Les résultats sont stockés dans des tableaux utilisés dans le programme principal.
;
Procedure HanoiTowers()
Dim Stack(4096)
Dim Towers.l(3, MaxTowers)
StackPointer = 1
Destination = 2
Source = 0
u = 1
n = 3
e = 0
m = 0
Disk = Val(GetGadgetText(#Gadget_Spin))
TotalMoves = 1 << (Disk + 1) - 1 << (Disk - 1) - 2
NMoves = 0
For i = 1 To Disk
Towers(1, i) = i
;
; Don't worry this formula only generates childish colors ! That's all folks !
;
Colors(i) = $80 * (i & 1) + $8000 * (i & 2) / 2 + $800000 * (i & 4) / 4 + $404040 * (i & 8) / 8
Next
Stack(StackPointer) = Disk
Stack(StackPointer + 1) = 1
Stack(StackPointer + 2) = 3
Stack(StackPointer + 3) = 0
StackPointer + 4
While StackPointer > 1
If StackPointer <> 0
StackPointer - 1
Disk = Stack(StackPointer)
EndIf
e = Disk
If StackPointer <> 0
StackPointer - 1
Disk = Stack(StackPointer)
EndIf
Destination = Disk
If StackPointer <> 0
StackPointer - 1
Disk = Stack(StackPointer)
EndIf
Source = Disk
If StackPointer <> 0
StackPointer - 1
Disk = Stack(StackPointer)
EndIf
n = Disk
m = 6 - Source - Destination
If e <> 0
Towers(Source, Disk) = 0
Towers(Destination, Disk) = Disk
Stack(StackPointer) = n - 1
Stack(StackPointer + 1) = m
Stack(StackPointer + 2) = Destination
Stack(StackPointer + 3) = 0
StackPointer + 4
ElseIf n <> 1
Stack(StackPointer) = n
Stack(StackPointer + 1) = Source
Stack(StackPointer + 2) = Destination
Stack(StackPointer + 3) = 1
Stack(StackPointer + 4) = n - 1
Stack(StackPointer + 5) = Source
Stack(StackPointer + 6) = m
Stack(StackPointer + 7) = 0
StackPointer + 8
Else
Towers(Source, Disk) = 0
Towers(Destination, Disk) = Disk
EndIf
Delay(GetGadgetState(#Gadget_TrackBar))
SetWindowTitle(#Window_Main, "move " + Str(Source) + " --> " + Str(Destination) + " : " + Str(Disk))
NMoves + 1
Wend
ThreadID = 0
EndProcedure
;
; Main manages the window creation and the main event loop
; When the OK button is pushed the game is started in a thread.
; If a game is playing, the main program allow to change parameters. By pressing the OK button again it kills the current thread if one still exists before starting
; a new one.
; ===========
; Le programme principal créé la fenêtre principale et la boucle évènementielle.
; Lorsque l'on appuie sur le bouton OK, le jeu démarre dans un thread
; Si un jeu est en cours, le programme principal permet de modifier les paramètres. En appuyant sur le bouton OK à nouveau on peut relancer le jeu. Si un thread
; est en cours il est détruit avant d'en lancer un autre.
;
WindowXSize = 800
WindowYSize = 600
ScreenXSize = 720
ScreenYSize = 520
Quit = #FALSE
If OpenWindow(#Window_Main, 0, 0, WindowXSize, WindowYSize, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "")
InitSprite()
OpenWindowedScreen(WindowID(), 40, 60, ScreenXSize, ScreenYSize, #FALSE, 0, 0)
AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Escape, #PB_Shortcut_Escape)
AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Return, #PB_Shortcut_Return)
If CreateGadgetList(WindowID(#Window_Main))
Frame3DGadget(#Gadget_Frame3D1, 200, 10, 130, 40, "Delay 250ms")
TrackBarGadget(#Gadget_TrackBar, 215, 25, 100, 20, 1, 250)
SetGadgetState(#Gadget_TrackBar, 250)
Frame3DGadget(#Gadget_Frame3D2, 10, 10, 90, 40, "N")
SpinGadget(#Gadget_Spin, 25, 25, 70, 20, 3, 12)
SetGadgetState(#Gadget_Spin, 5)
SetGadgetText(#Gadget_Spin, "5")
ButtonGadget(#Gadget_Button, 120, 23, 60, 20, "OK")
EndIf
ThreadID = CreateThread(@HanoiTowers(), 0)
Repeat
Select WindowEvent()
Case #PB_Event_CloseWindow
Quit = #TRUE
Case #PB_Event_Menu
Select EventMenuID()
Case #PB_Shortcut_Escape
Quit = #TRUE
Case #PB_Shortcut_Return
If ThreadID <> 0
KillThread(ThreadID)
EndIf
ThreadID = CreateThread(@HanoiTowers(), 0)
EndSelect
Case #PB_Event_Gadget
Select EventGadgetID()
Case #Gadget_Button
If ThreadID <> 0
KillThread(ThreadID)
EndIf
ThreadID = CreateThread(@HanoiTowers(), 0)
Case #Gadget_Spin
SetGadgetText(#Gadget_Spin, Str(GetGadgetState(#Gadget_Spin)))
WindowEvent()
Case #Gadget_TrackBar
Frame3DGadget(#Gadget_Frame3D1, 200, 10, 130, 40, "Delay " + Str(GetGadgetState(#Gadget_TrackBar)) + "ms")
EndSelect
EndSelect
FlipBuffers(0)
ClearScreen(0, 0, 0)
DiskSize = ScreenYSize / 30
StartDrawing(ScreenOutput())
For i = 1 To 3
k = 0
For j = 1 To MaxTowers
If Towers(i, j) <> 0
k + 1
EndIf
Next
For j = 1 To MaxTowers
If Towers(i, j) <> 0
;
; If a tile takes place position is calculated and also a shaded color is drawn in nested boxes
; =======================================================================
; Si une pièce prend place, sa position est calculée et une couleur dégradée est générée par des boites gigognes
;
XPosition = DiskSize * MaxTowers * i - DiskSize * Towers(i, j) / 2
YPosition = (ScreenYSize - MaxTowers * DiskSize) / 2 + DiskSize * MaxTowers - k * DiskSize
Width = DiskSize * Towers(i, j)
Height = DiskSize
Red = Red(Colors(Towers(i, j)))
Green = Green(Colors(Towers(i, j)))
Blue = Blue(Colors(Towers(i, j)))
For l = 0 To DiskSize / 2
Color = RGB(Red, Green, Blue)
Box(XPosition + l, YPosition + l, Width - 2 * l, Height - 2 * l, Color)
Red - l
Green - l
Blue - l
Next
k - 1
EndIf
Next
Next
;
; Stats display
; ==============
; Affichage des statistiques
;
BackColor(0, 0, 0)
FrontColor(255, 255, 255)
DrawingMode(1)
Locate(10, 10)
DrawText("FPS " + Str(FPS))
Locate(10, 30)
DrawText("Moves " + Str(NMoves) + " / " + Str(TotalMoves))
StopDrawing()
If ElapsedMilliseconds() - tz => 1000
FPS = NFrames
NFrames = 0
tz = ElapsedMilliseconds()
EndIf
NFrames + 1
Delay(5)
Until Quit
If ThreadID <> 0
KillThread(ThreadID)
EndIf
CloseWindow(#Window_Main)
EndIf
End