Page 1 sur 1

Tours de Hanoï (windowedscreen + gadgets + thread)

Publié : lun. 28/juin/2004 23:44
par fweil
Le vieux sujet des tours de Hanoï retravaillé avec qq trucs intéressants.

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

Publié : mar. 29/juin/2004 9:35
par Dr. Dri
10 étages génerrent une erreur, sinon c'est super
Je pensai que c'était une version à jouer je suis déçu ^^

Dri

Publié : mar. 29/juin/2004 9:37
par fweil
J'ai constaté qu'il y a une erreur de temps en temps si le debugger est actif, erreur qui survient dans le thread.

Je ne suis pas parvenu pour l'instant à délimiter le pb.

Pour la version à jouer, je ferai une mise à jour prochainement.

Slts

Publié : mar. 29/juin/2004 11:39
par nico
ça tombe bien, j'ai justement la tour, je vais pouvoir m'entrainer, jamais utiliser pour l'instant!

:)