Author Topic: Pascal's Triangle Pinball Demo  (Read 3191 times)

0 Members and 1 Guest are viewing this topic.

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Pascal's Triangle Pinball Demo
« on: May 05, 2019, 06:26:40 am »
Pascal's Triangle is a construction to give the binomial coefficients.  Machines have been constructed to show a physical analogue of this (see en.wikipedia.org/wiki/Bean_machine for details of this).  This program is a simulation of a triangular pinball table which demonstrates (closely) the same thing.

Ball's fall through the pin board under a constant force (gravity) and bounce off the pins through the array and exit at the bottom.  The program uses full bouncing mechanics at each pin, with friction and non-ideal elastics collisions.  At each pin there is a 50% chance of the ball leaving to the left or right, which is the condition required to obtain the Pascal's Triangle numbers.

In the real constructed machines, a large number of balls simultaneously fall through the pin array and accumulate in columns at the bottom.  In this simulation, balls fall through one-at-a-time and are counted at the exits at the bottom.  The numbers through each exit are displayed in a histogram (Sorry, Fellippe, I couldn't do the ball columns!).  Beneath the histogram, figures are given in ratio to the expected binomial coefficients, scaled to the central column: if each pin collision were perfectly 50% left-right, each of the displayed figures would be exactly 1.

The balls are moving under constant force and (apart from the friction and inelastic collisions) would achieve high speeds, and consequently each ball experiences many collisions as it travels through the array.  This would have made the display very slow, and the program is adjusted to put an image to the screen at a fraction of the calculation cycle.  You may find that ball movement flicker is improved if you adjust line 4 of the code [FrameRate% = 60] to change the Constant FrameRate% to your monitor's refresh rate.

Because only one ball at a time travels through the pinboard, the histogram accumulation is rather slow and if you are interested to get to reasonable numbers, you'll have to allow the program to run for some time.

I had thought that I would need to place additional pins to the left and right of the triangle to prevent any ball exiting the triangle after an appropriate bounce.  However, I have never seen such a problem and the balls always stay within the triangle (it'll be interesting if anybody ever finds such an event - the program is likely to crash if this did happen).

You will need the whiteball and icon images and the cyberbit font file which comes with QB64.

Code: QB64: [Select]
  1. 'Pascal's Triangle Simulation by QWERKEY 04/05/19
  2.  
  3. CONST True = -1, False = 0
  4. CONST FrameRate% = 60, CalcRate% = 600
  5. CONST BallDiam%% = 60, PinRad%% = 7, Separation%% = (BallDiam%% / 2) + PinRad%%, Spacing%% = BallDiam%% + (2 * PinRad%%) + 6
  6. CONST H0! = SQR(0.75), H! = Spacing%% * H0!
  7. CONST XScreen% = 980, YScreen% = 820, SmallBit! = 0.2, CornRad%% = 50, NoBallsLess1%% = 4
  8. CONST A1%% = 16 + BallDiam%% + CornRad%%, A2%% = 8 + BallDiam%% / 2, A3%% = CornRad%% + 8 + BallDiam%% / 2
  9. CONST A4%% = 16 + BallDiam%%, A5%% = 8 + BallDiam%%
  10. CONST HistBase% = 380, HistHeight% = 340, HistWidth%% = 22, HistSepn%% = 5, HistBlock%% = 20
  11. CONST G! = 0.2, F! = 0.97, W! = 0.8, Z! = 0.05, Bagatelle! = 0.8, Omega! = Bagatelle! / A3%%, SpeedLimit! = 3.5
  12. DIM Pascal%(1, 8), Nos&(10), Pins!(1, 53), Vect!(NoBallsLess1%%, 4), DoPascal%%(NoBallsLess1%%, 6)
  13.  
  14. _TITLE "Pascal's Triangle"
  15. $EXEICON:'.\blaise2.ico'
  16.  
  17. DATA 1,8,28,56,70,56,28,8,1
  18. FOR N%% = 0 TO 8
  19.     READ Pascal%(0, N%%)
  20. NEXT N%%
  21. 'Images
  22. TempImg& = _NEWIMAGE(BallDiam%%, BallDiam%%, 32)
  23. _DEST TempImg&
  24. _PUTIMAGE (0, 0)-(BallDiam%% - 1, BallDiam%% - 1), _LOADIMAGE("whiteball.png", 32)
  25. Ball& = MakeHardware&(TempImg&)
  26. Pin& = _NEWIMAGE(PinRad%% * 2 + 1, PinRad%% * 2 + 1, 32)
  27. _DEST Pin&
  28. FOR N%% = PinRad%% TO 1 STEP -1
  29.     CIRCLE (PinRad%%, PinRad%%), N%%, _RGB32(CINT(181 * (N%% + 5) / (PinRad%% + 5)), CINT(166 * (N%% + 5) / (PinRad%% + 5)), CINT(66 * (N%% + 5) / (PinRad%% + 5)))
  30.     PAINT (PinRad%%, PinRad%%), _RGB32(CINT(181 * (N%% + 5) / (PinRad%% + 5)), CINT(166 * (N%% + 5) / (PinRad%% + 5)), CINT(66 * (N%% + 5) / (PinRad%% + 5)))
  31. NEXT N%%
  32. B& = _NEWIMAGE(128, 128, 32)
  33. COLOR _RGB32(100, 100, 100), _RGB32(230, 230, 20)
  34. Corn& = _NEWIMAGE(A1%%, A1%%, 32)
  35. _DEST Corn&
  36. COLOR _RGB32(229, 170, 112)
  37. CIRCLE (0, 0), CornRad%%
  38. CIRCLE (0, 0), A1%% - 1
  39. PAINT (CornRad%% + 1, 1)
  40. COLOR _RGB32(193, 117, 46)
  41. CIRCLE (0, 0), CornRad%%
  42. CIRCLE (0, 0), CornRad%% + 8
  43. PAINT (CornRad%% + 1, 1)
  44. CIRCLE (0, 0), A1%% - 1 - 8
  45. CIRCLE (0, 0), A1%% - 1
  46. PAINT (A1%% - 8, 1)
  47. TempImg& = _NEWIMAGE(XScreen%, YScreen%, 32)
  48. _DEST TempImg&
  49. T% = 0
  50. FOR N%% = 0 TO 8
  51.     FOR M%% = -(N%% + 1) TO (N%% + 1) STEP 2
  52.         _PUTIMAGE ((XScreen% / 2) + CINT(M%% * Spacing%% / 2) - PinRad%%, A1%% + 30 - PinRad%% + CINT(H! * N%%)), Pin&
  53.         Pins!(0, T%) = (XScreen% / 2) + (M%% * Spacing%% / 2)
  54.         Pins!(1, T%) = A1%% + 30 + (H! * N%%)
  55.         T% = T% + 1
  56.     NEXT M%%
  57. NEXT N%%
  58. L% = 700
  59. T% = 130
  60. _MAPTRIANGLE (0, 127)-(63, 127)-(63, 16), B& TO(L% + 0, T% + 127)-(L% + 63, T% + 127)-(L% + 63, T% + 16)
  61. _MAPTRIANGLE (127, 127)-(63, 127)-(63, 16), B& TO(L% + 127, T% + 127)-(L% + 63, T% + 127)-(L% + 63, T% + 16)
  62. COLOR _RGB32(0, 0, 0), _RGB32(230, 230, 20)
  63. font& = _LOADFONT("cyberbit.ttf", 30, "bold")
  64. _FONT font&
  65. _PRINTSTRING (L% + 54, T% + 32), "P"
  66. _PRINTSTRING (L% + 38, T% + 63), "A"
  67. _PRINTSTRING (L% + 68, T% + 63), "S"
  68. _PRINTSTRING (L% + 22, T% + 94), "C"
  69. _PRINTSTRING (L% + 52, T% + 94), "A"
  70. _PRINTSTRING (L% + 82, T% + 94), "L"
  71. _FREEFONT font&
  72. LINE (90, YScreen% - 1)-(XScreen% - 1 - A1%%, YScreen% - 1 - A4%%), _RGB32(229, 170, 112), BF
  73. LINE (90, YScreen% - 1)-(XScreen% - 1 - A1%%, YScreen% - 1 - 8), _RGB32(193, 117, 46), BF
  74. LINE (90, YScreen% - 1 - A4%%)-(120, YScreen% - 1 - A5%%), _RGB32(193, 117, 46), BF
  75. LINE (90, YScreen% - 1 - A4%%)-(98, YScreen% - 1), _RGB32(193, 117, 46), BF
  76. LINE (121, YScreen% - 1 - A4%%)-(XScreen% - 1 - A1%%, YScreen% - 1 - A5%%), _RGBA32(193, 117, 46, 80), BF
  77. LINE (XScreen% - 1 - A4%%, A1%%)-(XScreen% - 1, YScreen% - 1 - A1%%), _RGB32(229, 170, 112), BF
  78. LINE (XScreen% - 1 - 8, A1%%)-(XScreen% - 1, YScreen% - 1 - A1%%), _RGB32(193, 117, 46), BF
  79. LINE (XScreen% - 1 - A5%%, A1%%)-(XScreen% - 1 - A5%% - 8, YScreen% - 1 - A1%%), _RGB32(193, 117, 46), BF
  80. LINE (XScreen% / 2 + BallDiam%% / 2 + CornRad%%, 0)-(XScreen% - 1 - A1%%, A4%%), _RGB32(229, 170, 112), BF
  81. LINE (XScreen% / 2 + BallDiam%% / 2 + CornRad%%, 0)-(XScreen% - 1 - A1%%, 8), _RGB32(193, 117, 46), BF
  82. LINE (XScreen% / 2 + BallDiam%% / 2 + CornRad%%, A4%% - 8)-(XScreen% - 1 - A1%%, A4%%), _RGB32(193, 117, 46), BF
  83. _PUTIMAGE (XScreen% - 1 - A1%%, YScreen% - 1 - A1%%), Corn&
  84. _MAPTRIANGLE (0, 0)-(A1%% - 1, 0)-(A1%% - 1, A1%% - 1), Corn& TO(XScreen% - 1 - A1%%, A1%%)-(XScreen% - 1 - A1%%, 0)-(XScreen% - 1, 0)
  85. _MAPTRIANGLE (A1%% - 1, A1%% - 1)-(0, A1%% - 1)-(0, 0), Corn& TO(XScreen% - 1, 0)-(XScreen% - 1, A1%%)-(XScreen% - 1 - A1%%, A1%%)
  86. _MAPTRIANGLE (0, 0)-(A1%% - 1, 0)-(A1%% - 1, A1%% - 1), Corn& TO(XScreen% / 2 + A3%%, A1%%)-(XScreen% / 2 - A2%%, A1%%)-(XScreen% / 2 - A2%%, 0)
  87. _MAPTRIANGLE (A1%% - 1, A1%% - 1)-(0, A1%% - 1)-(0, 0), Corn& TO(XScreen% / 2 - A2%%, 0)-(XScreen% / 2 + A3%%, 0)-(XScreen% / 2 + A3%%, A1%%)
  88. Background& = MakeHardware&(TempImg&)
  89. TempImg& = _NEWIMAGE(20, 240, 32)
  90. _DEST TempImg&
  91. COLOR _RGB32(100, 100, 100), _RGB32(80, 240, 40)
  92. Histo& = MakeHardware&(TempImg&)
  93. FOR N%% = 0 TO 9
  94.     No& = _NEWIMAGE(8, 14, 32)
  95.     _DEST No&
  96.     COLOR _RGB32(255, 30, 80)
  97.     _PRINTSTRING (0, 0), LTRIM$(STR$(N%%))
  98.     Nos&(N%%) = _NEWIMAGE(14, 8, 32)
  99.     _DEST Nos&(N%%)
  100.     _MAPTRIANGLE (0, 0)-(7, 0)-(0, 13), No& TO(13, 0)-(13, 7)-(0, 0)
  101.     _MAPTRIANGLE (7, 13)-(0, 13)-(7, 0), No& TO(0, 7)-(0, 0)-(13, 7)
  102.     _FREEIMAGE No&
  103. NEXT N%%
  104. No& = _NEWIMAGE(8, 14, 32)
  105. _DEST No&
  106. COLOR _RGB32(255, 30, 80)
  107. _PRINTSTRING (0, 0), "."
  108. Nos&(10) = _NEWIMAGE(14, 8, 32)
  109. _DEST Nos&(10)
  110. _MAPTRIANGLE (0, 0)-(7, 0)-(0, 13), No& TO(13, 0)-(13, 7)-(0, 0)
  111. _MAPTRIANGLE (7, 13)-(0, 13)-(7, 0), No& TO(0, 7)-(0, 0)-(13, 7)
  112. 'Initialise
  113. MaxBar% = 0
  114. C%% = False
  115. DoPascal%%(0, 0) = True
  116. DoPascal%%(0, 1) = False
  117. DoPascal%%(0, 2) = False
  118. DoPascal%%(0, 3) = False
  119. DoPascal%%(0, 4) = False
  120. DoPascal%%(0, 5) = False
  121. DoPascal%%(0, 6) = False
  122. Vect!(0, 0) = XScreen% / 2
  123. Vect!(0, 1) = A1%% + 10
  124. Vect!(0, 2) = Z! * (0.5 - RND)
  125. Vect!(0, 3) = 0.3 + (0.2 * RND)
  126. DoPascal%%(1, 0) = False
  127. DoPascal%%(1, 1) = False
  128. DoPascal%%(1, 2) = False
  129. DoPascal%%(1, 3) = True
  130. DoPascal%%(1, 4) = False
  131. DoPascal%%(1, 5) = False
  132. DoPascal%%(1, 6) = False
  133. Vect!(1, 0) = XScreen% - A1%%
  134. Vect!(1, 1) = A2%%
  135. Vect!(1, 2) = -Bagatelle!
  136. Vect!(1, 3) = 0
  137. DoPascal%%(2, 0) = False
  138. DoPascal%%(2, 1) = False
  139. DoPascal%%(2, 2) = True
  140. DoPascal%%(2, 3) = False
  141. DoPascal%%(2, 4) = False
  142. DoPascal%%(2, 5) = False
  143. DoPascal%%(2, 6) = False
  144. Vect!(2, 0) = XScreen% - A2%%
  145. Vect!(2, 1) = A1%% + 10
  146. Vect!(2, 2) = 0
  147. Vect!(2, 3) = -Bagatelle!
  148. DoPascal%%(3, 0) = False
  149. DoPascal%%(3, 1) = False
  150. DoPascal%%(3, 2) = True
  151. DoPascal%%(3, 3) = False
  152. DoPascal%%(3, 4) = False
  153. DoPascal%%(3, 5) = False
  154. DoPascal%%(3, 6) = False
  155. Vect!(3, 0) = XScreen% - A2%%
  156. Vect!(3, 1) = YScreen% - 1 - A1%% - 10
  157. Vect!(3, 2) = 0
  158. Vect!(3, 3) = -Bagatelle!
  159. DoPascal%%(4, 0) = False
  160. DoPascal%%(4, 1) = True
  161. DoPascal%%(4, 2) = False
  162. DoPascal%%(4, 3) = False
  163. DoPascal%%(4, 4) = False
  164. DoPascal%%(4, 5) = False
  165. DoPascal%%(4, 6) = False
  166. Vect!(4, 0) = XScreen% / 2
  167. Vect!(4, 1) = YScreen% - A2%%
  168. Vect!(4, 2) = 1.8 * Bagatelle!
  169. Vect!(4, 3) = 0
  170.  
  171. SCREEN _NEWIMAGE(XScreen%, YScreen%, 32)
  172.     _LIMIT CalcRate%
  173.     DispCount% = DispCount% + 1
  174.     'Display Images
  175.     IF DispCount% = CINT(CalcRate% / FrameRate%) THEN
  176.         'CLS
  177.         _PUTIMAGE (0, 0), Background&
  178.         FOR N%% = 0 TO NoBallsLess1%%
  179.             _PUTIMAGE (CINT(Vect!(N%%, 0) - (BallDiam%% / 2)), CINT(Vect!(N%%, 1) - (BallDiam%% / 2))), Ball&
  180.         NEXT N%%
  181.         FOR N%% = 0 TO 8
  182.             IF Pascal%(1, N%%) > MaxBar% THEN MaxBar% = Pascal%(1, N%%)
  183.         NEXT N%%
  184.         FOR N%% = 0 TO 8
  185.             IF MaxBar% > HistBlock%% THEN
  186.                 IF Pascal%(1, N%%) = 0 THEN
  187.                     _PUTIMAGE (20 + (HistWidth%% + HistSepn%%) * N%%, HistBase%)-(20 + HistWidth%% + (HistWidth%% + HistSepn%%) * N%%, HistBase%), Histo&, , (0, 0)-(19, 0)
  188.                 ELSE
  189.                     _PUTIMAGE (20 + (HistWidth%% + HistSepn%%) * N%%, HistBase%)-(20 + HistWidth%% + (HistWidth%% + HistSepn%%) * N%%, HistBase% - CINT(Pascal%(1, N%%) * HistHeight% / MaxBar%)), Histo&, , (0, 0)-(19, CINT(Pascal%(1, N%%) * HistHeight% / MaxBar%) - 1)
  190.                 END IF
  191.             ELSE
  192.                 IF Pascal%(1, N%%) = 0 THEN
  193.                     _PUTIMAGE (20 + (HistWidth%% + HistSepn%%) * N%%, HistBase%)-(20 + HistWidth%% + (HistWidth%% + HistSepn%%) * N%%, HistBase%), Histo&, , (0, 0)-(19, 0)
  194.                 ELSE
  195.                     _PUTIMAGE (20 + (HistWidth%% + HistSepn%%) * N%%, HistBase%)-(20 + HistWidth%% + (HistWidth%% + HistSepn%%) * N%%, HistBase% - CINT(Pascal%(1, N%%) * HistHeight% / HistBlock%%)), Histo&, , (0, 0)-(19, CINT(Pascal%(1, N%%) * HistHeight% / MaxBar%) - 1)
  196.                 END IF
  197.             END IF
  198.         NEXT N%%
  199.         IF Pascal%(1, 4) > 0 THEN
  200.             FOR N%% = 0 TO 8
  201.                 S! = Pascal%(1, N%%) / (Pascal%(0, N%%) * (Pascal%(1, 4) / Pascal%(0, 4)))
  202.                 IF S! > 9.99 THEN S! = 9.99
  203.                 IF INT(S!) = S! THEN
  204.                     _PUTIMAGE (24 + (HistWidth%% + HistSepn%%) * N%%, HistBase% + 10), Nos&(INT(S!))
  205.                 ELSE
  206.                     I1%% = INT(S!)
  207.                     XS! = 10 * (S! - I1%%)
  208.                     I3%% = INT(XS!)
  209.                     XS! = 10 * (XS! - I3%%)
  210.                     I4%% = INT(XS!)
  211.                     XS! = 10 * (XS! - I4%%)
  212.                     IF XS! >= 0.5 THEN I4%% = I4%% + 1
  213.                     IF I4%% > 9 THEN
  214.                         I3%% = I3%% + 1
  215.                         I4%% = 0
  216.                     END IF
  217.                     IF I3%% > 9 THEN
  218.                         I1%% = I1%% + 1
  219.                         I3%% = 0
  220.                     END IF
  221.                     _PUTIMAGE (24 + (HistWidth%% + HistSepn%%) * N%%, HistBase% + 10 + 7), Nos&(10)
  222.                     _PUTIMAGE (24 + (HistWidth%% + HistSepn%%) * N%%, HistBase% + 10), Nos&(I1%%)
  223.                     _PUTIMAGE (24 + (HistWidth%% + HistSepn%%) * N%%, HistBase% + 10 + 16), Nos&(I3%%)
  224.                     _PUTIMAGE (24 + (HistWidth%% + HistSepn%%) * N%%, HistBase% + 10 + 25), Nos&(I4%%)
  225.                 END IF
  226.             NEXT N%%
  227.         END IF
  228.         LOCATE 1, 1: PRINT Count&
  229.         _DISPLAY
  230.         DispCount% = 0
  231.     END IF
  232.     'Calculate
  233.     FOR BallNo%% = 0 TO NoBallsLess1%%
  234.         PreviousBall%% = BallNo%% - 1
  235.         IF PreviousBall%% < 0 THEN PreviousBall%% = NoBallsLess1%%
  236.         IF (Vect!(BallNo%%, 0) - Vect!(PreviousBall%%, 0)) * (Vect!(BallNo%%, 0) - Vect!(PreviousBall%%, 0)) + (Vect!(BallNo%%, 1) - Vect!(PreviousBall%%, 1)) * (Vect!(BallNo%%, 1) - Vect!(PreviousBall%%, 1)) > BallDiam%% * BallDiam%% THEN
  237.             IF DoPascal%%(BallNo%%, 0) AND (Vect!(BallNo%%, 1) <= A1%% + 30 + 8 * H! OR NOT DoPascal%%(PreviousBall%%, 1)) THEN
  238.                 Vect!(BallNo%%, 0) = Vect!(BallNo%%, 0) + Vect!(BallNo%%, 2)
  239.                 Vect!(BallNo%%, 1) = Vect!(BallNo%%, 1) + Vect!(BallNo%%, 3)
  240.                 Vect!(BallNo%%, 3) = (F! * Vect!(BallNo%%, 3)) + G!
  241.                 Bounce%% = False
  242.                 N%% = 0
  243.                 WHILE NOT Bounce%% AND N%% <= 53 'FIO Doesn't seem to require external pins
  244.                     IF SQR((Vect!(BallNo%%, 1) - Pins!(1, N%%)) * (Vect!(BallNo%%, 1) - Pins!(1, N%%)) + (Vect!(BallNo%%, 0) - Pins!(0, N%%)) * (Vect!(BallNo%%, 0) - Pins!(0, N%%))) < Separation%% THEN
  245.                         Bounce%% = True
  246.                         CALL Axes((Pins!(1, N%%)), Dum!, YPin1!, Dum1!)
  247.                         CALL Axes(Vect!(BallNo%%, 1), Vect!(BallNo%%, 3), YPosn1!, YVel1!)
  248.                         V! = SQR(Vect!(BallNo%%, 2) * Vect!(BallNo%%, 2) + YVel1! * YVel1!)
  249.                         Theta! = _ATAN2(YVel1!, Vect!(BallNo%%, 2))
  250.                         Beta! = _ATAN2(YPin1! - YPosn1!, Pins!(0, N%%) - Vect!(BallNo%%, 0))
  251.                         Vect!(BallNo%%, 2) = -V! * COS(2 * Beta! - Theta!)
  252.                         YVel1! = -V! * SIN(2 * Beta! - Theta!)
  253.                         Vect!(BallNo%%, 0) = Pins!(0, N%%) - (Separation%% + SmallBit!) * COS(Beta!)
  254.                         YPosn1! = YPin1! - (Separation%% + SmallBit!) * SIN(Beta!)
  255.                         CALL Axes(YPosn1!, YVel1!, Vect!(BallNo%%, 1), Vect!(BallNo%%, 3))
  256.                         Vect!(BallNo%%, 2) = W! * Vect!(BallNo%%, 2) + (0.5 - RND) * Z! 'FIO Not perfectly elastic (with some randomness) TBF
  257.                         Vect!(BallNo%%, 3) = W! * Vect!(BallNo%%, 3)
  258.                     END IF
  259.                     N%% = N%% + 1
  260.                 WEND
  261.                 IF Vect!(BallNo%%, 3) < -SpeedLimit! THEN Vect!(BallNo%%, 3) = -SpeedLimit! 'FIO Gives reasonable coefficients with only -ve Vect!(BallNo%%, 3)
  262.                 IF Vect!(BallNo%%, 1) > A1%% + 30 + 8 * H! AND NOT C%% THEN
  263.                     Count& = Count& + 1
  264.                     Slot%% = CINT(4 + (Vect!(BallNo%%, 0) - (XScreen% / 2)) / Spacing%%)
  265.                     Vect!(BallNo%%, 2) = 0
  266.                     Pascal%(1, Slot%%) = Pascal%(1, Slot%%) + 1
  267.                     C%% = True
  268.                 ELSEIF Vect!(BallNo%%, 1) >= YScreen% - 1 - 8 THEN
  269.                     RANDOMIZE (TIMER)
  270.                     Vect!(BallNo%%, 1) = YScreen% - 1 - A2%%
  271.                     Vect!(BallNo%%, 2) = Bagatelle! * (1 + (8 - Slot%%) / 6)
  272.                     Vect!(BallNo%%, 3) = 0
  273.                     C%% = False
  274.                     DoPascal%%(BallNo%%, 1) = True
  275.                     DoPascal%%(BallNo%%, 0) = False
  276.                 END IF
  277.             ELSEIF DoPascal%%(BallNo%%, 1) OR DoPascal%%(BallNo%%, 2) OR DoPascal%%(BallNo%%, 3) THEN
  278.                 Vect!(BallNo%%, 0) = Vect!(BallNo%%, 0) + Vect!(BallNo%%, 2)
  279.                 Vect!(BallNo%%, 1) = Vect!(BallNo%%, 1) + Vect!(BallNo%%, 3)
  280.                 IF DoPascal%%(BallNo%%, 1) THEN
  281.                     IF Vect!(BallNo%%, 0) >= XScreen% - 1 - A1%% THEN
  282.                         Vect!(BallNo%%, 0) = XScreen% - 1 - A1%%
  283.                         DoPascal%%(BallNo%%, 1) = False
  284.                         DoPascal%%(BallNo%%, 4) = True
  285.                         Vect!(BallNo%%, 4) = 0
  286.                     END IF
  287.                 ELSEIF DoPascal%%(BallNo%%, 2) THEN
  288.                     IF Vect!(BallNo%%, 1) < A1%% THEN
  289.                         Vect!(BallNo%%, 0) = XScreen% - 1 - A2%%
  290.                         Vect!(BallNo%%, 4) = 0
  291.                         DoPascal%%(BallNo%%, 2) = False
  292.                         DoPascal%%(BallNo%%, 5) = True
  293.                     END IF
  294.                 ELSE
  295.                     IF Vect!(BallNo%%, 0) <= XScreen% / 2 + A3%% THEN
  296.                         Vect!(BallNo%%, 0) = XScreen% / 2 + A3%%
  297.                         Vect!(BallNo%%, 4) = 0
  298.                         DoPascal%%(BallNo%%, 3) = False
  299.                         DoPascal%%(BallNo%%, 6) = True
  300.                     END IF
  301.                 END IF
  302.             ELSEIF DoPascal%%(BallNo%%, 4) OR DoPascal%%(BallNo%%, 5) OR DoPascal%%(BallNo%%, 6) THEN
  303.                 IF DoPascal%%(BallNo%%, 4) THEN
  304.                     Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
  305.                     Vect!(BallNo%%, 0) = XScreen% - 1 - A1%% + (A3%% * SIN(Vect!(BallNo%%, 4)))
  306.                     Vect!(BallNo%%, 1) = YScreen% - 1 - A1%% + (A3%% * COS(Vect!(BallNo%%, 4)))
  307.                     IF Vect!(BallNo%%, 1) <= YScreen% - 1 - A1%% THEN
  308.                         Vect!(BallNo%%, 0) = XScreen% - 1 - A2%%
  309.                         Vect!(BallNo%%, 1) = YScreen% - 1 - A1%%
  310.                         Vect!(BallNo%%, 2) = 0
  311.                         Vect!(BallNo%%, 3) = -Bagatelle!
  312.                         DoPascal%%(BallNo%%, 4) = False
  313.                         DoPascal%%(BallNo%%, 2) = True
  314.                     END IF
  315.                 ELSEIF DoPascal%%(BallNo%%, 5) THEN
  316.                     Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
  317.                     Vect!(BallNo%%, 0) = XScreen% - 1 - A1%% + (A3%% * COS(Vect!(BallNo%%, 4)))
  318.                     Vect!(BallNo%%, 1) = A1%% - (A3%% * SIN(Vect!(BallNo%%, 4)))
  319.                     IF Vect!(BallNo%%, 0) < XScreen% - 1 - A1%% THEN
  320.                         Vect!(BallNo%%, 0) = XScreen% - 1 - A1%%
  321.                         Vect!(BallNo%%, 1) = A2%%
  322.                         Vect!(BallNo%%, 2) = -Bagatelle!
  323.                         Vect!(BallNo%%, 3) = 0
  324.                         DoPascal%%(BallNo%%, 5) = False
  325.                         DoPascal%%(BallNo%%, 3) = True
  326.                     END IF
  327.                 ELSE
  328.                     IF Vect!(BallNo%%, 1) <= A1%% THEN
  329.                         Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
  330.                         Vect!(BallNo%%, 0) = XScreen% / 2 + A3%% - (A3%% * SIN(Vect!(BallNo%%, 4)))
  331.                         Vect!(BallNo%%, 1) = A1%% - (A3%% * COS(Vect!(BallNo%%, 4)))
  332.                     ELSEIF NOT DoPascal%%(PreviousBall%%, 0) THEN
  333.                         Vect!(BallNo%%, 0) = XScreen% / 2
  334.                         Vect!(BallNo%%, 1) = A1%%
  335.                         Vect!(BallNo%%, 2) = Z! * (0.5 - RND)
  336.                         Vect!(BallNo%%, 3) = 0.3 + (0.2 * RND)
  337.                         DoPascal%%(BallNo%%, 6) = False
  338.                         DoPascal%%(BallNo%%, 0) = True
  339.                     END IF
  340.                 END IF
  341.             END IF
  342.         END IF
  343.     NEXT BallNo%%
  344.  
  345.  
  346. FUNCTION MakeHardware& (Img&)
  347.     MakeHardware& = _COPYIMAGE(Img&, 33)
  348.     _FREEIMAGE Img&
  349.  
  350. SUB Axes (YIn, VYIn, YOut, VYOut)
  351.     YOut = -YIn
  352.     VYOut = -VYIn
  353.  

* blaise2.ico (Filesize: 66.06 KB, Dimensions: 128x128, Views: 364)
whiteball.png
* whiteball.png (Filesize: 72.74 KB, Dimensions: 300x300, Views: 198)
screenshot.jpg
* screenshot.jpg (Filesize: 108.99 KB, Dimensions: 987x849, Views: 179)
« Last Edit: May 07, 2019, 01:25:49 pm by Qwerkey »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Pascal's Triangle Pinball Demo
« Reply #1 on: May 05, 2019, 10:42:08 am »
Hi Qwerky,

Very impressive graphics! Getting that track drawn and the ball moving through it must of taken some effort.

(Would be nice to put all attachments in a zip file, so everything is in one folder, including font, to check out.)

I am also curious why you start a new thread with every update?
https://www.qb64.org/forum/index.php?topic=1310.0
« Last Edit: May 05, 2019, 10:44:34 am by bplus »

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Pascal's Triangle Pinball Demo
« Reply #2 on: May 05, 2019, 11:13:54 am »
bplus, thanks.  I had imagined that you'd be one to appreciate this.

I do normally put everything in a zipped folder, but I thought that the attachments were so few that people would prefer the individual downloads.  I will stick to my usual method in future.

"Getting that track drawn and the ball moving through it must of taken some effort."

Well no, this is the beauty-beyond-measure of QB64.  With very little effort you can come up with graphics stuff this good (pardon my immodesty).

"Why start a new thread with every update?"

The previous thread was an "in preparation" topic.  In my mind, we've completely finished that.  Odin may give me a dressing-down for cluttering up the site.

Qwerkey.  To expropriate Miss Minnelli "That's Qwerkey with two E's"!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Pascal's Triangle Pinball Demo
« Reply #3 on: May 05, 2019, 11:23:35 am »
Quote
Qwerkey.  To expropriate Miss Minnelli "That's Qwerkey with two E's"!

Woops! sorry, I must have been miss appropriated by your avatar. :-))