Noughts and Crosses

Noughts and Crosses or Tic-Tac-Toe is a very simple game to play and to create. This tutorial features message boxes, arrays and Drawing using Windows Presentation Foundation (WPF).

www.cespage.com/vb/vb08tut9.html

Step 1

Start Microsoft Visual Basic 2008 Express Edition, then select File then New Project... Choose WPF Application from the New Project Window, enter a name for the Project and then click OK, see below:

New Project

Step 2

A Blank Window named Window1 should then appear, see below:

Window1

Step 3

Then from the Controls tab on the Toolbox select the Grid component:

Grid Component

Step 4

Draw a Grid on the Window or in the XAML Pane below the "<Grid>" type the following:

<Grid Margin="29,0,29,42" Name="Grid1" />

See below:

Window1 with Grid

Step 5

Select or click on the Grid then goto the Properties box, change the Name to "BoardLayout" without the quotes, see below:

Grid Properties

Step 6

Then from the Controls tab on the Toolbox select the Button component:

Button Component

Step 7

Draw a Button on the Window, by dragging the Button from the Toolbox onto the Window, or in the XAML Pane above the bottom "</Grid>" type the following:

<Button Margin="102,0,100,12" Name="Button1" Height="23" VerticalAlignment="Bottom">Button</Button> 

See below:

Window1 with Grid and Button

Step 8

Select or click on the Button (Button1), then goto the Properties box and change the Name to btnNew and the Content property from Button to New Game, see below:

btnNew Properties

Step 9

Right Click on the Window or the entry for "Window1" in the Solution Explorer and choose the "View Code" option then below "Class Window1" type the following:

Private WithEvents btn1, btn2, btn3, btn4, _
btn5, btn6, btn7, btn8, btn9 As New Button
Dim IsCross As Boolean
Dim Nought As String = "O"
Dim Cross As String = "X"
Dim Won As Boolean
Dim Board(3, 3) As String

See Below:

Window1 Declarations

Step 10

While still in the Code View for Window1, above "End Class" type the following:

Private Sub Add(ByRef Grid As Grid, ByRef Button As Button, _
                ByRef Row As Integer, ByRef Column As Integer)
  Button.Margin = New Thickness(5)
  Grid.Children.Add(Button)
  Grid.SetColumn(Button, Column)
  Grid.SetRow(Button, Row)
End Sub

See Below:

Window1 Add Subroutine

Step 11

Again while still in the Code View for Window1, below the "End Sub" for "Private Sub Add(...)", type the following:

Private Sub Layout(ByRef Grid As Grid)
  Grid.ColumnDefinitions.Clear() ' Clear Columns
  Grid.RowDefinitions.Clear() ' Clear Rows
  Grid.Children.Clear() ' Clear the Grid
  Grid.ColumnDefinitions.Add(New ColumnDefinition)
  Grid.ColumnDefinitions.Add(New ColumnDefinition)
  Grid.ColumnDefinitions.Add(New ColumnDefinition)
  Grid.RowDefinitions.Add(New RowDefinition)
  Grid.RowDefinitions.Add(New RowDefinition)
  Grid.RowDefinitions.Add(New RowDefinition)
  Add(Grid, btn1, 0, 0)
  Add(Grid, btn2, 0, 1)
  Add(Grid, btn3, 0, 2)
  Add(Grid, btn4, 1, 0)
  Add(Grid, btn5, 1, 1)
  Add(Grid, btn6, 1, 2)
  Add(Grid, btn7, 2, 0)
  Add(Grid, btn8, 2, 1)
  Add(Grid, btn9, 2, 2)
  For Each Button As Button In Grid.Children
    Button.Content = Nothing ' Clear Buttons
  Next
End Sub

See Below:

Window1 Layout Subroutine

Step 12

While still in the Code View for Window1, below the "End Sub" for "Private Sub Layout(...)", type the following:

Private Function GetPiece(ByRef Button As Button) As String
  If IsCross Then ' Draw X
    Dim Line1, Line2 As New LineGeometry
    Dim Lines As New Path
    Dim LineGroup As New GeometryGroup
    Line1.StartPoint = New Point(0, 0)
    Line1.EndPoint = New Point(50, 50)
    Line2.StartPoint = New Point(50, 0)
    Line2.EndPoint = New Point(0, 50)
    LineGroup.Children.Add(Line1)
    LineGroup.Children.Add(Line2)
    Lines.Stretch = Stretch.Uniform
    Lines.Data = LineGroup
    Lines.Stroke = Brushes.Red
    Lines.StrokeThickness = 4.0
    Lines.Margin = New Thickness(5)
    Button.Content = Lines
    Return Cross
  Else ' Draw O
    Dim CircleGeo As New  _
    EllipseGeometry(New Rect(0, 0, 50, 50))
    Dim Circle As New Path
    Circle.Stretch = Stretch.Uniform
    Circle.Data = CircleGeo
    Circle.Stroke = Brushes.Blue
    Circle.StrokeThickness = 4.0
    Circle.Margin = New Thickness(5)
    Button.Content = Circle
    Return Nought
  End If
End Function

See Below:

Window1 GetPiece Function

Step 13

Again while still in the Code View for Window1, below the "End Function" for "Private Function GetPiece(...)", type the following:

Private Sub SetPiece(ByRef Grid As Grid, ByRef Button As Button)
  Dim Piece As String
  If Button.Content Is Nothing Then
    Piece = GetPiece(Button)
    Board(Grid.GetRow(Button), Grid.GetColumn(Button)) = Piece
  End If
End Sub

See Below:

Window1 SetPiece Subroutine

Step 14

While still in the Code View for Window1, below the "End Sub" for "Private Sub SetPiece(...)", type the following:

Private Sub NewGame()
  Dim Result As MsgBoxResult
  Dim Piece As String
  Layout(BoardLayout) ' Reset Grid
  Board(0, 0) = ""
  Board(0, 1) = ""
  Board(0, 2) = ""
  Board(1, 0) = ""
  Board(1, 1) = ""
  Board(1, 2) = ""
  Board(2, 0) = ""
  Board(2, 1) = ""
  Board(2, 2) = ""
  Won = False
  Result = MsgBox(Cross & " goes first?", _
                  MsgBoxStyle.Question + MsgBoxStyle.YesNo, _
                  "Noughts and Crosses")
  If Result = MsgBoxResult.Yes Then
    IsCross = True
    Piece = Cross
  Else
    IsCross = False
    Piece = Nought
  End If
  Me.Title = "Player:" & Piece
End Sub

See Below:

Window1 NewGame Subroutine

Step 15

Again while still in the Code View for Window1, below the "End Sub" for "Private Sub NewGame()", type the following Function and Sub:

Private Function CheckWinner(ByRef Player As String) As Boolean
  If (Board(0, 0) = Player And Board(0, 1) = Player And Board(0, 2) = Player) Or _
  (Board(1, 0) = Player And Board(1, 1) = Player And Board(1, 2) = Player) Or _
  (Board(2, 0) = Player And Board(2, 1) = Player And Board(2, 2) = Player) Or _
  (Board(0, 0) = Player And Board(1, 0) = Player And Board(2, 0) = Player) Or _
  (Board(0, 1) = Player And Board(1, 1) = Player And Board(2, 1) = Player) Or _
  (Board(0, 2) = Player And Board(1, 2) = Player And Board(2, 2) = Player) Or _
  (Board(0, 0) = Player And Board(1, 1) = Player And Board(2, 2) = Player) Or _
  (Board(0, 2) = Player And Board(1, 1) = Player And Board(2, 0) = Player) Then
    Return True
  End If
End Function

Private Sub CheckDraw()
  If Board(0, 0) <> "" And Board(0, 1) <> "" And Board(0, 2) <> "" _
  And Board(1, 0) <> "" And Board(1, 1) <> "" And Board(1, 2) <> "" _
  And Board(2, 0) <> "" And Board(2, 1) <> "" And Board(2, 2) <> "" Then
    If Not Won Then
      MsgBox("Draw!", MsgBoxStyle.Information, "Noughts and Crosses")
      Me.Title = "Draw!"
      NewGame()
    End If
  End If
End Sub

See Below:

Window1 CheckWinner Function and CheckDraw Subroutine

Step 16

Finally while still in the Code View for Window1, below the "End Sub" for "Private Sub CheckDraw()", type the following:

Private Sub OnClick(ByVal sender As System.Object, _
                     ByVal e As System.Windows.RoutedEventArgs) _
                     Handles btn1.Click, btn2.Click, btn3.Click, _
                     btn4.Click, btn5.Click, btn6.Click, btn7.Click, _
                     btn8.Click, btn9.Click
  Dim Piece As String = ""
  If Not Won Then
    SetPiece(BoardLayout, sender)
    If CheckWinner(Cross) Then
        Piece = Cross
    ElseIf CheckWinner(Nought) Then
        Piece = Nought
    End If
    If Piece <> "" Then
        Won = True
        MsgBox("Player " & Piece & " Won!", _
               MsgBoxStyle.Information, "Noughts and Crosses")
    End If
    CheckDraw()
    IsCross = Not IsCross
    If IsCross Then
      Me.Title = "Player:" & Cross
    Else
      Me.Title = "Player:" & Nought
    End If
  Else
    MsgBox("Game Over!", _
           MsgBoxStyle.Exclamation, "Noughts and Crosses")
    NewGame()
  End If
End Sub

See Below:

Window1 OnClick Subroutine

Step 17

Return to the Design view by selecting the [Design] tab or Right Click on the "View Designer" option in Solution Explorer for Window1. Double Click on the "New Game" Button (btnNew) and type the following in the btnNew_Click() Sub:

NewGame()

See Below:

Window1 New Game Click Event

Step 18

While still in Code View, if not Right Click on the Window or the entry for "Window1" in the Solution Explorer and choose "View Code". The top of this window will have two drop-down boxes one with "(General)" in and the other "(Declarations)", click on the first and select the "(Window1 Events)" Option, then from the drop-down next to this select "Loaded", type the following in the Window1_Loaded Sub:

NewGame()

See Below:

Window1 Loaded Event

Step 19

Save the Project as you have now finished the application, then click on Start:

Start

When you do it will ask "X goes first?", choose either Yes or No, and the following will appear:

Application Running

Step 20

Click on the Buttons to place a O or an X continue until you Win, Lose or Draw, see below:

Game Played

Step 21

Click on the Close button Close on the top right of Window1 to end the application.

This is a very simple game written using Visual Basic 2008 Express Edition, feel free to amend the game as you with, including writing a Computer-based Player 2, try to beat the computer using random numbers, or change the colours of the Noughts and Crosses, plus try resizing the window and see what happens!