'Pascal's Triangle Simulation by QWERKEY 04/05/19
CONST True
= -1, False
= 0 CONST FrameRate%
= 60, CalcRate%
= 600 CONST BallDiam%%
= 60, PinRad%%
= 7, Separation%%
= (BallDiam%%
/ 2) + PinRad%%
, Spacing%%
= BallDiam%%
+ (2 * PinRad%%
) + 6 CONST H0!
= SQR(0.75), H!
= Spacing%%
* H0!
CONST XScreen%
= 980, YScreen%
= 820, SmallBit!
= 0.2, CornRad%%
= 50, NoBallsLess1%%
= 4 CONST A1%%
= 16 + BallDiam%%
+ CornRad%%
, A2%%
= 8 + BallDiam%%
/ 2, A3%%
= CornRad%%
+ 8 + BallDiam%%
/ 2 CONST A4%%
= 16 + BallDiam%%
, A5%%
= 8 + BallDiam%%
CONST HistBase%
= 380, HistHeight%
= 340, HistWidth%%
= 22, HistSepn%%
= 5, HistBlock%%
= 20 CONST G!
= 0.2, F!
= 0.97, W!
= 0.8, Z!
= 0.05, Bagatelle!
= 0.8, Omega!
= Bagatelle!
/ A3%%
, SpeedLimit!
= 3.5 DIM Pascal%
(1, 8), Nos&
(10), Pins!
(1, 53), Vect!
(NoBallsLess1%%
, 4), DoPascal%%
(NoBallsLess1%%
, 6)
DATA 1,8,28,56,70,56,28,8,1 'Images
TempImg&
= _NEWIMAGE(BallDiam%%
, BallDiam%%
, 32)Ball& = MakeHardware&(TempImg&)
Pin&
= _NEWIMAGE(PinRad%%
* 2 + 1, PinRad%%
* 2 + 1, 32) CIRCLE (PinRad%%
, PinRad%%
), N%%
, _RGB32(CINT(181 * (N%%
+ 5) / (PinRad%%
+ 5)), CINT(166 * (N%%
+ 5) / (PinRad%%
+ 5)), CINT(66 * (N%%
+ 5) / (PinRad%%
+ 5))) PAINT (PinRad%%
, PinRad%%
), _RGB32(CINT(181 * (N%%
+ 5) / (PinRad%%
+ 5)), CINT(166 * (N%%
+ 5) / (PinRad%%
+ 5)), CINT(66 * (N%%
+ 5) / (PinRad%%
+ 5))) T% = 0
_PUTIMAGE ((XScreen%
/ 2) + CINT(M%%
* Spacing%%
/ 2) - PinRad%%
, A1%%
+ 30 - PinRad%%
+ CINT(H!
* N%%
)), Pin&
Pins!(0, T%) = (XScreen% / 2) + (M%% * Spacing%% / 2)
Pins!(1, T%) = A1%% + 30 + (H! * N%%)
T% = T% + 1
L% = 700
T% = 130
_MAPTRIANGLE (0, 127)-(63, 127)-(63, 16), B&
TO(L%
+ 0, T%
+ 127)-(L%
+ 63, T%
+ 127)-(L%
+ 63, T%
+ 16) _MAPTRIANGLE (127, 127)-(63, 127)-(63, 16), B&
TO(L%
+ 127, T%
+ 127)-(L%
+ 63, T%
+ 127)-(L%
+ 63, T%
+ 16) font&
= _LOADFONT("cyberbit.ttf", 30, "bold")LINE (90, YScreen%
- 1)-(XScreen%
- 1 - A1%%
, YScreen%
- 1 - A4%%
), _RGB32(229, 170, 112), BF
LINE (90, YScreen%
- 1)-(XScreen%
- 1 - A1%%
, YScreen%
- 1 - 8), _RGB32(193, 117, 46), BF
LINE (90, YScreen%
- 1 - A4%%
)-(120, YScreen%
- 1 - A5%%
), _RGB32(193, 117, 46), BF
LINE (90, YScreen%
- 1 - A4%%
)-(98, YScreen%
- 1), _RGB32(193, 117, 46), BF
LINE (121, YScreen%
- 1 - A4%%
)-(XScreen%
- 1 - A1%%
, YScreen%
- 1 - A5%%
), _RGBA32(193, 117, 46, 80), BF
LINE (XScreen%
- 1 - A4%%
, A1%%
)-(XScreen%
- 1, YScreen%
- 1 - A1%%
), _RGB32(229, 170, 112), BF
LINE (XScreen%
- 1 - 8, A1%%
)-(XScreen%
- 1, YScreen%
- 1 - A1%%
), _RGB32(193, 117, 46), BF
LINE (XScreen%
- 1 - A5%%
, A1%%
)-(XScreen%
- 1 - A5%%
- 8, YScreen%
- 1 - A1%%
), _RGB32(193, 117, 46), BF
LINE (XScreen%
/ 2 + BallDiam%%
/ 2 + CornRad%%
, 0)-(XScreen%
- 1 - A1%%
, A4%%
), _RGB32(229, 170, 112), BF
LINE (XScreen%
/ 2 + BallDiam%%
/ 2 + CornRad%%
, 0)-(XScreen%
- 1 - A1%%
, 8), _RGB32(193, 117, 46), BF
LINE (XScreen%
/ 2 + BallDiam%%
/ 2 + CornRad%%
, A4%%
- 8)-(XScreen%
- 1 - A1%%
, A4%%
), _RGB32(193, 117, 46), BF
_PUTIMAGE (XScreen%
- 1 - A1%%
, YScreen%
- 1 - A1%%
), Corn&
_MAPTRIANGLE (0, 0)-(A1%%
- 1, 0)-(A1%%
- 1, A1%%
- 1), Corn&
TO(XScreen%
- 1 - A1%%
, A1%%
)-(XScreen%
- 1 - A1%%
, 0)-(XScreen%
- 1, 0) _MAPTRIANGLE (A1%%
- 1, A1%%
- 1)-(0, A1%%
- 1)-(0, 0), Corn&
TO(XScreen%
- 1, 0)-(XScreen%
- 1, A1%%
)-(XScreen%
- 1 - A1%%
, A1%%
) _MAPTRIANGLE (0, 0)-(A1%%
- 1, 0)-(A1%%
- 1, A1%%
- 1), Corn&
TO(XScreen%
/ 2 + A3%%
, A1%%
)-(XScreen%
/ 2 - A2%%
, A1%%
)-(XScreen%
/ 2 - A2%%
, 0) _MAPTRIANGLE (A1%%
- 1, A1%%
- 1)-(0, A1%%
- 1)-(0, 0), Corn&
TO(XScreen%
/ 2 - A2%%
, 0)-(XScreen%
/ 2 + A3%%
, 0)-(XScreen%
/ 2 + A3%%
, A1%%
) Background& = MakeHardware&(TempImg&)
Histo& = MakeHardware&(TempImg&)
'Initialise
MaxBar% = 0
C%% = False
DoPascal%%(0, 0) = True
DoPascal%%(0, 1) = False
DoPascal%%(0, 2) = False
DoPascal%%(0, 3) = False
DoPascal%%(0, 4) = False
DoPascal%%(0, 5) = False
DoPascal%%(0, 6) = False
Vect!(0, 0) = XScreen% / 2
Vect!(0, 1) = A1%% + 10
Vect!
(0, 2) = Z!
* (0.5 - RND)Vect!
(0, 3) = 0.3 + (0.2 * RND)DoPascal%%(1, 0) = False
DoPascal%%(1, 1) = False
DoPascal%%(1, 2) = False
DoPascal%%(1, 3) = True
DoPascal%%(1, 4) = False
DoPascal%%(1, 5) = False
DoPascal%%(1, 6) = False
Vect!(1, 0) = XScreen% - A1%%
Vect!(1, 1) = A2%%
Vect!(1, 2) = -Bagatelle!
Vect!(1, 3) = 0
DoPascal%%(2, 0) = False
DoPascal%%(2, 1) = False
DoPascal%%(2, 2) = True
DoPascal%%(2, 3) = False
DoPascal%%(2, 4) = False
DoPascal%%(2, 5) = False
DoPascal%%(2, 6) = False
Vect!(2, 0) = XScreen% - A2%%
Vect!(2, 1) = A1%% + 10
Vect!(2, 2) = 0
Vect!(2, 3) = -Bagatelle!
DoPascal%%(3, 0) = False
DoPascal%%(3, 1) = False
DoPascal%%(3, 2) = True
DoPascal%%(3, 3) = False
DoPascal%%(3, 4) = False
DoPascal%%(3, 5) = False
DoPascal%%(3, 6) = False
Vect!(3, 0) = XScreen% - A2%%
Vect!(3, 1) = YScreen% - 1 - A1%% - 10
Vect!(3, 2) = 0
Vect!(3, 3) = -Bagatelle!
DoPascal%%(4, 0) = False
DoPascal%%(4, 1) = True
DoPascal%%(4, 2) = False
DoPascal%%(4, 3) = False
DoPascal%%(4, 4) = False
DoPascal%%(4, 5) = False
DoPascal%%(4, 6) = False
Vect!(4, 0) = XScreen% / 2
Vect!(4, 1) = YScreen% - A2%%
Vect!(4, 2) = 1.8 * Bagatelle!
Vect!(4, 3) = 0
DispCount% = DispCount% + 1
'Display Images
'CLS
FOR N%%
= 0 TO NoBallsLess1%%
_PUTIMAGE (CINT(Vect!
(N%%
, 0) - (BallDiam%%
/ 2)), CINT(Vect!
(N%%
, 1) - (BallDiam%%
/ 2))), Ball&
IF Pascal%
(1, N%%
) > MaxBar%
THEN MaxBar%
= Pascal%
(1, N%%
) _PUTIMAGE (20 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
)-(20 + HistWidth%%
+ (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
), Histo&
, , (0, 0)-(19, 0) _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) _PUTIMAGE (20 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
)-(20 + HistWidth%%
+ (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
), Histo&
, , (0, 0)-(19, 0) _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) S! = Pascal%(1, N%%) / (Pascal%(0, N%%) * (Pascal%(1, 4) / Pascal%(0, 4)))
_PUTIMAGE (24 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
+ 10), Nos&
(INT(S!
)) XS! = 10 * (S! - I1%%)
XS! = 10 * (XS! - I3%%)
XS! = 10 * (XS! - I4%%)
IF XS!
>= 0.5 THEN I4%%
= I4%%
+ 1 I3%% = I3%% + 1
I4%% = 0
I1%% = I1%% + 1
I3%% = 0
_PUTIMAGE (24 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
+ 10 + 7), Nos&
(10) _PUTIMAGE (24 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
+ 10), Nos&
(I1%%
) _PUTIMAGE (24 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
+ 10 + 16), Nos&
(I3%%
) _PUTIMAGE (24 + (HistWidth%%
+ HistSepn%%
) * N%%
, HistBase%
+ 10 + 25), Nos&
(I4%%
) DispCount% = 0
'Calculate
FOR BallNo%%
= 0 TO NoBallsLess1%%
PreviousBall%% = BallNo%% - 1
IF PreviousBall%%
< 0 THEN PreviousBall%%
= NoBallsLess1%%
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 IF DoPascal%%
(BallNo%%
, 0) AND (Vect!
(BallNo%%
, 1) <= A1%%
+ 30 + 8 * H!
OR NOT DoPascal%%
(PreviousBall%%
, 1)) THEN Vect!(BallNo%%, 0) = Vect!(BallNo%%, 0) + Vect!(BallNo%%, 2)
Vect!(BallNo%%, 1) = Vect!(BallNo%%, 1) + Vect!(BallNo%%, 3)
Vect!(BallNo%%, 3) = (F! * Vect!(BallNo%%, 3)) + G!
Bounce%% = False
N%% = 0
WHILE NOT Bounce%%
AND N%%
<= 53 'FIO Doesn't seem to require external pins 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 Bounce%% = True
CALL Axes
((Pins!
(1, N%%
)), Dum!
, YPin1!
, Dum1!
) CALL Axes
(Vect!
(BallNo%%
, 1), Vect!
(BallNo%%
, 3), YPosn1!
, YVel1!
) V!
= SQR(Vect!
(BallNo%%
, 2) * Vect!
(BallNo%%
, 2) + YVel1!
* YVel1!
) Theta!
= _ATAN2(YVel1!
, Vect!
(BallNo%%
, 2)) Beta!
= _ATAN2(YPin1!
- YPosn1!
, Pins!
(0, N%%
) - Vect!
(BallNo%%
, 0)) Vect!
(BallNo%%
, 2) = -V!
* COS(2 * Beta!
- Theta!
) YVel1!
= -V!
* SIN(2 * Beta!
- Theta!
) Vect!
(BallNo%%
, 0) = Pins!
(0, N%%
) - (Separation%%
+ SmallBit!
) * COS(Beta!
) YPosn1!
= YPin1!
- (Separation%%
+ SmallBit!
) * SIN(Beta!
) CALL Axes
(YPosn1!
, YVel1!
, Vect!
(BallNo%%
, 1), Vect!
(BallNo%%
, 3)) Vect!
(BallNo%%
, 2) = W!
* Vect!
(BallNo%%
, 2) + (0.5 - RND) * Z!
'FIO Not perfectly elastic (with some randomness) TBF Vect!(BallNo%%, 3) = W! * Vect!(BallNo%%, 3)
N%% = N%% + 1
IF Vect!
(BallNo%%
, 3) < -SpeedLimit!
THEN Vect!
(BallNo%%
, 3) = -SpeedLimit!
'FIO Gives reasonable coefficients with only -ve Vect!(BallNo%%, 3) Count& = Count& + 1
Slot%%
= CINT(4 + (Vect!
(BallNo%%
, 0) - (XScreen%
/ 2)) / Spacing%%
) Vect!(BallNo%%, 2) = 0
Pascal%(1, Slot%%) = Pascal%(1, Slot%%) + 1
C%% = True
ELSEIF Vect!
(BallNo%%
, 1) >= YScreen%
- 1 - 8 THEN Vect!(BallNo%%, 1) = YScreen% - 1 - A2%%
Vect!(BallNo%%, 2) = Bagatelle! * (1 + (8 - Slot%%) / 6)
Vect!(BallNo%%, 3) = 0
C%% = False
DoPascal%%(BallNo%%, 1) = True
DoPascal%%(BallNo%%, 0) = False
ELSEIF DoPascal%%
(BallNo%%
, 1) OR DoPascal%%
(BallNo%%
, 2) OR DoPascal%%
(BallNo%%
, 3) THEN Vect!(BallNo%%, 0) = Vect!(BallNo%%, 0) + Vect!(BallNo%%, 2)
Vect!(BallNo%%, 1) = Vect!(BallNo%%, 1) + Vect!(BallNo%%, 3)
IF DoPascal%%
(BallNo%%
, 1) THEN IF Vect!
(BallNo%%
, 0) >= XScreen%
- 1 - A1%%
THEN Vect!(BallNo%%, 0) = XScreen% - 1 - A1%%
DoPascal%%(BallNo%%, 1) = False
DoPascal%%(BallNo%%, 4) = True
Vect!(BallNo%%, 4) = 0
IF Vect!
(BallNo%%
, 1) < A1%%
THEN Vect!(BallNo%%, 0) = XScreen% - 1 - A2%%
Vect!(BallNo%%, 4) = 0
DoPascal%%(BallNo%%, 2) = False
DoPascal%%(BallNo%%, 5) = True
IF Vect!
(BallNo%%
, 0) <= XScreen%
/ 2 + A3%%
THEN Vect!(BallNo%%, 0) = XScreen% / 2 + A3%%
Vect!(BallNo%%, 4) = 0
DoPascal%%(BallNo%%, 3) = False
DoPascal%%(BallNo%%, 6) = True
ELSEIF DoPascal%%
(BallNo%%
, 4) OR DoPascal%%
(BallNo%%
, 5) OR DoPascal%%
(BallNo%%
, 6) THEN IF DoPascal%%
(BallNo%%
, 4) THEN Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
Vect!
(BallNo%%
, 0) = XScreen%
- 1 - A1%%
+ (A3%%
* SIN(Vect!
(BallNo%%
, 4))) Vect!
(BallNo%%
, 1) = YScreen%
- 1 - A1%%
+ (A3%%
* COS(Vect!
(BallNo%%
, 4))) IF Vect!
(BallNo%%
, 1) <= YScreen%
- 1 - A1%%
THEN Vect!(BallNo%%, 0) = XScreen% - 1 - A2%%
Vect!(BallNo%%, 1) = YScreen% - 1 - A1%%
Vect!(BallNo%%, 2) = 0
Vect!(BallNo%%, 3) = -Bagatelle!
DoPascal%%(BallNo%%, 4) = False
DoPascal%%(BallNo%%, 2) = True
Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
Vect!
(BallNo%%
, 0) = XScreen%
- 1 - A1%%
+ (A3%%
* COS(Vect!
(BallNo%%
, 4))) Vect!
(BallNo%%
, 1) = A1%%
- (A3%%
* SIN(Vect!
(BallNo%%
, 4))) IF Vect!
(BallNo%%
, 0) < XScreen%
- 1 - A1%%
THEN Vect!(BallNo%%, 0) = XScreen% - 1 - A1%%
Vect!(BallNo%%, 1) = A2%%
Vect!(BallNo%%, 2) = -Bagatelle!
Vect!(BallNo%%, 3) = 0
DoPascal%%(BallNo%%, 5) = False
DoPascal%%(BallNo%%, 3) = True
IF Vect!
(BallNo%%
, 1) <= A1%%
THEN Vect!(BallNo%%, 4) = Vect!(BallNo%%, 4) + Omega!
Vect!
(BallNo%%
, 0) = XScreen%
/ 2 + A3%%
- (A3%%
* SIN(Vect!
(BallNo%%
, 4))) Vect!
(BallNo%%
, 1) = A1%%
- (A3%%
* COS(Vect!
(BallNo%%
, 4))) Vect!(BallNo%%, 0) = XScreen% / 2
Vect!(BallNo%%, 1) = A1%%
Vect!
(BallNo%%
, 2) = Z!
* (0.5 - RND) Vect!
(BallNo%%
, 3) = 0.3 + (0.2 * RND) DoPascal%%(BallNo%%, 6) = False
DoPascal%%(BallNo%%, 0) = True
SUB Axes
(YIn
, VYIn
, YOut
, VYOut
) YOut = -YIn
VYOut = -VYIn