Memory Game

Memory Game is a simple shape matching game that can be created using Silverlight on Windows Phone 7.

www.cespage.com/silverlight/wp7tut10.html

Step 1

Start Microsoft Visual Studio 2010 Express for Windows Phone, then Select File then New Project... Select "Visual C#" then "Silverlight for Windows Phone" and then "Windows Phone 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

A Windows Phone application Page named MainPage.xaml should then appear, see below:

MainPage.xaml

Step 3

In the XAML Pane for MainPage.xaml between the <Grid x:Name="ContentGrid" Grid.Row="1"> and </Grid> lines, enter the following XAML:

<Grid x:Name="ContentMain">
  <Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <Button Grid.Row="1" Width="160" Content="new" Click="New_Click"/>
</Grid>

XAML:

MainPage XAML View

Design:

MainPage Design View

Step 4

Then from the Windows Phone Controls section in the Toolbox select the Grid control:

Grid Control

Step 5

Draw a Grid on the Page by dragging a Grid from the Toolbox onto the middle part of the Grid on the Page, then in the XAML Pane change the "grid1" line to the following:

<Grid Height="400" Width="400" Name="Display"/>

See below:

MainPage with Grid

Step 6

Right Click on the Page or the entry for "MainPage.xaml" in Solution Explorer and choose the "View Code" option. In the Code View above "namespace MemoryGame" type the following:

using System.Windows.Threading;

Also in the CodeView above "public MainPage()" type the following declarations:

int _moves = 0;
int _first = 0;
int _second = 0;
Button _firstButton;
Button _secondButton;
int[,] _board = new int[4,4];
List<int> _matches = new List<int>();
DispatcherTimer _timer = new DispatcherTimer();

See Below:

MainPage Includes and Declarations

Step 7

While still the Code View for MainPage.xaml.cs above "public MainPage()" type the following Method:

private object Shape(ref System.Windows.Media.PointCollection Points)
{
  Polygon _shape = new Polygon();
  _shape.Stretch = Stretch.Uniform;
  _shape.StrokeLineJoin = PenLineJoin.Round;
  _shape.Points = Points;
  _shape.Height = 40;
  _shape.Width = _shape.Height;
  _shape.Stroke = new SolidColorBrush((Color)
  App.Current.Resources["PhoneForegroundColor"]);
  _shape.StrokeThickness = 5;
  _shape.Margin = new Thickness(4);
  return _shape;
}

See Below:

MainPage Shape Method

Step 8

While still the Code View for MainPage.xaml.cs, below the "}" of the "private object Shape(...)" method type the following Method:

private object Card(ref int Type)
{
  System.Windows.Media.PointCollection _points = 
  new System.Windows.Media.PointCollection();
  switch (Type)
  {
    case 1: // Circle
      EllipseGeometry _ellipse = new EllipseGeometry();
      Path _circle = new Path();
      _ellipse.Center = new Point(20, 20);
      _ellipse.RadiusX = 20;
      _ellipse.RadiusY = 20;
      _circle.Data = _ellipse;
      _circle.Stroke = new SolidColorBrush((Color)
      App.Current.Resources["PhoneForegroundColor"]);
      _circle.StrokeThickness = 4;
      _circle.Margin = new Thickness(4);
      return _circle;
    case 2: // Cross
      Path _lines = new Path();
      LineGeometry _line1 = new LineGeometry();
      LineGeometry _line2 = new LineGeometry();
      GeometryGroup _linegroup = new GeometryGroup();
      _line1.StartPoint = new Point(0, 0);
      _line1.EndPoint = new Point(40, 40);
      _line2.StartPoint = new Point(40, 0);
      _line2.EndPoint = new Point(0, 40);
      _linegroup.Children.Add(_line1);
      _linegroup.Children.Add(_line2);
      _lines.Data = _linegroup;
      _lines.Stroke = new SolidColorBrush((Color)
      App.Current.Resources["PhoneForegroundColor"]);
      _lines.StrokeThickness = 4;
      _lines.Margin = new Thickness(4);
      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(ref _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(ref _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(ref _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(ref _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(ref _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(ref _points);
    default:
      return Type;
  }
}

See Below:

MainPage Card Method

Step 9

While still the Code View for MainPage.xaml.cs, below the "}" of the "private object Card(...)" method type the following Method and Button Event Handler:

private void Clear(object sender, EventArgs e)
{
  if (!(_firstButton == null))
  {
    _firstButton.Content = null;
    _firstButton = null;
  }
  if (!(_secondButton == null))
  {
    _secondButton.Content = null;
    _secondButton = null;
  }
  _timer.Stop();
}

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
  Button _btn = new Button();
  int _row;
  int _col;
  int _selected;
  if (!_timer.IsEnabled)
  {
    _btn = ((Button)(sender));
    _row = (int)_btn.GetValue(Grid.RowProperty);
    _col = (int)_btn.GetValue(Grid.ColumnProperty);
    _selected = _board[_row, _col];
    if ((_matches.IndexOf(_selected) < 0))
    {
      if ((_first == 0)) // No Match
      {
        _firstButton = _btn;
        _first = _selected;
        _firstButton.Content = Card(ref _selected);
      }
      else if ((_second == 0))
      {
        _secondButton = _btn;
        if (!_firstButton.Equals(_secondButton)) // Different
        {
          _second = _selected;
          _secondButton.Content = Card(ref _selected);
          if ((_first == _second)) // Is Match
          {
            _matches.Add(_first);
            _matches.Add(_second);
            MessageBox.Show("Match!", "Memory Game", MessageBoxButton.OK);
            if ((_matches.Count == 16))
            {
              MessageBox.Show(("Well Done! You matched them all in " +
              (_moves + " moves!")), "Memory Game", MessageBoxButton.OK);
            }
          }
          else // No Match
          {
            _timer.Interval = TimeSpan.FromSeconds(1.5);
            _timer.Tick += Clear; // Clear Buttons after 1.5 Seconds
            _timer.Start();
          }
          _moves++;
          _first = 0;
          _second = 0;
        }
      }
    }
  }
}

See Below:

MainPage Clear and Button Click Method

Step 10

While still the Code View for MainPage.xaml.cs, below the "}" of the "private void Button_Click(...)" method type the following Methods:

private void Add(ref Grid Grid, int Row, int Column)
{
  Button _btn = new Button();
  _btn.Click += Button_Click;
  _btn.Content = null;
  _btn.Margin = new Thickness(0);
  _btn.SetValue(Grid.ColumnProperty, Column);
  _btn.SetValue(Grid.RowProperty, Row);
  Grid.Children.Add(_btn);
}

private void Layout(ref Grid Grid)
{
  Grid.Children.Clear();
  Grid.ColumnDefinitions.Clear();
  Grid.RowDefinitions.Clear();
  // Setup 4x4 Grid
  for (int Index = 0; (Index <= 3); Index++)
  {
    Grid.RowDefinitions.Add(new RowDefinition());
    Grid.ColumnDefinitions.Add(new ColumnDefinition());
  }
  Add(ref Grid, 0, 0);
  Add(ref Grid, 0, 1);
  Add(ref Grid, 0, 2);
  Add(ref Grid, 0, 3);
  Add(ref Grid, 1, 0);
  Add(ref Grid, 1, 1);
  Add(ref Grid, 1, 2);
  Add(ref Grid, 1, 3);
  Add(ref Grid, 2, 0);
  Add(ref Grid, 2, 1);
  Add(ref Grid, 2, 2);
  Add(ref Grid, 2, 3);
  Add(ref Grid, 3, 0);
  Add(ref Grid, 3, 1);
  Add(ref Grid, 3, 2);
  Add(ref Grid, 3, 3);
}

See Below:

MainPage Add and Layout Methods

Step 11

While still the Code View for MainPage.xaml.cs, below the "}" of the "private void Layout(...)" method type the following Methods:

private List<int> Random(int start, int finish, int total)
{
  int _number;
  List<int> _numbers = new List<int>();
  Random random = new Random();
  while ((_numbers.Count < total)) // Select Numbers
  {
    // Random Number between Start and Finish
    _number = random.Next(start, finish + 1);
    if ((!_numbers.Contains(_number)) || (_numbers.Count < 1))
    {
      _numbers.Add(_number); // Add if number Chosen or None
    }
  }
  return _numbers;
}

private void Choose()
{
  List<int> _values = new List<int>();
  List<int> _indices = new List<int>();
  int _counter = 0;
  while (_values.Count < 17)
  {
    List<int> _numbers = Random(1, 8, 8); // Random 1 - 8
    for (int _number = 0; (_number <= 7); _number++)
    {
      _values.Add(_numbers[_number]); // Add to Cards
    }
  }
  _indices = Random(1, 16, 16); // Random 1 - 16
  for (int Column = 0; (Column <= 3); Column++) // Board Columns
  {
    for (int Row = 0; (Row <= 3); Row++) // Board Rows
    {
      _board[Column, Row] = _values[_indices[_counter] - 1];
      _counter++;
    }
  }
}

See Below:

MainPage Random and Choose Methods

Step 12

While still the Code View for MainPage.xaml.cs, below the "}" of the "public MainPage()" method type the following Event Handler:

private void New_Click(object sender, RoutedEventArgs e)
{
  _moves = 0;
  _matches.Clear();
  Layout(ref Display);
  Choose();
}

See Below:

MainPage Event Handler

Step 13

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

Start Debugging

After you do, the following will appear in the Windows Phone Emulator after it has been loaded:

Application Running

Step 14

Tap the "new" Button, then Tap on any two of the Buttons shown to display a Shape, match the shapes to make a pair, do this until all are matched to win, see below:

Memory Game

Step 15

You can then Stop the application by selecting the Visual Studio 2010 application window and clicking on the Stop Debugging button:

Stop Debugging

This is a very 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 - make it your own!