Memory Game

Memory Game is a simple random shape matching game that can be created with this Tutorial in Silverlight.

www.cespage.com/silverlight/sl4tut10.html

Step 1

Start Microsoft Visual Web Developer 2010 Express, then Select File then New Project... Select "Visual Basic" then "Silverlight Application" from Templates, select a Location if you wish, then enter a name for the Project and then click OK, see below:

New Project

Step 2

New Silverlight Application window should appear, uncheck the box "Host the Silverlight Application in a new Web site" and then select the required Silverlight Version, see below:

New Silverlight Application

Step 3

A Blank Page named MainPage.xaml should then appear, see below:

MainPage.xaml

Step 4

Then from the All Silverlight Controls section in the Toolbox select the Canvas control:

Canvas Control

Step 5

Draw a Canvas that fill the whole Page or in the XAML Pane between the "<Grid>" and "</Grid>" lines type the following XAML:

<Canvas Height="300" Width="400" HorizontalAlignment="Left" VerticalAlignment="Top" Name="Page">
</Canvas>

See below:

MainPage with Canvas

Step 6

Then from the Common Silverlight Controls section in the Toolbox select the Grid control:

Grid Control

Step 7

Draw a Grid on the Canvas by dragging a Grid from the Toolbox onto the Canvas then in the XAML Pane inbetween the "<Canvas>" and "</Canvas>" tags change the "<Grid> line to the following:

<Grid Canvas.Left="75" Canvas.Top="0" Height="250" Width="250" Name="Display"/>

See below:

MainPage with Canvas and Grid

Step 8

Then from the Common Silverlight Controls section in the Toolbox select the Button control:

Button Control

Step 9

Draw a Button on the Canvas by dragging the Button from the Toolbox onto the Canvas, then in the XAML Pane below the "<StackPanel>" tag change the "<Button>" line to the following:

<Button Canvas.Left="163" Canvas.Top="263" Height="23" Width="75" Name="New" Content="New"/> 

See below:

MainPage with Canvas, Grid and Button

Step 10

Right Click on the Page or the entry for "MainPage.xaml" in Solution Explorer and choose the "View Code" option. In the Code View below the "Inherits UserControl" line type the following:

Private _moves As Integer = 0
Private _first As Integer = 0
Private _second As Integer = 0
Private _firstButton As Button
Private _secondButton As Button
Private _board(4, 4) As Integer
Private _matches As New List(Of Integer)
Private _timer As New Windows.Threading.DispatcherTimer

See Below:

MainPage.xaml Declarations

Step 11

While still in the Code View for MainPage.xaml, below the "End Sub" for "Public Sub New()" Constructor type the following Function:

Private Function Shape(ByRef Points As _
    System.Windows.Media.PointCollection) As Object
  Dim _shape As New Polygon
  _shape.Stretch = Stretch.Uniform
  _shape.StrokeLineJoin = PenLineJoin.Round
  _shape.Points = Points
  _shape.Height = 30
  _shape.Width = _shape.Height
  _shape.Stroke = New SolidColorBrush(Colors.Black)
  _shape.StrokeThickness = 4.0
  _shape.Margin = New Thickness(5)
  Return _shape
End Function

See Below:

MainPage Shape Function

Step 12

While still in the Code View for MainPage.xaml, below "End Function" for "Private Function Shape(...)" Function, type the following Function:

Private Function Card(ByRef Type As Integer) As Object
  Dim _points As New System.Windows.Media.PointCollection
  Select Case Type
    Case 1 ' Circle
      Dim _ellipse As New EllipseGeometry
      Dim _circle As New Path
      _ellipse.Center = New Point(15, 15)
      _ellipse.RadiusX = 15
      _ellipse.RadiusY = 15
      _circle.Data = _ellipse
      _circle.Stroke = New SolidColorBrush(Colors.Black)
      _circle.StrokeThickness = 4.0
      _circle.Margin = New Thickness(5)
      Return _circle
    Case 2 ' Cross
      Dim _lines As New Path
      Dim _line1, _line2 As New LineGeometry
      Dim _linegroup As New GeometryGroup
      _line1.StartPoint = New Point(0, 0)
      _line1.EndPoint = New Point(30, 30)
      _line2.StartPoint = New Point(30, 0)
      _line2.EndPoint = New Point(0, 30)
      _linegroup.Children.Add(_line1)
      _linegroup.Children.Add(_line2)
      _lines.Data = _linegroup
      _lines.Stroke = New SolidColorBrush(Colors.Black)
      _lines.StrokeThickness = 4.0
      _lines.Margin = New Thickness(5)
      Return _lines
    Case 3 ' Triangle
      _points.Add(New Point(150, 0))
      _points.Add(New Point(0, 250))
      _points.Add(New Point(300, 250))
      Return Shape(_points)
    Case 4 ' Square
      _points.Add(New Point(0, 0))
      _points.Add(New Point(0, 100))
      _points.Add(New Point(100, 100))
      _points.Add(New Point(100, 0))
      Return Shape(_points)
    Case 5 ' Pentagon
      _points.Add(New Point(0, 125))
      _points.Add(New Point(150, 0))
      _points.Add(New Point(300, 125))
      _points.Add(New Point(250, 300))
      _points.Add(New Point(50, 300))
      Return Shape(_points)
    Case 6 ' Hexagon
      _points.Add(New Point(75, 0))
      _points.Add(New Point(225, 0))
      _points.Add(New Point(300, 150))
      _points.Add(New Point(225, 300))
      _points.Add(New Point(75, 300))
      _points.Add(New Point(0, 150))
      Return Shape(_points)
    Case 7 ' Star
      _points.Add(New Point(9, 2))
      _points.Add(New Point(11, 7))
      _points.Add(New Point(17, 7))
      _points.Add(New Point(12, 10))
      _points.Add(New Point(14, 15))
      _points.Add(New Point(9, 12))
      _points.Add(New Point(4, 15))
      _points.Add(New Point(6, 10))
      _points.Add(New Point(1, 7))
      _points.Add(New Point(7, 7))
      Return Shape(_points)
    Case 8 ' Rhombus
      _points.Add(New Point(50, 0))
      _points.Add(New Point(100, 50))
      _points.Add(New Point(50, 100))
      _points.Add(New Point(0, 50))
      Return Shape(_points)
    Case Else
      Return Type
  End Select
End Function

See Below:

MainPage Card Function

Step 13

While still in the Code View for MainPage.xaml, below the "End Function" for "Private Function Card(...)" type the following Subs:

Private Sub Clear()
  If Not _firstButton Is Nothing Then
    _firstButton.Content = Nothing
    _firstButton = Nothing
  End If
  If Not _secondButton Is Nothing Then
    _secondButton.Content = Nothing
    _secondButton = Nothing
  End If
  _timer.Stop()
End Sub

Private Sub Button_Click(ByVal sender As System.Object, _
    ByVal e As System.Windows.RoutedEventArgs)
  Dim _btn As New Button
  Dim _row, _col, _selected As Integer
  If Not _timer.IsEnabled Then
    _btn = CType(sender, Button)
    _row = _btn.GetValue(Grid.RowProperty)
    _col = _btn.GetValue(Grid.ColumnProperty)
    _selected = _board(_row, _col)
    If _matches.IndexOf(_selected) < 0 Then ' No Match
      If _first = 0 Then
        _firstButton = _btn
        _first = _selected
        _firstButton.Content = Card(_selected)
      ElseIf _second = 0 Then
        _secondButton = _btn
        If Not _firstButton.Equals(_secondButton) Then ' Different
          _second = _selected
          _secondButton.Content = Card(_selected)
          If _first = _second Then ' Is Match
            _matches.Add(_first)
            _matches.Add(_second)
            MessageBox.Show("Match!", "Memory Game", MessageBoxButton.OK)
            If _matches.Count = 16 Then
              MessageBox.Show("Well Done! You matched them all in " & _moves & " moves!", _
                "Memory Game", MessageBoxButton.OK)
            End If
          Else ' No Match
            _timer.Interval = TimeSpan.FromSeconds(1.5)
            AddHandler _timer.Tick, AddressOf Clear ' Clear Buttons after 1.5 Seconds
            _timer.Start()
          End If
          _moves += 1
          _first = 0
          _second = 0
        End If
      End If
    End If
  End If
End Sub

See Below:

MainPage Clear and Button Click Subs

Step 14

While still in the Code View for MainPage.xaml, below the "End Sub" for "Private Sub Button_Click(...)" type the following Subs:

Private Sub Add(ByRef Grid As Grid, ByRef Row As Integer, ByRef Column As Integer)
  Dim _btn As New Button
  AddHandler _btn.Click, AddressOf Button_Click
  _btn.Content = Nothing
  _btn.Margin = New Thickness(5)
  _btn.SetValue(Grid.ColumnProperty, Column)
  _btn.SetValue(Grid.RowProperty, Row)
  Grid.Children.Add(_btn)
End Sub

Private Sub Layout(ByRef Grid As Grid)
  Grid.Children.Clear()
  Grid.ColumnDefinitions.Clear()
  Grid.RowDefinitions.Clear()
  For Index As Integer = 0 To 3 ' Setup 4x4 Grid
    Grid.RowDefinitions.Add(New RowDefinition)
    Grid.ColumnDefinitions.Add(New ColumnDefinition)
  Next
  Add(Grid, 0, 0)
  Add(Grid, 0, 1)
  Add(Grid, 0, 2)
  Add(Grid, 0, 3)
  Add(Grid, 1, 0)
  Add(Grid, 1, 1)
  Add(Grid, 1, 2)
  Add(Grid, 1, 3)
  Add(Grid, 2, 0)
  Add(Grid, 2, 1)
  Add(Grid, 2, 2)
  Add(Grid, 2, 3)
  Add(Grid, 3, 0)
  Add(Grid, 3, 1)
  Add(Grid, 3, 2)
  Add(Grid, 3, 3)
End Sub

See Below:

MainPage Add and Layout Subs

Step 15

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

Private Function Random(ByRef Start As Integer, ByRef Finish As Integer, _
    ByRef Total As Integer) As List(Of Integer)
  Dim _number As Integer
  Dim _numbers As New List(Of Integer)
  While _numbers.Count < Total ' Total Numbers
    Randomize(Timer) ' Random Number with Seed
    _number = Int((Finish * Rnd()) + Start) ' Between Start - Finish
    If Not _numbers.Contains(_number) _
      Or _numbers.Count < 1 Then ' If Chosen or None
      _numbers.Add(_number) ' Add Number
    End If
  End While
  Return _numbers
End Function

Private Sub Choose()
  Dim _values, _indices As New List(Of Integer)
  Dim _counter As Integer = 0
  While _values.Count < 17 ' Get 16 Numbers (2x8)
    Dim _numbers As List(Of Integer) = Random(1, 8, 8) ' Random 1 - 8
    For _number As Integer = 0 To 7
      _values.Add(_numbers.Item(_number)) ' Add to Cards
    Next
  End While
  _indices = Random(1, 16, 16) ' Random 1 - 16
  For Column As Integer = 0 To 3 ' Board Columns
    For Row As Integer = 0 To 3 ' Board Rows
      _board(Column, Row) = _values.Item(_indices(_counter) - 1)
      _counter += 1
    Next
  Next
End Sub

See Below:

MainPage Random Function and Choose Sub

Step 16

Return to the Designer View, by selecting the "MainPage.xaml" Tab, or Right Click on the Page or the Entry for "MainPage.xaml" in Solution Explorer and choose the "View Designer" option.
Double Click on the "New" Button Control and type in the New_Click Sub:

_moves = 0
_matches.Clear()
Layout(Display)
Choose()

See Below:

New Button Click Event

Step 17

Save the Project as you have now finished the Silverlight application. Select Debug then Start Debugging or click on Start Debugging:

Start Debugging

After you do, the following will appear in a new Web Browser window:

Application Running

Step 18

Click on the New Button and the following will appear:

New Game

Step 19

Click on any two Buttons to show a Shape, match the shapes to make a pair, do this until all are matched to win, see below:

Memory Game

Step 20

Close the Browser window by clicking on the Close Button Close on the top right of the Web Browser to Stop the application.

This is a simple game using Shapes for each of the Cards displayed - try changing it to use different shapes, colours or even patterns, you could even make them look more like cards, anything you like!