Coding 4: Creating the holes

In this coding lesson, we will finally be creating the holes!

How many holes do we need to create?

Our WhackAMole game is going to be played on a 4x4 grid so there will be 16 holes in total.

The grid should look something like this: (where the circle represents a mole)

Create a new JPanel on top of the content panel

We should now create a new JPanel which will represent the grid, where all the holes will be displayed.

This time, our JPanel should not be declared inside the constructor. Instead, it should be declared as a global variable. This means it is declared outside the function and can therefore be accessed from anywhere within the class.

public class Game extends JFrame{

    private JPanel panel;

    public Game() {
      ...
    }

    ...

private simply means the panel object can only be accessed within this class: Game

Now let's also set some attributes to this JPanel:

panel = new JPanel(); //initialise the object
panel.setBackground(new Color(0, 102, 0));
panel.setBounds(32, 105, 535, 546);
panel.setLayout(null);

Finally we can add the JPanel on top of the content panel:

contentPane.add(panel);

Inside the panel we want to add the 16 holes which we will represent using JLabels. For this we will first create an array of size 16 which will store the JLabels.

If you do not know what an array is or you're unfamiliar with using arrays in Java, it is highly recommended to read Lesson 2: Java basics

The array will also be declared as a global variable so it can be accessed by other functions (which we will implement later):

  public class Game extends JFrame{

    private JPanel panel;
    private JLabel[] holes = new JLabel[16];

    public Game() {
        ...

        panel = new JPanel();
        panel.setBackground(new Color(0, 102, 0));
        panel.setBounds(32, 105, 535, 546);
        panel.setLayout(null);
        contentPane.add(panel);

        ...
    }

    ...

As you can see here we created a one-dimensional array of JLabels called: holes and initialised the array to be size 16.

Now inside the constructor we can start creating the 16 JLabels, for instance:

holes[0] = new JLabel("0");
holes[0].setName("0");
holes[0].setBounds(0, 396, 132, 132);

And add it to our panel:

panel.add(holes[0]);

We simply have to repeat this 15 more times, only slightly modifying the numbers each time (in setBounds the position would have to change so that the labels are arranged in a 4x4 grid):

        holes[0] = new JLabel("0");
        holes[0].setName("0");
        holes[0].setBounds(0, 396, 132, 132);
        panel.add(holes[0]);

        holes[1] = new JLabel("1");
        holes[1].setName("1");
        holes[1].setBounds(132, 396, 132, 132);
        panel.add(holes[1]);

        holes[2] = new JLabel("2");
        holes[2].setName("2");
        holes[2].setBounds(264, 396, 132, 132);
        panel.add(holes[2]);

        holes[3] = new JLabel("3");
        holes[3].setName("3");
        holes[3].setBounds(396, 396, 132, 132);
        panel.add(holes[3]);

        holes[4] = new JLabel("4");
        holes[4].setName("4");
        holes[4].setBounds(0, 264, 132, 132);
        panel.add(holes[4]);

        holes[5] = new JLabel("5");
        holes[5].setName("5");
        holes[5].setBounds(132, 264, 132, 132);
        panel.add(holes[5]);

        holes[6] = new JLabel("6");
        holes[6].setName("6");
        holes[6].setBounds(264, 264, 132, 132);
        panel.add(holes[6]);

        holes[7] = new JLabel("7");
        holes[7].setName("7");
        holes[7].setBounds(396, 264, 132, 132);
        panel.add(holes[7]);

        holes[8] = new JLabel("8");
        holes[8].setName("8");
        holes[8].setBounds(0, 132, 132, 132);
        panel.add(holes[8]);

        holes[9] = new JLabel("9");
        holes[9].setName("9");
        holes[9].setBounds(132, 132, 132, 132);
        panel.add(holes[9]);

        holes[10] = new JLabel("10");
        holes[10].setName("10");
        holes[10].setBounds(264, 132, 132, 132);
        panel.add(holes[10]);

        holes[11] = new JLabel("11");
        holes[11].setName("11");
        holes[11].setBounds(396, 132, 132, 132);
        panel.add(holes[11]);

        holes[12] = new JLabel("12");
        holes[12].setName("12");
        holes[12].setBounds(0, 0, 132, 132);
        panel.add(holes[12]);

        holes[13] = new JLabel("13");
        holes[13].setName("13");
        holes[13].setBounds(132, 0, 132, 132);
        panel.add(holes[13]);

        holes[14] = new JLabel("14");
        holes[14].setName("14");
        holes[14].setBounds(264, 0, 132, 132);
        panel.add(holes[14]);

        holes[15] = new JLabel("15");
        holes[15].setName("15");
        holes[15].setBounds(396, 0, 132, 132);
        panel.add(holes[15]);

You may have noticed that we are not setting any image to the labels at the moment, so right now they just display a number: 0-15.

Since all the JLabels will have the same initial image (a empty hole image) we can use a loop to set all of the JLabel images to display an empty hole.

If you are unfamiliar with loops, please read Lesson 5

First, go ahead and save the following image: moleIn.png

Right click on your project folder and click New -> Source Folder:

Create a new source folder called: res

This folder will contain the images (resources) used in this game.

So now simply drag and drop the moleIn.png image file into the res folder.

Now we are ready to add the image to our JLabels

Let's make a function that will help us load the image

private ImageIcon loadImage(String path){

}

This function takes in a string and returns an ImageIcon object

Inside the function, we will first create an ImageIcon object, by calling it's constructor with the relative path we give it.
Image image = new ImageIcon(this.getClass().getResource(path)).getImage();

The following segment of the line:

this.getClass().getResource

simply points to the "res" folder we just created.

Next, we need to scale (resize) our image to fit the Label dimension is 132x132 pixels
Image scaledImage = image.getScaledInstance(132, 132,  java.awt.Image.SCALE_SMOOTH);
Finally, we can convert our scaled image back into an ImageIcon object and return it
return new ImageIcon(scaledImage);
Now our loadImage function should look like this:
private ImageIcon loadImage(String path){
    Image image = new ImageIcon(this.getClass().getResource(path)).getImage();
    Image scaledImage = image.getScaledInstance(132, 132,  java.awt.Image.SCALE_SMOOTH);
    return new ImageIcon(scaledImage);
}

Now we can loop through our array of labels and set each of it's icon to moleIn.png
Make sure to do this inside the constructor after initialising all the labels in the 'holes' array.

for(int i = 0; i < 16; i++){
    holes[i].setIcon(loadImage("/moleIn.png"));
}

It's time to test the program! Let's run it.

If you have this showing on your screen right now, congratulations you have followed the steps correctly so far.

If not, do not worry.

Your code up to this point should look like this:

import java.awt.Color;
import java.awt.Font;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;


public class Game extends JFrame{

    private JPanel panel;
    private JLabel[] holes = new JLabel[16];

    private ImageIcon loadImage(String path){
        Image image = new ImageIcon(this.getClass().getResource(path)).getImage();
        Image scaledImage = image.getScaledInstance(132, 132,  java.awt.Image.SCALE_SMOOTH);
        return new ImageIcon(scaledImage);
    }

    public Game() {
        setTitle("Whack A Mole");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 608, 720);

        JPanel contentPane = new JPanel();
        contentPane = new JPanel();
        contentPane.setBackground(new Color(0, 51, 0));
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(null);

        JLabel lblTitle = new JLabel("Whack A Mole");
        lblTitle.setForeground(new Color(153, 204, 0));
        lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
        lblTitle.setFont(new Font("Century Gothic", Font.BOLD, 20));
        lblTitle.setBounds(0, 0, 602, 47);
        contentPane.add(lblTitle);

        panel = new JPanel();
        panel.setBackground(new Color(0, 102, 0));
        panel.setBounds(32, 105, 535, 546);
        panel.setLayout(null);
        contentPane.add(panel);

        holes[0] = new JLabel("0");
        holes[0].setName("0");
        holes[0].setBounds(0, 396, 132, 132);
        panel.add(holes[0]);

        holes[1] = new JLabel("1");
        holes[1].setName("1");
        holes[1].setBounds(132, 396, 132, 132);
        panel.add(holes[1]);

        holes[2] = new JLabel("2");
        holes[2].setName("2");
        holes[2].setBounds(264, 396, 132, 132);
        panel.add(holes[2]);

        holes[3] = new JLabel("3");
        holes[3].setName("3");
        holes[3].setBounds(396, 396, 132, 132);
        panel.add(holes[3]);

        holes[4] = new JLabel("4");
        holes[4].setName("4");
        holes[4].setBounds(0, 264, 132, 132);
        panel.add(holes[4]);

        holes[5] = new JLabel("5");
        holes[5].setName("5");
        holes[5].setBounds(132, 264, 132, 132);
        panel.add(holes[5]);

        holes[6] = new JLabel("6");
        holes[6].setName("6");
        holes[6].setBounds(264, 264, 132, 132);
        panel.add(holes[6]);

        holes[7] = new JLabel("7");
        holes[7].setName("7");
        holes[7].setBounds(396, 264, 132, 132);
        panel.add(holes[7]);

        holes[8] = new JLabel("8");
        holes[8].setName("8");
        holes[8].setBounds(0, 132, 132, 132);
        panel.add(holes[8]);

        holes[9] = new JLabel("9");
        holes[9].setName("9");
        holes[9].setBounds(132, 132, 132, 132);
        panel.add(holes[9]);

        holes[10] = new JLabel("10");
        holes[10].setName("10");
        holes[10].setBounds(264, 132, 132, 132);
        panel.add(holes[10]);

        holes[11] = new JLabel("11");
        holes[11].setName("11");
        holes[11].setBounds(396, 132, 132, 132);
        panel.add(holes[11]);

        holes[12] = new JLabel("12");
        holes[12].setName("12");
        holes[12].setBounds(0, 0, 132, 132);
        panel.add(holes[12]);

        holes[13] = new JLabel("13");
        holes[13].setName("13");
        holes[13].setBounds(132, 0, 132, 132);
        panel.add(holes[13]);

        holes[14] = new JLabel("14");
        holes[14].setName("14");
        holes[14].setBounds(264, 0, 132, 132);
        panel.add(holes[14]);

        holes[15] = new JLabel("15");
        holes[15].setName("15");
        holes[15].setBounds(396, 0, 132, 132);
        panel.add(holes[15]);

        for(int i = 0; i < 16; i++){
            holes[i].setIcon(loadImage("/moleIn.png"));
        }

        setContentPane(contentPane);
    }

    public static void main(String[] args) {
        Game frame = new Game();
        frame.setVisible(true);
    }
}


Now we need to start implementing the Game Board array which will determine the state of each of the 16 holes (mole peeking out or mole hidden inside)

We will use an int to represent the state: 0 = empty hole, 1 = mole peeking out of hole

So let's go ahead an create a one-dimensional integer array of size 16:

private int[] board = new int[16];

Make sure it is a global variable (do not place it inside any function or the constructor)

Now go back to the code that loops through the labels:

for(int i = 0; i < 16; i++){
    holes[i].setIcon(loadImage("/moleIn.png"));
}

And add a line of code inside the loop which initialises the 'board' array values to 0:

for(int i = 0; i < 16; i++){
    holes[i].setIcon(loadImage("/moleIn.png"));
    board[i] = 0;
}

Create a function which generates a random number 0-15 which determines which hole a mole will appear from

The scope of our game will be limited so that one mole can appear from any hole at one point and the goal is to hit the mole as fast as possible.

So let's create the function
private void genRandMole(){
    Random rnd = new Random(System.currentTimeMillis()); //seeding random with current time
    int moleID = rnd.nextInt(16);
    board[moleID] = 1;
    holes[moleID].setIcon(loadImage("/moleOut.png"));
}

Random rnd = new Random(System.currentTimeMillis()); - initialises a Random object
int moleID = rnd.nextInt(16); - declares a variable 'moleID' and assigns it to a random integer between 0 and 15
board[moleID] = 1; - set's the board index 'moleID' to 1 which indicates that the mole is peeking out of the hole.
holes[moleID].setIcon(loadImage("/moleOut.png")); - set's the label from the 'holes' array at index 'moleID' to the image displaying the mole peeking out of the hole.

Note that moleOut.png should also be saved in the 'res' folder of the project for this to work. Simply save the following image as: 'moleOut.png' and move it into the 'res' folder.

We will use this function in the next lesson so stay tuned.

Coding 4: Source Code

import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;


public class Game extends JFrame{

    private JPanel panel;
    private JLabel[] holes = new JLabel[16];
    private int[] board = new int[16];

    private void genRandMole(){
        Random rnd = new Random(System.currentTimeMillis()); //seeding random with current time
        int moleID = rnd.nextInt(16);
        board[moleID] = 1;
        holes[moleID].setIcon(loadImage("/moleOut.png"));
    }

    private ImageIcon loadImage(String path){
        Image image = new ImageIcon(this.getClass().getResource(path)).getImage();
        Image scaledImage = image.getScaledInstance(132, 132,  java.awt.Image.SCALE_SMOOTH);
        return new ImageIcon(scaledImage);
    }

    public Game() {
        setTitle("Whack A Mole");
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 608, 720);

        JPanel contentPane = new JPanel();
        contentPane = new JPanel();
        contentPane.setBackground(new Color(0, 51, 0));
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(null);

        JLabel lblTitle = new JLabel("Whack A Mole");
        lblTitle.setForeground(new Color(153, 204, 0));
        lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
        lblTitle.setFont(new Font("Century Gothic", Font.BOLD, 20));
        lblTitle.setBounds(0, 0, 602, 47);
        contentPane.add(lblTitle);

        panel = new JPanel();
        panel.setBackground(new Color(0, 102, 0));
        panel.setBounds(32, 105, 535, 546);
        panel.setLayout(null);
        contentPane.add(panel);

        holes[0] = new JLabel("0");
        holes[0].setName("0");
        holes[0].setBounds(0, 396, 132, 132);
        panel.add(holes[0]);

        holes[1] = new JLabel("1");
        holes[1].setName("1");
        holes[1].setBounds(132, 396, 132, 132);
        panel.add(holes[1]);

        holes[2] = new JLabel("2");
        holes[2].setName("2");
        holes[2].setBounds(264, 396, 132, 132);
        panel.add(holes[2]);

        holes[3] = new JLabel("3");
        holes[3].setName("3");
        holes[3].setBounds(396, 396, 132, 132);
        panel.add(holes[3]);

        holes[4] = new JLabel("4");
        holes[4].setName("4");
        holes[4].setBounds(0, 264, 132, 132);
        panel.add(holes[4]);

        holes[5] = new JLabel("5");
        holes[5].setName("5");
        holes[5].setBounds(132, 264, 132, 132);
        panel.add(holes[5]);

        holes[6] = new JLabel("6");
        holes[6].setName("6");
        holes[6].setBounds(264, 264, 132, 132);
        panel.add(holes[6]);

        holes[7] = new JLabel("7");
        holes[7].setName("7");
        holes[7].setBounds(396, 264, 132, 132);
        panel.add(holes[7]);

        holes[8] = new JLabel("8");
        holes[8].setName("8");
        holes[8].setBounds(0, 132, 132, 132);
        panel.add(holes[8]);

        holes[9] = new JLabel("9");
        holes[9].setName("9");
        holes[9].setBounds(132, 132, 132, 132);
        panel.add(holes[9]);

        holes[10] = new JLabel("10");
        holes[10].setName("10");
        holes[10].setBounds(264, 132, 132, 132);
        panel.add(holes[10]);

        holes[11] = new JLabel("11");
        holes[11].setName("11");
        holes[11].setBounds(396, 132, 132, 132);
        panel.add(holes[11]);

        holes[12] = new JLabel("12");
        holes[12].setName("12");
        holes[12].setBounds(0, 0, 132, 132);
        panel.add(holes[12]);

        holes[13] = new JLabel("13");
        holes[13].setName("13");
        holes[13].setBounds(132, 0, 132, 132);
        panel.add(holes[13]);

        holes[14] = new JLabel("14");
        holes[14].setName("14");
        holes[14].setBounds(264, 0, 132, 132);
        panel.add(holes[14]);

        holes[15] = new JLabel("15");
        holes[15].setName("15");
        holes[15].setBounds(396, 0, 132, 132);
        panel.add(holes[15]);

        for(int i = 0; i < 16; i++){
            holes[i].setIcon(loadImage("/moleIn.png"));
            board[i] = 0;
        }

        setContentPane(contentPane);
    }

    public static void main(String[] args) {
        Game frame = new Game();
        frame.setVisible(true);
    }
}