Microsoft Small Basic

Program Listing: GRT732-3
' Bowling Game
' Version 0.5b
' Copyright © 2017 Nonki Takahashi. The MIT License.
' Last update 2017-03-12
' Program ID GRT732-3

title = "Bowling Game 0.5b"
GraphicsWindow.Title = title + " - Hit arrow key."
Init()
Form()
GraphicsWindow.KeyDown = OnKeyDown
While "True"
subtotal = ""
For frame = 1 To 10
InitPins()
InitBall()
Position() ' for the first throwing
ThrowBall()
SelectPins() ' to blow
BlowPins()
throw = 1
DrawScore()
If Array.ContainsValue(fell, "False") Then
InitBall()
Position() ' for the second throwing
ThrowBall()
prevPoint = point
SelectPins() ' to blow
BlowPins()
throw = 2
point = point - prevPoint
DrawScore()
EndIf
If (frame = 10) And (subtotal[iPerson][frame] = 10) Then
InitPins()
InitBall()
Position() ' for the third throwing
ThrowBall()
SelectPins() ' to blow
BlowPins()
throw = 3
DrawScore()
EndIf
If frame = 10 Then
DrawTotal()
EndIf
EndFor
DrawTotal()
KeyInput()
ClearScore()
EndWhile

Sub BlowPins
For t = 0 To 1000 Step delay
For i = 1 To 10
If fell[i] Then
x[i] = x[i] + dx[i]
y[i] = y[i] - 5
a[i] = a[i] + da[i]
Shapes.Move(pin[i], x[i], y[i])
Shapes.Rotate(pin[i], a[i])
EndIf
EndFor
If ye <= yb Then
MoveBall()
yb = yb - 2
EndIf
Program.Delay(delay)
EndFor
Shapes.HideShape(ball)
For i = 1 To 10
If fell[i] Then
Shapes.HideShape(pin[i])
EndIf
EndFor
EndSub

Sub ClearScore
For i = 1 To nObj
Shapes.Remove(obj[i])
EndFor
nObj = 0
EndSub

Sub DrawBall
' param xb, yb - ball position
' param ab - ball angle
scale = yb / 212
If shadow = "" Then
GraphicsWindow.BrushColor = "Black"
shadow = Shapes.AddEllipse(78, 20)
Shapes.SetOpacity(shadow, 50)
EndIf
Shapes.Move(shadow, xb - 39, yb - 10)
Shapes.Zoom(shadow, scale, scale)
If ball = "" Then
path = "http://www.nonkit.com/smallbasic.files/Ball.png"
ball = Shapes.AddImage(path)
EndIf
Shapes.Move(ball, xb - 39, yb - 33 * scale - 39)
Shapes.Zoom(ball, scale, scale)
Shapes.Rotate(ball, ab)
EndSub

Sub DrawPoint
' param x, y - left top of the cursor
' param point - point
' param throw
' param frame
' param prevPoint
' return nObj
nObj = nObj + 1
GraphicsWindow.BrushColor = "Black"
If 0 < point Then
obj[nObj] = Shapes.AddText(point)
Else
If frame < 10 Then
If throw = 1 Then
obj[nObj] = Shapes.AddText("G")
Else
obj[nObj] = Shapes.AddText("-")
EndIf
Else
If (prevPoint = 0) Or (prevPoint = 10) Then
obj[nObj] = Shapes.AddText("G")
Else
obj[nObj] = Shapes.AddText("-")
EndIf
EndIf
EndIf
Shapes.Move(obj[nObj], x + 2, y)
EndSub

Sub DrawScore
' param point - point
' param throw
' param frame
' param prevPoint
' return nObj
If frame < 10 Then
x = xo + pw + (frame - 1) * fw + (throw - 1) * fw / 2
Else
x = xo + pw + (frame - 1) * fw + (throw - 1) * fw / 3
EndIf
y = yo + hh + (iPerson - 1) * fh
If frame < 10 Then
If 10 < point + subtotal[iPerson][frame] Then
point = 10 - subtotal[iPerson][frame]
EndIf
Else
If (1 < throw) And (prevPoint < 10) Then
If 10 < point + prevPoint Then
point = 10 - prevPoint
EndIf
EndIf
EndIf
subtotal[iPerson][frame] = subtotal[iPerson][frame] + point
If (1 < frame) And (0 < spare[iPerson][frame - 1]) Then
subtotal[iPerson][frame - 1] = subtotal[iPerson][frame - 1] + point
spare[iPerson][frame - 1] = spare[iPerson][frame - 1] - 1
If spare[iPerson][frame - 1] = 0 Then
frame = frame - 1
DrawTotal()
frame = frame + 1
EndIf
EndIf
If (2 < frame) And (0 < spare[iPerson][frame - 2]) Then
subtotal[iPerson][frame - 2] = subtotal[iPerson][frame - 2] + point
spare[iPerson][frame - 2] = spare[iPerson][frame - 2] - 1
If spare[iPerson][frame - 2] = 0 Then
frame = frame - 2
DrawTotal()
frame = frame + 2
EndIf
EndIf
isSpare = "False"
If (frame < 10) And (subtotal[iPerson][frame] = 10) Then
isSpare = "True"
ElseIf (frame = 10) And (point <> 10) And (1 < throw) And (spare[iPerson][frame][throw - 1] = 0) And (prevPoint + point = 10) Then
isSpare = "True"
EndIf
If point = 10 Then ' strike
If frame < 10 Then
spare[iPerson][frame] = 2
Else
spare[iPerson][frame][throw] = 2
EndIf
DrawStrike()
ElseIf isSpare Then
If frame < 10 Then
spare[iPerson][frame] = 1
Else
spare[iPerson][frame][throw] = 1
EndIf
DrawSpare()
Else
DrawPoint()
If throw = 2 And frame < 10 Then
DrawTotal()
EndIf
EndIf
EndSub

Sub DrawSpare
' param x, y - left top of the cursor
If frame < 10 Then
sw = fw / 2
Else
sw = fw / 3
EndIf
GraphicsWindow.PenWidth = 0
GraphicsWindow.BrushColor = "Black"
nObj = nObj + 1
obj[nObj] = Shapes.AddTriangle(x, y + fh / 2, x + sw, y, x + sw, y + fh / 2)
EndSub

Sub DrawStrike
' param x, y - left top of the cursor
If frame < 10 Then
dx = fw / 2
sw = fw / 2
Else
dx = 0
sw = fw / 3
EndIf
GraphicsWindow.PenWidth = 0
GraphicsWindow.BrushColor = "Black"
nObj = nObj + 1
obj[nObj] = Shapes.AddTriangle(x + dx, y, x + dx, y + fh / 2, x + dx + sw / 2, y + fh / 4)
nObj = nObj + 1
obj[nObj] = Shapes.AddTriangle(x + dx + sw / 2, y + fh / 4, x + dx + sw, y, x + dx + sw, y + fh / 2)
EndSub

Sub DrawTotal
' param frame
' param iPerson
GraphicsWindow.BrushColor = "Black"
_x = xo + pw + (frame - 1) * fw
_y = yo + hh + (iPerson - 0.5) * fh
total = 0
For _i = 1 To frame
total = total + subtotal[iPerson][_i]
EndFor
nObj = nObj + 1
obj[nObj] = Shapes.AddText(total)
Shapes.Move(obj[nObj], _x + 2, _y)
If frame = 10 Then
_x = xo + pw + frame * fw
_y = yo + hh + (iPerson - 1) * fh
nObj = nObj + 1
obj[nObj] = Shapes.AddText(total)
Shapes.Move(obj[nObj], _x + 2, _y)
EndIf
EndSub

Sub Form
GraphicsWindow.PenWidth = 2
GraphicsWindow.PenColor = "GreenYellow"
maxPerson = 1
hh = 22
pw = 100
fw = 44
fh = 44
bh = 26
xo = (gw - pw - fw * 11) / 2
yo = 8
GraphicsWindow.PenWidth = 0
GraphicsWindow.BrushColor = "White"
rect = Shapes.AddRectangle(pw - 2, hh - 2)
Shapes.Move(rect, xo + 1, yo + 1)
GraphicsWindow.BrushColor = "Black"
txt = Shapes.AddText("NAME")
Shapes.Move(txt, xo + 2, yo)
For iFrame = 1 To 11
x = xo + pw + (iFrame - 1) * fw
GraphicsWindow.BrushColor = "White"
rect = Shapes.AddRectangle(fw - 2, hh - 2)
Shapes.Move(rect, x + 1, yo + 1)
GraphicsWindow.BrushColor = "Black"
If iFrame = 11 Then
txt = Shapes.AddText("TOTAL")
Else
txt = Shapes.AddText(iFrame)
EndIf
Shapes.Move(txt, x + 2, yo)
EndFor
For iPerson = 1 To maxPerson
y = yo + hh + (iPerson - 1) * fh
GraphicsWindow.BrushColor = "White"
rect = Shapes.AddRectangle(pw - 2, fh - 2)
Shapes.Move(rect, xo + 1, y + 1)
GraphicsWindow.BrushColor = "Black"
txt = Shapes.AddText("PLAYER")
Shapes.Move(txt, xo + 2, y)
For iFrame = 1 To 11
x = xo + pw + (iFrame - 1) * fw
GraphicsWindow.BrushColor = "White"
rect = Shapes.AddRectangle(fw - 2, fh - 2)
Shapes.Move(rect, x + 1, y + 1)
GraphicsWindow.PenWidth = 2
GraphicsWindow.BrushColor = "Transparent"
If iFrame < 10 Then
rect = Shapes.AddRectangle(fw / 2, fh / 2)
Shapes.Move(rect, x + fw / 2, y)
spare[iPerson][iFrame] = 0
ElseIf iFrame = 10 Then
rect = Shapes.AddRectangle(fw / 3, fh / 2)
Shapes.Move(rect, x, y)
rect = Shapes.AddRectangle(fw / 3, fh / 2)
Shapes.Move(rect, x + fw / 3, y)
rect = Shapes.AddRectangle(fw / 3, fh / 2)
Shapes.Move(rect, x + fw * 2 / 3, y)
spare[iPerson][iFrame][1] = 0
spare[iPerson][iFrame][2] = 0
spare[iPerson][iFrame][3] = 0
EndIf
GraphicsWindow.PenWidth = 0
EndFor
EndFor
y = yo + hh + maxPerson * fh + 4
iPerson = 1
EndSub

Sub Init
Not = "False=True;True=False;"
gw = 598
gh = 428
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
range = "1=7;2=47;3=2478;4=12458;5=123589;6=13569;7=369A;8=6A;9=A;"
beyond = "1=23;2=45;3=56;4=78;5=89;6=9A;"
da = "1=-10;2=-8;3=8;4=-6;5=-6;6=6;7=-4;8=-4;9=4;10=4;"
dx = "1=-3;2=-4;3=4;4=-5;5=-3;6=5;7=-5;8=-4;9=4;10=5;"
GraphicsWindow.BackgroundColor = "LightGray"
' draw gutter
GraphicsWindow.BrushColor = "SaddleBrown"
color = GraphicsWindow.BrushColor
rate = 0.5
Colors_Init()
Color_Blacken()
GraphicsWindow.BrushColor = color
GraphicsWindow.FillTriangle(gw / 2, 60, -70, gh, gw + 70, gh)
' draw lane
ye = 200
GraphicsWindow.BrushColor = "SaddleBrown"
GraphicsWindow.FillTriangle(gw / 2, 60, 0, gh, gw, gh)
GraphicsWindow.BrushColor = "LightGray"
GraphicsWindow.FillRectangle(0, 0, gw, ye)
GraphicsWindow.BrushColor = "Black"
path = "http://www.nonkit.com/smallbasic.files/Pin.png"
i = 6
d = 3
For row = 4 To 1 Step -1
y = 130 - row * 10
For col = 1 To row
i = i + 1
pin[i] = Shapes.AddImage(path)
x = 249 + col * 60 - row * 30
Shapes.Move(pin[i], x, y)
x0[i] = x
y0[i] = y
EndFor
i = i - row - d
d = d - 1
shadow = Shapes.AddRectangle(366, 160)
Shapes.SetOpacity(shadow, 15)
Shapes.Move(shadow, 116, 82)
EndFor
shadow = ""
' draw wall
GraphicsWindow.PenWidth = 0
GraphicsWindow.BrushColor = "GreenYellow"
wall = Shapes.AddRectangle(gw, 82)
Shapes.Move(wall, 0, 0)
wall = Shapes.AddRectangle(116,160)
Shapes.Move(wall, 0, 82)
wall = Shapes.AddRectangle(149, 160)
Shapes.Move(wall, gw - 116, 82)
delay = 10 ' [ms]
EndSub

Sub InitBall
xb = gw / 2 ' ball position
yb = gh + 120
ab = 120 ' ball angle
DrawBall()
EndSub

Sub InitPins
For i = 1 To 10
Shapes.Move(pin[i], x0[i], y0[i])
Shapes.Rotate(pin[i], 0)
Shapes.ShowShape(pin[i])
fell[i] = "False"
EndFor
EndSub

Sub KeyInput
GraphicsWindow.Title = title + " - Hit any key."
While Not[keyDown]
Program.Delay(500)
EndWhile
keyDown = "False"
GraphicsWindow.Title = title + " - Hit arrow key."
EndSub

Sub MoveBall
' param xs - ball start x position
xb = (gw / 2) * (1 - yb / gh) + xs * yb / gh
ab = ab - 4
DrawBall()
Program.Delay(delay)
EndSub

Sub OnKeyDown
keyDown = "True"
EndSub

Sub Position
Shapes.ShowShape(ball)
positioning = "True"
While positioning
If keyDown Then
If GraphicsWindow.LastKey = "Up" Then
positioning = "False"
ElseIf GraphicsWindow.LastKey = "Left" Then
If 0 <= xb - 10 Then
xb = xb - 10
DrawBall()
EndIf
ElseIf GraphicsWindow.LastKey = "Right" Then
If xb + 10 <= gw Then
xb = xb + 10
DrawBall()
EndIf
EndIf
keyDown = "False"
EndIf
EndWhile
EndSub

Sub SelectPins
' param xb - ball position
' return point
point = 0
r = Math.Floor(xb / (gw / 9)) + 1
For i = 1 To 10
c = i
If c = 10 Then
c = "A"
EndIf
If Text.IsSubText(range[r], c) Then
fell[i] = "True"
n = i
While n <> ""
l = Text.GetLength(beyond[n])
If 0 < l Then
n = Text.GetSubText(beyond[n], Math.GetRandomNumber(l), 1)
If n = "A" Then
n = 10
EndIf
fell[n] = "True"
Else
n = ""
EndIf
EndWhile
EndIf
If fell[i] Then
point = point + 1
EndIf
x[i] = x0[i]
y[i] = y0[i]
a[i] = 0
EndFor
EndSub

Sub ThrowBall
Shapes.ShowShape(shadow)
xs = xb
For yb = gh - 1 To 208 Step -2
MoveBall()
EndFor
Shapes.HideShape(shadow)
EndSub

Sub Color_Blacken
' Color | Blacken given color
' param color - given color
' param rate - 0..1
' return color - color blackened
Color_NameToColor()
Color_ColorToRGB()
r = Math.Floor(r * (1 - rate))
g = Math.Floor(g * (1 - rate))
b = Math.Floor(b * (1 - rate))
color = GraphicsWindow.GetColorFromRGB(r, g, b)
EndSub

Sub Color_ColorToRGB
' Color | Convert color to RGB values
' param color - "#rrggbb" (hexadecimal values)
' return r, g, b - RGB values 0..255
sR = Text.GetSubText(color, 2, 2)
sG = Text.GetSubText(color, 4, 2)
sB = Text.GetSubText(color, 6, 2)
hex = sR
Math_Hex2Dec()
r = dec
hex = sG
Math_Hex2Dec()
g = dec
hex = sB
Math_Hex2Dec()
b = dec
EndSub

Sub Color_NameToColor
' Color | Convert color name to color
' param color - color name
' return color -"#rrggbb"
If Text.StartsWith(color, "#") Then
color = Text.ConvertToUpperCase(color)
Else
color = Text.ConvertToLowerCase(color)
color = colors[color]
EndIf
EndSub

Sub Colors_Init
' Colors | Initialize 140 colors array
txt = "aliceblue,antiquewhite,aqua,aquamarine,"
txt = txt + "azure,beige,bisque,black,blanchedalmond,"
txt = txt + "blue,blueviolet,brown,burlywood,"
txt = txt + "cadetblue,chartreuse,chocolate,coral,"
txt = txt + "cornflowerblue,cornsilk,crimson,"
txt = txt + "cyan,darkblue,darkcyan,darkgoldenrod,"
txt = txt + "darkgray,darkgreen,darkkhaki,"
txt = txt + "darkmagenta,darkolivegreen,darkorange,"
txt = txt + "darkorchid,darkred,darksalmon,darkseagreen,"
txt = txt + "darkslateblue,darkslategray,"
txt = txt + "darkturquoise,darkviolet,deeppink,"
txt = txt + "deepskyblue,dimgray,dodgerblue,"
txt = txt + "firebrick,floralwhite,forestgreen,"
txt = txt + "fuchsia,gainsboro,ghostwhite,gold,"
txt = txt + "goldenrod,gray,green,greenyellow,"
txt = txt + "honeydew,hotpink,indianred,indigo,"
txt = txt + "ivory,khaki,lavender,lavenderblush,"
txt = txt + "lawngreen,lemonchiffon,lightblue,"
txt = txt + "lightcoral,lightcyan,lightgoldenrodyellow,"
txt = txt + "lightgray,lightgreen,lightpink,"
txt = txt + "lightsalmon,lightseagreen,lightskyblue,"
txt = txt + "lightslategray,lightsteelblue,"
txt = txt + "lightyellow,lime,limegreen,linen,"
txt = txt + "magenta,maroon,mediumaquamarine,mediumblue,"
txt = txt + "mediumorchid,mediumpurple,mediumseagreen,"
txt = txt + "mediumslateblue,mediumspringgreen,"
txt = txt + "mediumturquoise,mediumvioletred,midnightblue,"
txt = txt + "mintcream,mistyrose,moccasin,navajowhite,"
txt = txt + "navy,oldlace,olive,olivedrab,orange,"
txt = txt + "orangered,orchid,palegoldenrod,palegreen,"
txt = txt + "paleturquoise,palevioletred,papayawhip,"
txt = txt + "peachpuff,peru,pink,plum,powderblue,"
txt = txt + "purple,red,rosybrown,royalblue,saddlebrown,"
txt = txt + "salmon,sandybrown,seagreen,seashell,"
txt = txt + "sienna,silver,skyblue,slateblue,slategray,"
txt = txt + "snow,springgreen,steelblue,"
txt = txt + "tan,teal,thistle,tomato,turquoise,violet,"
txt = txt + "wheat,white,whitesmoke,yellow,yellowgreen"
delim = ","
Text_Split()
saved = GraphicsWindow.PenColor
n = Array.GetItemCount(arry)
For i = 1 To n
GraphicsWindow.PenColor = arry[i]
c = GraphicsWindow.PenColor
colors[arry[i]] = c
EndFor
GraphicsWindow.PenColor = saved
EndSub

Sub Math_Hex2Dec
' Math | Convert hexadecimal to decimal
' param hex
' return dec
dec = 0
len = Text.GetLength(hex)
For ptr = 1 To len
dec = dec * 16 + Text.GetIndexOf("123456789ABCDEF", Text.GetSubText(hex, ptr, 1))
EndFor
EndSub

Sub Text_Split
' Text | Split text to array by delimiter
' param txt - to split
' param delim - delimiter
' return arry - splitted
len = Text.GetLength(txt)
p = 1
n = 0
d = Text.GetIndexOf(Text.GetSubTextToEnd(txt, p), delim)
While (0 < d) And (p <= len)
n = n + 1
arry[n] = Text.GetSubText(txt, p, d - 1)
p = p + d
d = Text.GetIndexOf(Text.GetSubTextToEnd(txt, p), delim)
EndWhile
n = n + 1
arry[n] = Text.GetSubTextToEnd(txt, p)
EndSub