My code works, I just don't understand WHY it works

#pragma strict

import System.Collections.Generic;

var cols:int = 4; // the number of columns in the card grid
var rows:int = 4; // the number of rows in the card grid
var totalCards:int = 16;
var matchesNeededToWin:int = totalCards * 0.5; // If there are 16 cards, the player needs to find 8 matches to clear the board
var matchesMade:int = 0; // At the outset, the player has not made any matches
var cardW:int = 100; // Each card's width and height is 100 pixels
var cardH:int = 100;
var aCards:List.<Card>; // We'll store all the cards we create in this List
var aGrid:Card[,]; // This 2d array will keep track of the shuffled, dealt cards
var aCardsFlipped:List.<Card>; // This generic array list will store the two cards that the player flips over
var playerCanClick:boolean; // We'll use this flag to prevent the player from clicking buttons when we don't want him to
var playerHasWon:boolean = false; // Store whether or not the player has won. This should probably start out false :)

function Start ()
{
	playerCanClick = true; // We should let the player play, don't you think?

	// Initialize some empty Collections:
	aCards = new List.<Card>(); // this Generic List is our deck of cards. It can only ever hold instances of the Card class.
	aGrid = new Card[rows,cols]; // The rows and cols variables help us define the dimensions of this 2D array
	aCardsFlipped = new List.<Card>(); // This List will store the two cards the player flips over. 

	BuildDeck();
	
	// Loop through the total number of rows in our aGrid List:  
	for(var i:int = 0; i<rows; i++)
	{

		// For each individual grid row, loop through the total number of columns in the grid:
		for(var j:int = 0; j<cols; j++)
		{ 
			var someNum:int = Random.Range(0,aCards.Count);
			aGrid[i,j] = aCards[someNum];
			aCards.RemoveAt(someNum);
		}
	}
	//for(i=0; i<1000; i++)
	//{
	//	Debug.Log(Random.Range(0,10));  // Uncomment to play around with Random
	//}
}

function OnGUI ()
{
	GUILayout.BeginArea (Rect (0,0,Screen.width,Screen.height));    
	BuildGrid();
	GUILayout.EndArea();
	//print("building grid!");
}

function BuildGrid()
{
	GUILayout.BeginVertical();
	GUILayout.FlexibleSpace();
	for(var i:int=0; i<rows; i++)
  	{
    	GUILayout.BeginHorizontal();
    	GUILayout.FlexibleSpace();
    	for(var j:int=0; j<cols; j++)
    	{
      		var card:Card = aGrid[i,j];
      		var img:String;
      		if(card.isFaceUp)
      		{
      			img = card.img;
      		}	else {
      			img = "wrench";
      		}         
      		if(GUILayout.Button(Resources.Load(img), GUILayout.Width(cardW)))
      		{
      		 	if(playerCanClick)
      			{
      			FlipCardFaceUp(card);
        		//Debug.Log(card.img);
      			}
    		}
    	}
    	GUILayout.FlexibleSpace();
    	GUILayout.EndHorizontal();   
  	}
  	GUILayout.FlexibleSpace();
  	GUILayout.EndVertical();
}

class Card extends System.Object
{
	var isFaceUp:boolean = false;
	var isMatched:boolean = false;
	var img:String;
	
	function Card(img:String)
	{
		this.img = img;
	}
}

function BuildDeck()
{
	var totalRobots:int = 4; // We've got four robots to work with
	var card:Card; // this stores a reference to a card
	
	for(var i:int=0; i<totalRobots; i++)
	{
		var aRobotParts:List.<String> = new List.<String>();
		aRobotParts.Add("Head");
		aRobotParts.Add("Arm");
		aRobotParts.Add("Leg");
		for(var j:int=0; j<2; j++)
		{
			var someNum:int = Random.Range(0, aRobotParts.Count);
			var theMissingPart:String = aRobotParts[someNum];
			
			aRobotParts.RemoveAt(someNum);
			
			card = new Card("robot" + (i+1) + "Missing" + theMissingPart);
			aCards.Add(card);
				
			card = new Card("robot" + (i+1) + theMissingPart);
			aCards.Add(card);
		}	
	}
}

function FlipCardFaceUp(card:Card)
{
	card.isFaceUp = true;
	if(aCardsFlipped.IndexOf(card) < 0 )
	{
		aCardsFlipped.Add(card);
	}
	Debug.Log(aCardsFlipped.IndexOf(card));
	
	if(aCardsFlipped.Count == 2)
	{
		playerCanClick = false;
		
		yield WaitForSeconds(1);
		
		aCardsFlipped[0].isFaceUp = false;
		aCardsFlipped[1].isFaceUp = false;
		
		aCardsFlipped = new List.<Card>();
		playerCanClick = true;
	}
	
}

What we’re going to look at is the FlipCardFaceUp function near the end of the code, inside is this little snippet:

if(aCardsFlipped.IndexOf(card) < 0 )

{

aCardsFlipped.Add(card);

}

I’ve been trying to figure out these 4 lines of code for maybe 3 hours and I still don’t understand what’s going on, even though my book explains it, it’s still not clicking with me.

This if statement confuses me so much!!

I’ll be specific, my book added this if statement because if you click the same card twice it would flip back over anyway, somehow adding this if statement prevents that from happening, but I don’t know why.

I’ll be honest with you: that’s a lot of code to dig through, and it’s a nice Friday night and I just got off work. So I’m going to skip all of that and get right to your bottom question. This code:

if(aCardsFlipped.IndexOf(card) < 0 )
{
	aCardsFlipped.Add(card);
}

First off, you’ll need to understand how if statements work, and the < (less than) operator, and the fact that IndexOf is returning an int that’s being compared against zero. If any of that confuses you, find tutorials that explain logic and branching. Important stuff.

Second, we know that IndexOf returns an int value, but let’s talk about how it picks a value. Your list is sort of like an array, right? It’s a series of values, each of which has a numbered “index”. IndexOf starts in box 0, and works up from there, checking for an item that’s equal to whatever you’re asking about. In this case, it’s looking for a particular card.

If IndexOf finds your card, it tells you which index holds that card. If you happen to have the same card in the list more than once, it only tells you about the first one it finds. If you don’t have that card in your list at all, it returns -1. Why? Because your list index numbering starts counting from 0, so -1 is a special value indicating that there’s no such item found.

So, getting back to the question, let’s explain with a comment:

//if list does not contain this card, add it to the list
if(aCardsFlipped.IndexOf(card) < 0 )
{
	aCardsFlipped.Add(card);
}

That if statement basically checks the list of flipped cards to see if the current card is in that list, if it is then it’s index will be 0 or greater, if it’s not in that list the IndexOf function returns -1 which passes the if statement and allows the card to be added to the list of flipped cards.

IndexOf returns -1 if the item was not found, so if the selected card is not in the aCardsFlipped array (IndexOf returned -1 which is less than 0), then add it (flip it) otherwise ignore it.