
VBScript solution to Event 10 in the 2008 Winter Scripting Games.
Solutions are also available for Windows PowerShell and Perl.
To successfully solve this event you needed to be able to work with arrays and – most likely, depending on your particular solution – nested if statements. This was as much an exercise in logic as in scripting. Here’s what we came up with:
arrFrames = Array(2,5,7,"/",8,1,"X",9,"/",5,3,7,0,4,5,"X",2,0)
iPoints = 0
For i = 0 to UBound(arrFrames) - 1
vFrame = arrFrames(i)
If IsNumeric(vFrame) Then
iPoints = iPoints + vFrame
Else
If vFrame = "/" Then
iPoints = iPoints + (10 - arrFrames(i - 1))
If IsNumeric(arrFrames(i + 1)) Then
iPoints = iPoints + arrFrames(i + 1)
Else
iPoints = iPoints + 10
End If
Else
iPoints = iPoints + 10
If IsNumeric(arrFrames(i + 1)) Then
iPoints = iPoints + arrFrames(i + 1)
If IsNumeric(arrFrames(i + 2)) Then
iPoints = iPoints + arrFrames(i + 2)
Else
iPoints = iPoints + (10 - arrFrames(i + 1))
End If
Else
iPoints = iPoints + 10
If IsNumeric(arrFrames(i + 2)) Then
iPoints = iPoints + arrFrames(i + 2)
Else
iPoints = iPoints + 10
End If
End If
End If
End If
Next
Wscript.Echo iPoints
We started the script with this array, which was given to you as part of the event description:
arrFrames = Array(2,5,7,"/",8,1,"X",9,"/",5,3,7,0,4,5,"X",2,0)
We’re going to be tallying points as we work our way through the array, so we initialize a variable to store the accumulated points:
iPoints = 0
Now it’s time to get down to business. We need to work our way through this array, and typically the best way to work through an array is with a For loop. So that’s exactly what we do:
For i = 0 to UBound(arrFrames) – 1
This loop is going to start at item 0 in our array (the first item – remember, arrays begin indexing at 0 rather than 1) and continue until we’re at the upper bound, or last item, of the array. To find the last item we use the UBound function, passing it the array we’re working with.
Inside the For loop the first thing we do is read the first item from the array, which represents the score from the first ball that was rolled, and assign it to the variable vFrame:
vFrame = arrFrames(i)
Note: Why vFrame rather than iFrame or strFrame? Mainly because our array contains integers and strings, and we never know which we’re reading in, so we identify this variable as a Variant be prefacing it with a v. |
The first thing we want to do is check to see what happened with this first ball: did the bowling ball knock down just a few pins, in which case this item will be the number of pins; was this a spare, meaning the array will contain a slash (/); or was this a strike, which is represented with an X? The first step towards determining which of these possibilities occurred is to call the IsNumeric function to see if the value is numeric:
If IsNumeric(vFrame) Then
The only time we need to do anything special with the scoring is when we’ve encountered a strike or a spare. If we just knocked down a few pins we simply add this number of pins to our total score:
iPoints = iPoints + vFrame
If we received a spare or a strike the value won’t be numeric so we’ll fall into our Else statement, at which point things get a little complicated. We start with another If statement, which one checking to see if the item is a spare (/):
If vFrame = "/" Then
If we’ve received a spare, that means we receive 10 points for the current frame, plus the points from the first roll in the second frame. For example, suppose on our first roll we knocked down 4 pins. At that point we have 4 points. In the second roll we knock down the remaining pins, giving us a spare. The first thing we need to do is calculate how many pins were remaining. We do this by subtracting the value of the previous roll (arrFrames(i - 1), or 4) from the total number of pins (10), like this:
iPoints = iPoints + (10 - arrFrames(i - 1))
Now we have the 10 points from the current frame. Next we need to add the number of points from the next ball rolled. There are two possibilities for the next ball: we knock down some of the pins or we knock down all the pins. If we knock down some of them, the next array item (arrFrames(i + 1)) will contain the number of pins knocked down. If we knock down all the pins, the next array item will be a strike (X). First we check so see if we knocked down some of the pins:
If IsNumeric(arrFrames(i + 1)) Then
If this is the case, we want to add the number of pins to the total points:
iPoints = iPoints + arrFrames(i + 1)
In other words, if we knocked down 8 pins, the score for our spare frame would be 18 (4 + 6 + 8). If instead of just some of the pins we knocked down all the pins, IsNumeric will be False (because our next array item will contain an X), and we simply add 10 points to the total:
iPoints = iPoints + 10
That takes care of a spare. Now what about a strike? A strike means we knocked down all 10 pins on one roll, so the first thing we do is add those 10 points to our total:
iPoints = iPoints + 10
In addition to those 10 points we add the number of points from the next two rolls. Now things really get weird. Basically, we need to redo everything we’ve already done so far. Let’s take a look. First we check to see if the next roll knocks down some of the pins (the next array item IsNumeric):
If IsNumeric(arrFrames(i + 1)) Then
If it is we add that number of pins to the total:
iPoints = iPoints + arrFrames(i + 1)
Remember, we need the next two rolls after a strike. If the next roll was numeric, the one after that has to be either a number or a spare (you can’t get a strike on the second roll; the definition of a strike is knocking down all 10 pins in one roll). So we check the frame at array index i + 2, first to see if it’s numeric:
If IsNumeric(arrFrames(i + 2)) Then
If it is, we simply add that number of pins to the total:
iPoints = iPoints + arrFrames(i + 2)
If it’s not, that means we have a space, so we need to figure out how many pins to add to make up the spare. That number would be 10 minus the number of pins knocked down in roll i + 1:
iPoints = iPoints + (10 - arrFrames(i + 1))
Let’s stop for just a moment before we move on to make sure we understood what we just did. Let’s say we rolled a strike, then our next two rolls were a 5 and then a 4. Our array would look like this:
| Index | Value |
I | X |
i + 1 | 5 |
i + 2 | 4 |
We started by adding 10 points to the total for the strike, so iPoints is equal to 10. Then we check to see if the value at array index i + 1 is numeric. It is, so we add the value of arrFrames(i + 1) (5) to the total, making the total 15. Then we check to see if the value at array index i + 2 is numeric. In this example it is, so we once again add that value to the total, bringing our total to 19.
Now let’s our array looks like this instead:
| Index | Value |
I | X |
i + 1 | 5 |
i + 2 | / |
Once again we add the 10 points for the strike, making iPoints equal to 10. The value of arrFrames(i + 1) – 5 – is numeric, so we add that value to our total, making iPoints equal to 15. The next, arrFrames(i + 2), is not numeric, which means we rolled a spare. So we subtract the value of arrFrames(i + 1) (5) from 10 and add the result (5) to iPoints, giving us 20 points.
Still with us? Good, because there’s more.
Let’s say the value of the next ball rolled isn’t numeric. That can mean only one thing: it was a strike. (You can’t roll a spare on the first roll of a frame, that would make it a strike.) So we add 10 to the total points:
iPoints = iPoints + 10
That takes care of the roll following the strike. Now we need to find out the value of the following roll. It can be only a numeric value or a strike. If it’s a numeric value, we add that value to the total:
If IsNumeric(arrFrames(i + 2)) Then
iPoints = iPoints + arrFrames(i + 2)
If it’s a strike, we add 10 points:
Else
iPoints = iPoints + 10
Like we said, the logic gets a little confusing. Not to mention all the nested if statements. Take a look at all the If statements, plus the For loop, that we have to close out:
End If
End If
End If
End If
Next
But we’re finally done. All that’s left is to echo the number of points:
Wscript.Echo iPoints
And how many points did we score in this game? This many:
107
Which, by the way, isn’t a very good score. (The maximum possible is 300.) It’s higher than the Scripting Guys normally get, but still not good.