Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game

Memory Game: 4x4 Size

3.29/5 (3 votes)
23 Oct 2019CPOL3 min read 10.5K   308  
Matching game: 4x4 size

Introduction

I'll present to you the way in which I created a memory game.

Background

I've found a memory game written in C# by Michael Hicks on YouTube. The game was based on font symbols and was well written, so I decided to create a memory game on my own, using pictures instead of symbols.

Using the Code

Having in mind that the game contains 16 fields (4x4), we'll have a pair of 8 different images: devil, sailors, scary, zombie, trick, wizard, bad and owl. Each image will have 2 same elements in the list, so we're sure that there will be no more or less than 2 same images per game:

C#
List<Bitmap> pictures = new List<Bitmap>()
{
 Properties.Resources.devil,Properties.Resources.devil,
   Properties.Resources.sailors,Properties.Resources.sailors,
 Properties.Resources.scary,Properties.Resources.scary,
   Properties.Resources.zombie,Properties.Resources.zombie,
 Properties.Resources.trick,Properties.Resources.trick,
   Properties.Resources.wizard,Properties.Resources.wizard,
 Properties.Resources.bat,Properties.Resources.bat,
   Properties.Resources.owl,Properties.Resources.owl        
};

We have two values of PictureBox type called first and second, that will remember the images we clicked (and their tags),and a bool value named done which will check if the moves are made:

C#
PictureBox first, second;

bool done = false; 

Now we need to find a way to name every image in order to compare them properly. If you visited my previous project - Sliding Puzzle, you could see that I assigned a tag to each element of Bitmap list. I'm going to do the same thing now, except it will be a little bit different. Again, I made the exact same order of the List elements, so I can name them precisely. I will create two procedures called Tags() and AssignImages(). Tags go first:

C#
private void Tags(int index)
{
 switch (index)
 {
  case 0:
  case 1:
      pictures[index].Tag = "devil";
      break;
  case 2:
  case 3:
      pictures[index].Tag = "sailors";
      break;
  case 4:
  case 5:
      pictures[index].Tag = "scary";
      break;
  case 6:
  case 7:
      pictures[index].Tag = "zombie";
      break;
  case 8:
  case 9:
      pictures[index].Tag = "trick";
      break;
  case 10:
  case 11:
      pictures[index].Tag = "wizard";
      break;
  case 12:
  case 13:
      pictures[index].Tag = "bat";
      break;
  case 14:
  case 15:
      pictures[index].Tag = "owl";
      break;
 }
}

Now let's move to AssignImages() procedure. As its name says, it's going to assign the images to the Form picture boxes, but before that we need to give each element its tag given by the procedure above. Once I do that, the image will contain a tag of its own and will be ready to be given to the control on the form.

But if I assign images to BackgroundImage or Image property, they will be shown once the form is loaded and the entire game logic will be screwed. So I'm going to use InitialImage instead and the images won't be displayed once the program is started:

C#
private void AssignImages()
{
 Random r = new Random();

 for (int i = 0; i < pictures.Count; i++) 
 {
  Tags(i);
 }

 foreach (Control c in this.Controls)
 {
  int j = r.Next(pictures.Count);
  PictureBox p = (PictureBox)c;
  p.InitialImage = pictures[j];
  p.Tag = pictures[j].Tag;
  pictures.RemoveAt(j);
 }
}

I forgot to mention that before I started writing a code, I marked all the pictureBox controls and created a common event called picture_Click. So once we clicked on the image, we'll check if value first is empty knowing that we haven't clicked yet. The clicked image will set its BackgroundImage property to the InitialImage so it will take that reserved image and its tag and the image will be presented in pictureBox control. The value called second will do the same for the second clicked image, and then we're setting a boolean value done to true so we're not allowing the player to click on more than two images per comparison, and we're starting timer which will perform simple check if the images matched or not:

C#
private void picture_Click(object sender, EventArgs e)
{
 PictureBox cast = (PictureBox)sender;
            
 if (cast.BackgroundImage == null && done == false)
 {
  if (first == null)
  {
   first = cast;
   first.BackgroundImage = first.InitialImage;
   return; 
  }
  second = cast;
  second.BackgroundImage = second.InitialImage;
  done = true;
  timer1.Start();
 }
}

The timer will check if the images matched, and if they did, we're going to check if the player revealed all the images and won the game. There's no need to do anything else, because the images are already revealed. If they don't match, we're setting their BackgroundImage properties to null, and in the end, setting first and second to null, while done is set to false in order to allow the player to click on the next pair of images. Timer interval is set to 500ms but you can change it if you wish:

C#
private void Timer(object sender, EventArgs e)
{
 timer1.Stop();

 if (first.Tag.ToString() == second.Tag.ToString())
 {
  CheckForWinner();
 }
 else if (first.Tag.ToString() != second.Tag.ToString())
 {
  first.BackgroundImage = null;
  second.BackgroundImage = null;
 }
 first = null;
 second = null;
 done = false;
}

And for the final part, we have CheckForWinner() procedure which checks if all the images are revealed and if player won the game or not. It's very simple - if a single image is empty, the game is not over and we're exiting. Otherwise, the winner is found and the game is over:

C#
private void CheckForWinner()
{
 foreach(Control c in this.Controls)
 {
  PictureBox pb = (PictureBox)c;
  if (pb.BackgroundImage == null) return; 
 }
 MessageBox.Show("Congratulations!");
}

History

  • 24th October, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)