The Minesweeper and Calculator Examples

The following two programming examples, Minesweeper and Calculator, utilize ActiveX controls and VBScript. These examples show how ActiveX controls, along with some VBScript code, can be used to create interesting interactive web pages. The complete code for these examples can be found at the end of this chapter and on the companion CD that comes with this book.

The Minesweeper example is a simple Internet version of the popular Microsoft Minesweeper game that shipped with Windows 3.1. Players are presented with a 5-by-5 grid of cells. Cells are "swept" when they are clicked. If the cell doesn't contain a mine, it is cleared along with all the adjacent cells that do not contain mines. Uncovering a mine ends the game. When the player believes that all the mines have been identified, he or she clicks on the Done Sweeping button to see whether he or she has won. Figure 4-16 shows a sample of the minesweeper interface. Listing 4-8, starting on page 104, shows the code for the Internet version of the Minesweeper game. Since some of the code for the Minesweeper example is repetitive, only the basic code structure is included in Listing 4-8. The full program listing is available on the companion CD, in the samples folder.

Figure 4-16.

The Minesweeper interface.

The Minesweeper grid of cells is an HTML table defined by the <TABLE></TABLE> tags. A label control is placed inside each cell with the <OBJECT></OBJECT> tags. Note that this control is not the same as the Label control found in Visual Basic 4.0 and does not support control arrays, which are discussed in more detail later in this section. Therefore, all of the code was created with discrete instances of the Label control. The following code shows the definition of the Label control:

<OBJECT
CLASSID="clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell5" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT> 

The controls are all built into a form called frmSweeper, using the <FORM></FORM> tags. The intrinsic Button controls are added to the form with the <INPUT> tag, as shown here:

<INPUT TYPE="BUTTON" ID="cmdShow" VALUE="Show All Mines" WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdNew" VALUE="New Game" WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdDone" VALUE="Done Sweeping" WIDTH=30> 

These controls will automatically call the associated OnClick event subroutine as coded in VBScript.

As shown in the Minesweeper example, many controls in the Internet Explorer do not support control arrays. A control array is a group of the same controls, all of which have the same name. The controls are differentiated by the values of their index property. Every control in the array can call the same event-handling routine and pass its index value as an argument. Control arrays are great timesavers because when you use them you don't have to write an event-handling routine for each control.

The second example presented in this section is a simple four-function calculator. It uses the OnClick event of intrinsic Button controls to simulate control arrays. In the OnClick event, a separate routine is called, and an index is passed. Listing 4-9, starting on page 113, shows the complete project, but the following code shows the workaround for the control array:

<INPUT TYPE="BUTTON" NAME="btnOne" VALUE="1" 
OnClick="Call NumPad(1)"> 

Note that the OnClick event can be used to execute code directly. This strategy is in contrast to that used in the Minesweeper example, in which the Click events were called because the controls were part of a form. Using the

OnClick event, as we did for the calculator, results in HTML code that is considerably shorter than the code for the Minesweeper game. Figure 4-17 shows a sample of the calculator interface.

Figure 4-17.

The four-function calculator interface.

The remaining portion of this chapter contains the program listings for the Minesweeper and Calculator examples.

<HTML>
<HEAD>
<TITLE>Minesweeper</TITLE>

<!--
This sample creates a Minesweeper game that uses
25 label controls in a table structure.  Players
clear cells by clicking on them. If a cell doesn't
contain a mine, it's cleared along with all
adjacent cells that don't contain mines.  If a cell
contains a mine and the player tries to clear it,
the game is over.
--> 
<SCRIPT LANGUAGE="VBScript">
<!--
    Sub lblCell1_Click
        Call Sweep(1,Document.frmSweeper.lblCell1)
    End Sub

    Sub lblCell2_Click
        Call Sweep(2,Document.frmSweeper.lblCell2)
    End Sub

    Sub lblCell3_Click
        Call Sweep(3,Document.frmSweeper.lblCell3)
    End Sub

    Sub lblCell4_Click
        Call Sweep(4,Document.frmSweeper.lblCell4)
    End Sub

    Sub lblCell5_Click
        Call Sweep(5,Document.frmSweeper.lblCell5)
    End Sub
                              .
                              .
                              .
    Sub lblCell25_Click
        Call Sweep(25,Document.frmSweeper.lblCell25)
    End Sub

    Sub Sweep(intIndex,lblCell)

    'Author: New Technology Solutions, Inc.
    'Purpose: This code handles the Click
    'events for all the labels.  When a
    'label is clicked, we check to see if it
    'contains a mine.
    '5/1/96 Original

        Dim i
        Dim MyForm
        Set MyForm=Document.frmSweeper

        If Playing=0 Then Exit Sub
        If Mine(intIndex)=0 Then
            lblCell.Caption=""
            Call ClearOthers(intIndex) 
        Else 
            lblCell.Caption="*"
            Call YouLose()
        End If
    End Sub

    'Author: New Technology Solutions, Inc.
    'Purpose: The variables are dimensioned
    'here. They are dimensioned inline so that
    'they are available to all code in the page.
    'They are declared when the page loads.
    '5/9/96 Original

    Dim Playing
    Dim Mine(25)
    
    Sub SetCellCaption(ByVal intMine,ByVal strCaption)

    'Author: New Technology Solutions, Inc.
    'Purpose: Set the caption of a label in the grid
    '5/1/96 Original

        Dim MyForm
        Set MyForm=Document.frmSweeper
        
        Select Case intMine
        Case 1
            MyForm.lblCell1.Caption=strCaption
        Case 2
            MyForm.lblCell2.Caption=strCaption
        Case 3
            MyForm.lblCell3.Caption=strCaption
        Case 4
            MyForm.lblCell4.Caption=strCaption
        Case 5
            MyForm.lblCell5.Caption=strCaption
                              .
                              .
                              .
        Case 25
            MyForm.lblCell25.Caption=strCaption
        End Select
    End Sub 

    Function GetCellCaption(ByVal intMine) 
        
    'Author: New Technology Solutions, Inc.
    'Purpose: Return the current label caption
    '5/1/96 Original

        Dim MyForm
        Set MyForm=Document.frmSweeper
        
        If intMine=1 Then _
            GetCellCaption=MyForm.lblCell1.Caption
        If intMine=2 Then _
            GetCellCaption=MyForm.lblCell2.Caption
        If intMine=3 Then _
            GetCellCaption=MyForm.lblCell3.Caption
        If intMine=4 Then _
            GetCellCaption=MyForm.lblCell4.Caption
        If intMine=5 Then _
            GetCellCaption=MyForm.lblCell5.Caption
                              .
                              .
                              .
        If intMine=25 Then _
            GetCellCaption=MyForm.lblCell25.Caption
    End Function
-->
</SCRIPT>

<SCRIPT LANGUAGE="VBScript">
<!--
    Sub ResetGame()
    
    'Author: New Technology Solutions, Inc.
    'Purpose: Reset the variables and the game board
    '5/1/96 Original

        Dim i
        Dim n

        For i=1 to 25
            Mine(i)=0
            Call SetCellCaption(i,"X")
        Next
        Randomize Timer
        For i=1 to 5 
            n=Int(25*Rnd)+1
            Mine(n)=1
        Next
        Playing=1
    End Sub

    Sub ClearOthers(ByVal intMine)

    'Author: New Technology Solutions, Inc.
    'Purpose: This routine clears adjacent
    'cells that do not have a mine in them
    '5/1/96 Original

        Dim MyForm
        Set MyForm=Document.frmSweeper
        
        Select Case intMine
        Case 1
            If Mine(2)=0 Then MyForm.lblCell2.Caption=""
            If Mine(6)=0 Then MyForm.lblCell6.Caption=""
            If Mine(7)=0 Then MyForm.lblCell7.Caption=""
        Case 2
            If Mine(1)=0 Then MyForm.lblCell1.Caption=""
            If Mine(3)=0 Then MyForm.lblCell3.Caption=""
            If Mine(6)=0 Then MyForm.lblCell6.Caption=""
            If Mine(7)=0 Then MyForm.lblCell7.Caption=""
            If Mine(8)=0 Then MyForm.lblCell8.Caption=""
        Case 3
            If Mine(2)=0 Then MyForm.lblCell2.Caption=""
            If Mine(4)=0 Then MyForm.lblCell4.Caption=""
            If Mine(7)=0 Then MyForm.lblCell7.Caption=""
            If Mine(8)=0 Then MyForm.lblCell8.Caption=""
            If Mine(9)=0 Then MyForm.lblCell9.Caption=""
        Case 4
            If Mine(3)=0 Then MyForm.lblCell3.Caption=""
            If Mine(5)=0 Then MyForm.lblCell5.Caption=""
            If Mine(8)=0 Then MyForm.lblCell8.Caption=""
            If Mine(9)=0 Then MyForm.lblCell9.Caption=""
            If Mine(10)=0 Then MyForm.lblCell10.Caption=""
        Case 5
            If Mine(4)=0 Then MyForm.lblCell4.Caption="" 
            If Mine(9)=0 Then MyForm.lblCell9.Caption="" 
            If Mine(10)=0 Then MyForm.lblCell10.Caption=""
                              .
                              .
                              .
        Case 25
            If Mine(24)=0 Then MyForm.lblCell24.Caption=""
            If Mine(19)=0 Then MyForm.lblCell19.Caption=""
            If Mine(20)=0 Then MyForm.lblCell20.Caption=""
        End Select
    End Sub

    Sub YouLose()

    'Author: New Technology Solutions, Inc.
    'Purpose: Display losing message
    '5/1/96 Original

        MsgBox "Oh, no! You Lose!",32,"Minesweeper"
        Playing=0        
    End Sub

    Sub YouWin()

    'Author: New Technology Solutions, Inc.
    'Purpose: Display winning message
    '5/1/96 Original

        MsgBox "Congratulations! You Win!",64,"Minesweeper"
        Playing=0
    End Sub


    Sub cmdNew_OnClick()

    'Author: New Technology Solutions, Inc.
    'Purpose: Initialize game
    '5/1/96 Original

        Call ResetGame()
        MsgBox "Ready to Play!",64,"Minesweeper"    

    End Sub
    Sub cmdDone_OnClick() 

    'Author: New Technology Solutions, Inc.
    'Purpose: This routine is called when the
    'player thinks he or she has found all the mines
    '5/1/96 Original

        Dim blnWinLose
        Dim i

        blnWinLose=1
        For i=1 to 25
            If Mine(i)=0 And GetCellCaption(i)="X" Then
                blnWinLose=0
            End if
        Next
        If blnWinLose=1 Then
            Call YouWin()
        Else
            Call YouLose()
        End If
    End Sub

    Sub cmdShow_OnClick()
    
        'Author: New Technology Solutions, Inc.
        'Purpose: This routine shows all the
        'mine locations for the current game
        '5/1/96 Original

        Dim i

        For i=1 to 25
            If Mine(i)=1 Then
                Call SetCellCaption(i,"*")
            Else
                Call SetCellCaption(i,"")
            End If
        Next
        Playing=0
    End sub
-->
</SCRIPT> 
</HEAD> 
<BODY BGCOLOR="White">
<CENTER>
<H2>Minesweeper!</H2><BR>

<!--
This HTML code builds the form that
contains the label controls and
the buttons
-->

<FORM NAME="frmSweeper">
<FONT FACE="Arial" Size="12">
    <TABLE BORDER CELLPADDING="5" WIDTH=100>
        <TR ALIGN="MIDDLE" VALIGN="BASELINE">
            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblCell1" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>
            
            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblCell2" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>

            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblCell3" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>

            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2" 
            ID="lblCell4" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>

            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblCell5" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>
        </TR>
                              .
                              .
                              .
            <TD ALIGN="CENTER" NOWRAP WIDTH=20>
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblCell25" HEIGHT=20 WIDTH=20>
            <PARAM NAME="Caption" VALUE="X">
            </OBJECT>
            </TD>
        </TR>
        <CAPTION ALIGN="BOTTOM">Click on a cell</CAPTION>
    </TABLE>

<INPUT TYPE="BUTTON" ID="cmdShow" VALUE="Show All Mines" 
WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdNew" VALUE="New Game" WIDTH=30>
<INPUT TYPE="Button" ID="cmdDone" VALUE="Done Sweeping" 
WIDTH=30>
<BR>

</FONT>
</FORM>
</CENTER>

<SCRIPT LANGUAGE="VBScript">
<!-- 

    'This code is called inline after 
    'the rest of the page is set up.
    'It initializes the game.    

    Call ResetGame()
-->
</SCRIPT>

</BODY>
</HTML>

Listing 4-9.

The four-function calculator example.

<HTML> 
<HEAD>
<TITLE>Calculator</TITLE>

<!--
This demo implements a simple four-function
calculator
-->

<SCRIPT LANGUAGE="VBScript">
<!--        
    `Author: New Technology Solutions, Inc.
    `Purpose:
    `These are variables used throughout
    `the calculator.  They are declared
    `inline as the page loads and are
    `available to the entire application.
    `5/1/96 Original

    `Variable for user storage
    Dim dblMemory
    `Flag indicating whether decimal button
    `has been clicked
    Dim blnDecimal
    `Display cache
    Dim dblDisplay
    `Temporary storage for chain calculations
    Dim dblStorage
    `Number of keystrokes entered
    Dim intKeyStrokes
    `Any pending mathematical operations
    Dim intPending
    `Initialize variables 
    dblMemory = 0
    blnDecimal = 0
    intKeyStrokes = 0
    dblDisplay = 0
    dblStorage = 0
    intPending = 0
-->
</SCRIPT>

<SCRIPT LANGUAGE="VBScript">
<!--
    Sub NumPad(intIndex)

        `Author: New Technology Solutions, Inc.
        `Purpose:
        `Receive all button clicks for
        `numbers on the calculator.
        `The buttons do not support control
        `arrays, but note how the OnClick
        `attribute is used as a workaround to
        `call the same routine for each button.
        `5/1/96 Original

        intKeyStrokes = intKeyStrokes + 1
        If blnDecimal=0 Then
            dblDisplay = dblDisplay * 10 + intIndex
        Else
            dblDisplay = dblDisplay + _
            intIndex/(10 ^ intKeyStrokes)
        End If
        Call UpdateDisplay(dblDisplay)
    End Sub
-->
</SCRIPT>

<SCRIPT LANGUAGE="VBScript">
<!--
    Sub btnClear_OnClick

        `Author: New Technology Solutions, Inc.
        `Purpose: Clear the calculator display
        `5/1/96 Original 
        intKeyStrokes = 0 
        dblDisplay = 0
        blnDecimal = 0
        dblStorage = 0
        dblMemory = 0
        Call UpdateDisplay(0)
    End Sub

    Sub btnDecimal_OnClick

        `Author: New Technology Solutions, Inc.
        `Purpose: Handle the Decimal button
        `5/1/96 Original

        intKeyStrokes = 0
        blnDecimal = 1
    End Sub
-->
</SCRIPT>

<SCRIPT LANGUAGE="VBScript">
<!--
    Sub OperationPad(intIndex)

        `Author: New Technology Solutions, Inc.
        `Purpose: Handle addition, subtraction,
        `multiplication, and division
        `5/1/96 Original

        Call DoPending()
        `Reset all flags
        intKeyStrokes = 0
        blnDecimal = 0
        intPending = intIndex
        dblDisplay = 0
        `Update calculator display
        Call UpdateDisplay(dblStorage)
    End Sub

    Sub btnEquals_OnClick

        `Author: New Technology Solutions, Inc.
        `Purpose: Handle Equals key
        `5/1/96 Original
        intKeyStrokes = 0 
        blnDecimal = 0
        Call DoPending()
        dblDisplay = 0
        Call UpdateDisplay(dblStorage)
        dblStorage = 0
    End Sub

    Sub DoPending()

        `Author: New Technology Solutions, Inc.
        `Purpose:
        `Handle any pending actions
        `during chain calculations
        `5/1/96 Original
        
        `No pending operations
        If intPending = 0 Then
            dblStorage = dblDisplay
        End If
        `Chain addition
        If intPending = 1 Then
            dblStorage = dblStorage + dblDisplay
        End If
        `Chain subtraction
        If intPending = 2 Then
            dblStorage = dblStorage - dblDisplay
        End if
        `Chain multiplication
        If intPending = 3 Then
            dblStorage = dblStorage * dblDisplay
        End if
        `Chain division
        If intPending = 4 Then
            If dblStorage = 0 Then
                intPending = 0
                Exit Sub
            End If
            dblStorage = dblStorage / dblDisplay 
        End If
        intPending = 0
    End Sub 
    Sub UpdateDisplay(dblValue) 

        `Author: New Technology Solutions, Inc.
        `Purpose: Refresh the display
        `5/1/96 Original

        Dim MyForm
        Set MyForm = Document.frmCalculator
        MyForm.lblDisplay.Caption = dblValue
    End Sub
-->
</SCRIPT>

<SCRIPT LANGUAGE="VBScript">
<!--
    `Author: New Technology Solutions, Inc.
    `Purpose:
    `All of these routines handle the
    `user-defined storage variable
    `5/1/96 Original

    Sub btnMemRecall_OnClick
        dblDisplay = dblMemory
        Call UpdateDisplay(dblDisplay)
    End Sub

    Sub btnMemMinus_OnClick
        dblMemory = dblMemory - dblDisplay
    End Sub

    Sub btnMemPlus_OnClick
        dblMemory = dblMemory + dblDisplay
    End Sub
-->
</SCRIPT>

</HEAD>
<BODY>
<CENTER>

<FORM NAME="frmCalculator">

<!--
    This HTML builds the actual calculator form
-->
    <TABLE BORDER=2 CELLSPACING=0 CELLPADDING=0 WIDTH=250> 
        <TR>
            <TH COLSPAN=5>
            <!-- 
            This is the label for displaying the results
            -->
            <OBJECT
            CLASSID=
            "clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
            ID="lblDisplay" WIDTH=250 HEIGHT=30>
            <PARAM NAME="Caption" VALUE="0">
            <PARAM NAME="Alignment" VALUE="1">
            <PARAM NAME="ForeColor" VALUE="#000000">
            </OBJECT>
            </TH>
        </TR>
        <TR>
            <TD>
            <INPUT TYPE="BUTTON" NAME="btnSeven"
            VALUE="7" OnClick="Call NumPad(7)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnEight"
            VALUE="8" OnClick="Call NumPad(8)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnNine"
            VALUE="9" OnClick="Call NumPad(9)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnMultiply"
            VALUE="X" OnClick="Call OperationPad(3)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnClear"
            VALUE="Clear">
            </TD>
        </TR>
        <TR>
            <TD>
            <INPUT TYPE="BUTTON" NAME="btnFour"
            VALUE="4" OnClick="Call NumPad(4)">
            </TD> 
            <TD WIDTH=50> 
            <INPUT TYPE="BUTTON" NAME="btnFive"
            VALUE="5" OnClick="Call NumPad(5)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnSix"
            VALUE="6" OnClick="Call NumPad(6)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnMinus"
            VALUE="-" OnClick="Call OperationPad(2)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnMemRecall"
            VALUE="MR">
            </TD>
        </TR>
        <TR>
            <TD>
            <INPUT TYPE="BUTTON" NAME="btnOne"
            VALUE="1" OnClick="Call NumPad(1)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnTwo"
            VALUE="2" OnClick="Call NumPad(2)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnThree"
            VALUE="3" OnClick="Call NumPad(3)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnDivide"
            VALUE="/" OnClick="Call OperationPad(4)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnMemMinus"
            VALUE="M-">
            </TD>
        </TR>
        <TR>
            <TD>
            <INPUT TYPE="BUTTON" NAME="btnZero"
            VALUE="0" OnClick="Call NumPad(0)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnDecimal" 
            VALUE=".">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnEquals"
            VALUE="=">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnPlus"
            VALUE="+" OnClick="Call OperationPad(1)">
            </TD>
            <TD WIDTH=50>
            <INPUT TYPE="BUTTON" NAME="btnMemPlus"
            VALUE="M+">
            </TD>
        </TR>
    </TABLE>
</FORM>

</CENTER>
</BODY>
</HTML> 

© 1996 by Scot Hillier. All rights reserved.