Tours de Hanoï (windowedscreen + gadgets + thread)

Partagez votre expérience de PureBasic avec les autres utilisateurs.
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Tours de Hanoï (windowedscreen + gadgets + thread)

Message 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
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message 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
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message 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
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Message par nico »

ça tombe bien, j'ai justement la tour, je vais pouvoir m'entrainer, jamais utiliser pour l'instant!

:)
Répondre