Home  Contents

The Puzzle game in Java Swing

In this chapter, we will create a simple puzzle game in Java Swing toolkit.

Puzzle

We have an image of a Sid character from the Ice Age movie. It is cut into 12 pieces. The goal is to form the picture.

package zetcode;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Puzzle extends JFrame implements ActionListener {

    private JPanel centerPanel;
    private JButton button;
    private JLabel label;
    private Image source;
    private Image image;
    int[][] pos;
    int width, height;

    public Puzzle() {

        initUI();
    }

    public final void initUI() {

        pos = new int[][]{
                    {0, 1, 2},
                    {3, 4, 5},
                    {6, 7, 8},
                    {9, 10, 11}
                };


        centerPanel = new JPanel();
        centerPanel.setLayout(new GridLayout(4, 4, 0, 0));

        ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
        source = sid.getImage();

        width = sid.getIconWidth();
        height = sid.getIconHeight();


        add(Box.createRigidArea(new Dimension(0, 5)), BorderLayout.NORTH);
        add(centerPanel, BorderLayout.CENTER);


        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                if (j == 2 && i == 3) {
                    label = new JLabel("");
                    centerPanel.add(label);
                } else {
                    button = new JButton();
                    button.addActionListener(this);
                    centerPanel.add(button);
                    image = createImage(new FilteredImageSource(source.getSource(),
                            new CropImageFilter(j * width / 3, i * height / 4,
                            (width / 3) + 1, height / 4)));
                    button.setIcon(new ImageIcon(image));
                }
            }
        }

        setSize(325, 275);
        setTitle("Puzzle");
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    public void actionPerformed(ActionEvent e) {

        JButton button = (JButton) e.getSource();
        Dimension size = button.getSize();

        int labelX = label.getX();
        int labelY = label.getY();
        int buttonX = button.getX();
        int buttonY = button.getY();
        int buttonPosX = buttonX / size.width;
        int buttonPosY = buttonY / size.height;
        int buttonIndex = pos[buttonPosY][buttonPosX];



        if (labelX == buttonX && (labelY - buttonY) == size.height) {

            int labelIndex = buttonIndex + 3;

            centerPanel.remove(buttonIndex);
            centerPanel.add(label, buttonIndex);
            centerPanel.add(button, labelIndex);
            centerPanel.validate();
        }

        if (labelX == buttonX && (labelY - buttonY) == -size.height) {

            int labelIndex = buttonIndex - 3;
            centerPanel.remove(labelIndex);
            centerPanel.add(button, labelIndex);
            centerPanel.add(label, buttonIndex);
            centerPanel.validate();
        }

        if (labelY == buttonY && (labelX - buttonX) == size.width) {

            int labelIndex = buttonIndex + 1;

            centerPanel.remove(buttonIndex);
            centerPanel.add(label, buttonIndex);
            centerPanel.add(button, labelIndex);
            centerPanel.validate();
        }

        if (labelY == buttonY && (labelX - buttonX) == -size.width) {

            int labelIndex = buttonIndex - 1;

            centerPanel.remove(buttonIndex);
            centerPanel.add(label, labelIndex);
            centerPanel.add(button, labelIndex);
            centerPanel.validate();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                Puzzle puzzle = new Puzzle();
                puzzle.setVisible(true);
            }
        });
    }
}

The goal of this little game is to form the original picture. We move the buttons by clicking on them. Only buttons adjacent to the label can be moved.

pos = new int[][] {
      {0, 1, 2}, 
      {3, 4, 5}, 
      {6, 7, 8}, 
      {9, 10, 11}
};

These are the positions of the image parts.

ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
source = sid.getImage();

We use the ImageIcon class to load the image.

for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 3; j++) {
        if (j == 2 && i == 3) {
            label = new JLabel("");
            centerPanel.add(label);
        } else {
            button = new JButton();
            button.addActionListener(this);
            centerPanel.add(button);
            image = createImage(new FilteredImageSource(source.getSource(),
                    new CropImageFilter(j * width / 3, i * height / 4,
                    (width / 3) + 1, height / 4)));
            button.setIcon(new ImageIcon(image));
        }
    }
}

The code creates 11 buttons and one label. We crop the image into pieces and place them on the buttons.

int labelX = label.getX();
int labelY = label.getY();
int buttonX = button.getX();
int buttonY = button.getY();

We get the x, y coordinates of the button that we hit and an empty label. The x, y coordinates are important in the logic of the program.

int buttonPosX = buttonX / size.width;
int buttonPosY = buttonY / size.height;
int buttonIndex = pos[buttonPosY][buttonPosX];

Here we get the index of the button in the two dimensional array of the button positions.

if (labelX == buttonX && (labelY - buttonY) == size.height ) {

    int labelIndex = buttonIndex + 3;

    centerPanel.remove(buttonIndex);
    centerPanel.add(label, buttonIndex);
    centerPanel.add(button,labelIndex);
    centerPanel.validate();
}

In this case, we check if we clicked on the button that is right above the empty label. If it is above the label, they share the x coordinate. If the button is right above the label, the equation (labelY - buttonY) == size.height is true.

Puzzle
Figure: Puzzle

This was a puzzle game.