Memory Game
The memory game is a childrens game, often played with cards or tiles. The tiles (or cards) have a face up or face down, come in pairs, and are initally randomly arranged all face down. The player selects one tile, which is fliped over so the player can see the face. Then the player selects another. If they match then both are removed. If they do not match then both are fliped back. The object of the game is to remove all the tiles in the fewest possible moves. (This is a one player game, in the two player game you keep the tiles and the object is to get as many tiles as possible).
In our version we will use graphics for the tiles. In order to make the game interesting, you will play against a clock, and the object will be to remove all the tiles before the clock ticks down.
Start by reading the text chapters 9 and 10. Play close attention to Section 10.5, although I'll be giving you a lot of the code. We are developing applications, not applets, but most of the commands that Cay discusses work the same for both.
Our tiles will be represented by rectangles of colors, 75 pixels wide and and 40 pixes high. Our playing surface will be 400 pixels wide and 300 high. As Horstmann describes in Section 10.5, the first step in your application is to create a JFrame (a window that includes features such as menu bars, a title, and the like) that includes a Panel (a drawing surface). I'll show you this bit of code (I've eliminated the comments, but kept them in the skeleton file):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Memory
{
public static void main(String [] args)
{
JFrame frame = new JFrame();
frame.setTitle("Memory Game");
frame.setSize(400, 300);
frame.setDefaultCloseOperation(3); // EXIT_ON_CLOSE
MyPanel board = new MyPanel();
frame.setContentPane(board);
frame.show();
}
}
class MyPanel extends JPanel
{
public MyPanel() {
// ...
}
private Tile[][] tiles = new Tile[4][4];
private int counter = 30;
private String text = "Click on Tile";
public void paintComponent(Graphics g)
{
int text_location_x = 200;
int text_location_y = 250;
super.paintComponent(g);
g.drawString(text, text_location_x, text_location_y);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
tiles[i][j].draw(g);
}
public class MyCounter implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// ...
repaint();
}
}
class MouseSpy extends MouseAdapter
{
public void mouseClicked(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
// ...
repaint();
}
}
}
The class MyPanel is where all the action takes place. I know we haven't
really discussed inheritance yet, but we are only using that feature
to a small extent here. The class MyPanel will inherit from the
system class JPanel. When it comes time to draw the window, the
function paintComponent will be called. There are two classes
nested inside of MyPanel, MyCounter and MouseSpy. More on those in a
moment.
What is our playing surface? It will consist of two parts. The first is a two-dimensional array of tiles. I'm calling this array tiles, and you can see the declaration in the code above. The second is a text message, which will be counting down until the game is finished. The paint command shown above displays these two items.
Since Tiles are just assigned a fixed position, they can actually be in any one of THREE states. The tile can be face up, face down, or empty (no longer in play). To make your life just a little bit easier, I'll provide the class Tile for you:
class Tile
{
public Tile(int ix, int iy, Color ic)
{
x = ix;
y = iy;
state = DOWN;
color = ic;
}
public static final int UP = 1;
public static final int DOWN = 2;
public static final int EMPTY = 3;
public static final int HEIGHT = 40;
public static final int WIDTH = 75;
private Color color;
private int x, y;
private int state;
public boolean stateIs(int s)
{
return state == s;
}
public boolean sameColor(Tile d)
{
return color.equals(d.color);
}
public void draw(Graphics g)
{
if (state == EMPTY)
g.setColor(Color.white);
else if (state == DOWN)
g.setColor(Color.black);
else
g.setColor(color);
g.fillRect(x, y, WIDTH, HEIGHT);
}
public void flip()
{
if (state == UP)
state = DOWN;
else if (state == DOWN)
state = UP;
}
public void makeEmpty()
{
state = EMPTY;
}
}
Tiles are initialized with an x, y location on the playing surface,
and a color. In addition to the colors black and white, we will use
the following eight predefined colors: Color.blue, Color.red, Color.green,
Color.orange, Color.pink, Color.cyan, Color.yellow and Color.magenta.
The tile prints as a block 75 by 40 pixels of solid color. There are
methods to test the state of a tile, test if two tiles are the same
color, flip a tile, and to make a tile empty.
The following are the steps necessary to produce the game.
Find tile under mouse click
If tile is down
If this is first tile flipped
remember coordinates, and flip tile
else
if tile is same color as previous flip
mark both tiles as empty
else
flip first tile back
Note that yes, this logic flips only the first tile, and therefore
only shows you one tile on each move of the game.
(To flip both would have required a pause before deciding to
erase both or flip both back, which would have made the game more
complex).
text = "Counter: " + counterWhen the counter reaches zero, change the text message to indicate the game is over. If you start the counter from 30 it gives you 30 seconds to play the game.
That's it. Once you have those pieces your game should work.
The assignment is the game as described. If you want to, on your own you might want to add logic to do things like figure out if the player has won and change the text accordingly, allow multiple plays, perhaps decreasing the counter each time the player wins, or changing the graphic representation of the tiles. But do not hand in these additions.
You must use Horstmanns formatting style. I've provided a skeleton you can use as a starting point, although you are not obligated to use this. Note that many textbooks would have the main class (Memory in this example) be either a subclass of JFrame, or a subclass of JPanel. The latter would eliminate the need for the separate class MyPanel. There is nothing wrong with this. However, Horstmann keeps them separate in order to more clearly show classes are doing what. I think that is a good idea, so I've followed his approach. If you put all your classes in one file remember that only the main class Memory is declared as public. If you want to put your classes in separate files (Memory, Tile, MyPanel) then that is ok as well. I've allowed up to four files in the submission area.