You don't want to try and compare PImage as it is slow and not always accurate.
You don't want to store more images than you need, as this wastes memory. Only store unique images.
You want to separate the model from the view. You don't need to ever manipulate your images. You only need to know where they should be displayed and the procedure of searching for matches. The way you store your images should be separate from that logic.
I would recommend creating a "PImage" array of your 6 unique images. Then, create an "int" array with a size twice that of the number of unique images (since you want to have pairs). Lastly, create a "boolean" array with the same length as the "int" array.
So at setup, you will populate the image array (the "PImage" array) with 6 images, populate the label array (the "int" array) with the keys of the image array (0 through 5 repeated, i.e. {0,1,2,3,4,5,0,1,2,3,4,5), shuffle the label array, and populate the display array (the "boolean" array) with the "false" value.
When the user clicks a tile, you will determine the tile number (0 through 11), set the display of that tile number to true, and store the tile number as the first clicked. When the user clicks another tile, first check that it is a different tile number from the first clicked, then set the display to true, and store the tile number as the second clicked. Now that two have been clicked, check the label array for each tile number and see that they are equal. If so, you have a match, if not, there is no match and the first and second clicked are reset and the displays for those tile numbers set to false again.
In the example I have created below, there are two pde files, match and colors. The match.pde file includes everything you need to understand the label matching method. The colors.pde is only included as a method for generating random colors, you don't need to worry about it. The point is to show you the logic using colors so that you can then implement it using images.
match.pde
import java.util.Arrays; // used for shuffling
import java.util.Collections; // used for shuffling
int COLOR_COUNT = 6; //number of colors we will try to match
int WINDOW_X = 600;
int WINDOW_Y = 600;
//we will set these values during setup
int COLUMN_COUNT;
int ROW_COUNT;
color TILE_BACK_COLOR = color(255);
color TILE_EDGE_COLOR = color(0);
//we will set these values after we set the size of the window
int TILE_WIDTH;
int TILE_HEIGHT;
int ROUNDED_CORNER = 10;
//this is where we will store the colors
color[] COLORS = new color[COLOR_COUNT];
//the following must be Integer to allow for shuffle
//see http://stackoverflow.com/a/3981494/1736092
//this is where we will store the labels for the colors
Integer[] LABELS = new Integer[COLOR_COUNT*2];
//this is where we will store which tiles may be displayed
boolean[] DISPLAY = new boolean[COLOR_COUNT*2];
//this is where we will store the last 2 clicked tiles
int[] CLICKED = new int[2];
boolean MATCHED = false;
int MATCH_COUNT = 0;
int GUESS_COUNT = 0;
void setup() {
/* calculate how many rows and columns we need based on number of tiles
* since this is a matching game, number of tiles is twice the number of colors
* we want a board that is as square as possible
* take the square root of the number of tiles and round down (floor) and set that as rows
* if rows divide evenly into the number of tiles, just divide tiles by rows to get columns
* if not, keep subtracting a row until they divide evenly then get columns
*/
println("Tiles: " + COLOR_COUNT*2);
ROW_COUNT = floor(sqrt(COLOR_COUNT*2));
println("Initial ROW_COUNT: " + ROW_COUNT);
if((COLOR_COUNT*2) % ROW_COUNT == 0) {
COLUMN_COUNT = (COLOR_COUNT*2) / ROW_COUNT;
println("Keeping ROW_COUNT: " + ROW_COUNT + ", Setting COLUMN_COUNT: " + COLUMN_COUNT);
} else {
for(int i = ROW_COUNT - 1; i > 1; i--) {
ROW_COUNT = i;
if((COLOR_COUNT*2) % ROW_COUNT == 0) {
COLUMN_COUNT = (COLOR_COUNT*2) / ROW_COUNT;
println("Calculated ROW_COUNT: " + ROW_COUNT + ", Setting COLUMN_COUNT: " + COLUMN_COUNT);
}
}
}
// make sure that the rows and columns are valid
assert(COLUMN_COUNT * ROW_COUNT == COLOR_COUNT*2);
size(WINDOW_X, WINDOW_Y);
TILE_WIDTH = width/COLUMN_COUNT;
TILE_HEIGHT = height/ROW_COUNT;
populateColors(); // populate the colors
newGrid(); // set up the initial grid
background(0);
drawGrid();
}
void draw() {
// //With no animations, this game is visually static
// //No need for a draw loop
}
void populateColors() {
//for this game, we'll just generate random colors
//however, you could change this function to set specific colors
for(int i = 0; i < COLORS.length; i++) {
COLORS[i] = getRandomColor();
}
}
//this function will create a new grid
//labels will be populated and shuffled
//clicks will be initialized to -1, which we will use to mean no click
void newGrid() {
print("Initial LABELS[" + LABELS.length + "]:\t");
for(int i = 0; i < LABELS.length; i++) {
if(i < LABELS.length/2) LABELS[i] = i;
else LABELS[i] = i-COLOR_COUNT;
DISPLAY[i] = false;
print(LABELS[i] + " ");
}
CLICKED[0] = -1;
CLICKED[1] = -1;
// shuffles the labels array
Collections.shuffle(Arrays.asList(LABELS));
print("\nShuffled LABELS[" + LABELS.length + "]:\t");
for(int i = 0; i < LABELS.length; i++) print(LABELS[i] + " ");
println();
}
//this just iterates through the grid and displays tiles as necessary
void drawGrid() {
stroke(TILE_EDGE_COLOR); //set outline color
for(int row = 0; row < ROW_COUNT; row++) {
for(int col = 0; col < COLUMN_COUNT; col++) {
int tile_number = col + row*(COLUMN_COUNT);
if(DISPLAY[tile_number]) {
fill(COLORS[LABELS[tile_number]]); //set fill color to that of tile front
} else {
fill(TILE_BACK_COLOR); //set fill color to that of tile back
}
//rect(top left x, top left y, width, height)
rect(col*TILE_WIDTH, row*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT, ROUNDED_CORNER);
}
}
}
//this is called when two tiles have been clicked
//it checks the labels of the colors of the given tiles, not the actual colors
void checkMatch() {
//we want to make sure that both of the clicked tiles have been properly logged
if(CLICKED[0] != -1 || CLICKED[1] != -1) {
println("Comparing LABELS of COLORS[" + LABELS[CLICKED[0]] + "] and COLORS[" + LABELS[CLICKED[1]] + "]");
if(LABELS[CLICKED[0]] == LABELS[CLICKED[1]]) {
println("Colors match! MATCHED set to true and MATCH_COUNT++");
MATCHED = true;
MATCH_COUNT++;
println("MATCH_COUNT now " + MATCH_COUNT);
if(MATCH_COUNT == COLOR_COUNT) {
println("MATCH_COUNT now equals COLOR_COUNT, board must be complete, executing win()");
win();
}
} else {
println("Colors do not match");
}
}
}
//this funciton is called when a win condition has been met
void win() {
println("You Win! You made " + GUESS_COUNT + " tile flips, best possible is " + COLOR_COUNT*2);
if(GUESS_COUNT == COLOR_COUNT*2) println("PERFECT GAME!");
println("Press SPACE to generate a new board.");
}
//this function is called when the user wants to reset the board
void reset() {
println("Resetting the board");
COLORS = new color[COLOR_COUNT];
LABELS = new Integer[COLOR_COUNT*2];
DISPLAY = new boolean[COLOR_COUNT*2];
CLICKED = new int[2];
MATCHED = false;
MATCH_COUNT = 0;
GUESS_COUNT = 0;
populateColors();
newGrid();
}
void mouseClicked() {
println("Mouse Clicked");
int clicked_column = mouseX/TILE_WIDTH;
int clicked_row = mouseY/TILE_HEIGHT;
int tile_number = clicked_column + clicked_row*(COLUMN_COUNT);
println("Clicked: " + clicked_column + "," + clicked_row + " [" + tile_number + "]");
//we don't want to allow clicking a tile that is already being displayed
if(!DISPLAY[tile_number]) {
GUESS_COUNT++;
println("Guess count incremented to " + GUESS_COUNT);
if(CLICKED[0] != -1 && CLICKED[1] != -1) {
if(!MATCHED) {
println("Set DISPLAY[" + CLICKED[0] + "] and DISPLAY[" + CLICKED[1] + "] to false");
DISPLAY[CLICKED[0]] = false;
DISPLAY[CLICKED[1]] = false;
} else {
println("Set MATCHED to false");
MATCHED = false;
}
CLICKED[0] = -1;
CLICKED[1] = -1;
}
if(CLICKED[0] == -1 && CLICKED[1] == -1) {
CLICKED[0] = tile_number;
DISPLAY[tile_number] = true;
println("Tile " + tile_number + " set as CLICKED[0], set DISPLAY[" + tile_number + "] to true");
} else if(CLICKED[0] != -1 && CLICKED[1] == -1) {
CLICKED[1] = tile_number;
DISPLAY[tile_number] = true;
println("Tile " + tile_number + " set as CLICKED[1], set DISPLAY[" + tile_number + "] to true");
checkMatch();
} else {
println("error in mouseClicked()");
}
}
drawGrid();
if(DISPLAY[tile_number]) {
println("Tile " + tile_number + " is already being displayed");
for(int i = 0; i < LABELS.length; i++) {
print("-["+i+"]-");
if(i != tile_number && LABELS[tile_number] == LABELS[i]) {
break;
}
}
}
}
//allow user to reset the board by pressing SPACE
void keyPressed() {
if(key == ' ') reset();
}
colors.pde
final float PHI = (1 + sqrt(5))/2;
float rand = random(0,1);
color HSVtoRGB(float h, float s, float v) {
float r, g, b;
if (s == 0) {
r = v * 255;
g = v * 255;
b = v * 255;
} else {
float var_h = h * 6;
float var_i = floor(var_h);
float var_1 = v * (1 - s);
float var_2 = v * (1 - s * (var_h - var_i));
float var_3 = v * (1 - s * (1 - (var_h - var_i)));
float var_r, var_g, var_b;
if (var_i == 0) {var_r = v; var_g = var_3; var_b = var_1;}
else if (var_i == 1) {var_r = var_2; var_g = v; var_b = var_1;}
else if (var_i == 2) {var_r = var_1; var_g = v; var_b = var_3;}
else if (var_i == 3) {var_r = var_1; var_g = var_2; var_b = v;}
else if (var_i == 4) {var_r = var_3; var_g = var_1; var_b = v;}
else {var_r = v; var_g = var_1; var_b = var_2;}
r = var_r * 255;
g = var_g * 255;
b = var_b * 255;
}
return color(r, g, b);
}
// returns a random color
color getRandomColor() {
//0.25,0.8
float sat = 0.65;
float val = 0.6;
rand += PHI - 1;
rand %= 1;
//this is a custom function to convert HSV to RGB
return HSVtoRGB(rand, sat, val);
}
As an aside, you don't have to use the Java shuffle method, especially if you want to avoid using the Java libraries and stick with Processing only. One popular method is the Fisher-Yates Shuffle.
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle