Playing memory games can improve attention, and concentration and enhance critical thinking. In this article, we will make a Memory game in Java with Swing. This game requires the player to remember the position of different images and try to match two similar images within a limited number of attempts.
Project Overview: Memory Game in Java
Project Name: | Memory Game in Java |
Abstract: | It’s a GUI-based project used with the swing library to organize all the elements that work under the Memory Game. |
Language Used: | Java |
IDE: | VS Code |
Java version (Recommended): | Java SE 18.0. 2.1 |
Database: | None |
Type: | Desktop Application |
Recommended for: | Beginners of Java |
Time to build: | 1-2 hours |
What will you learn?
- Building the logic of the game with the help of conditionals and loops
- Learn the OOPs paradigm with the help of classes, objects, and inheritance
- Creating user-friendly graphics with the help of Java Swing and Java AWT
Features
- The player will be able to flip the pieces and check the image on it
- If two images do not match then the number of tries left decreases
- A total of 10 tries are given initially to increase the difficulty of the game
- 4*4 images are shown and the player needs to match all the images correctly to win
- For a fresh start, the images are picked and placed randomly in the window
Complete Code for Memory Game in Java
Create a folder for the project and a file with the name Game.java. Download all the images for the project from here and keep all these images in the project folder. Now, paste the below lines of code into that file. Comments are provided for explanation.
import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.util.stream.Collectors; import javax.swing.Timer; class Game { public static class Controller { final JFrame window; Model model; View view; // Constructor public Controller(Model model) { this.window = new JFrame("Memory"); // Create the window this.window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close the window when the user clicks on the close button this.window.setResizable(false); // Disable the resizing of the window this.reset(model); // Reset the game } // Reset the game public void reset(Model model) { this.model = model; this.view = new View(model); this.window.setVisible(false); this.window.setContentPane(view); this.window.pack(); this.window.setLocationRelativeTo(null); for (JButton button : this.model.getButtons()) { button.addActionListener(new ButtonActionListener(this)); } Utilities.timer(200, (ignored) -> this.window.setVisible(true)); // Show the window after 200ms } public JFrame getWindow() { return this.window; } public Model getModel() { return this.model; } public View getView() { return this.view; } } public static class Model { // Constants for the game static final String[] AVAILABLE_IMAGES = new String[]{"0.png", "1.png", "2.png", "3.png", "4.png", "5.png", "6.png", "7.png", "8.png"}; static final Integer MAX_REGISTERED_SCORES = 10; final ArrayList<Float> scores; final ArrayList<JButton> buttons; final int columns; // Number of columns int tries; // Number of tries left boolean gameStarted; // Is the game started public Model(int columns) { this.columns = columns; // Number of columns this.buttons = new ArrayList<>(); // List of buttons in the game this.scores = new ArrayList<>(); // List of scores in the game this.tries = 10; // Number of tries initially this.gameStarted = false; // Game is not started initially int numberOfImage = columns * columns; // Number of images Vector<Integer> v = new Vector<>(); // Vector to store the images for (int i = 0; i < numberOfImage - numberOfImage % 2; i++) { // Add the images twice v.add(i % (numberOfImage / 2)); } if (numberOfImage % 2 != 0) v.add(AVAILABLE_IMAGES.length - 1); // Add the last image if the number of images is odd // Add the images as a button to the game for (int i = 0; i < numberOfImage; i++) { int rand = (int) (Math.random() * v.size()); // Randomly select an image String reference = AVAILABLE_IMAGES[v.elementAt(rand)]; // Get the image this.buttons.add(new MemoryButton(reference)); // Add the image as a button v.removeElementAt(rand); // Remove the image from the vector } } public int getColumns() { return columns; } public ArrayList<JButton> getButtons() { return buttons; } // Get the number of tries left public int getTries() { return tries; } // Decrement the tries count by calling this method public void decrementTries() { this.tries--; } // return if the game has started public boolean isGameStarted() { return this.gameStarted; } // start the game public void startGame() { this.gameStarted = true; } } // class to handle the UI of the game public static class View extends JPanel { final JLabel tries; public View(Model model) { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.tries = new JLabel("", SwingConstants.CENTER); this.tries.setFont(new Font("MV Boli", Font.BOLD, 30)); this.tries.setForeground(Color.WHITE); JPanel imagePanel = new JPanel(); int columns = model.getColumns(); imagePanel.setLayout(new GridLayout(columns, columns)); for (JButton button : model.getButtons()) { imagePanel.add(button); } this.setTries(model.getTries()); JPanel triesPanel = new JPanel(); triesPanel.add(this.tries); triesPanel.setAlignmentX(CENTER_ALIGNMENT); triesPanel.setBackground(new Color(0X8946A6)); this.add(triesPanel); this.add(imagePanel); } public void setTries(int triesLeft) { this.tries.setText("Tries left : " + triesLeft); } } // class to handle the button clicks public static class ReferencedIcon extends ImageIcon { final String reference; public ReferencedIcon(Image image, String reference) { super(image); this.reference = reference; } public String getReference() { return reference; } } // class to handle the button on the images public static class MemoryButton extends JButton { static final String IMAGE_PATH = ""; static final Image NO_IMAGE = Utilities.loadImage("no_image.png"); public MemoryButton(String reference) { Image image = Utilities.loadImage(IMAGE_PATH + reference); Dimension dimension = new Dimension(120, 120); this.setPreferredSize(dimension); this.setIcon(new ImageIcon(NO_IMAGE)); this.setDisabledIcon(new ReferencedIcon(image, reference)); } } public static class Dialogs { public static void showLoseDialog(JFrame window) { UIManager.put("OptionPane.background", new Color(0XEA99D5)); UIManager.put("Panel.background", new Color(0XEA99D5)); JOptionPane.showMessageDialog(window, "You lost, try again !", "You lost !", JOptionPane.INFORMATION_MESSAGE); } public static void showWinDialog(JFrame window, Model model) { String message = String.format("Congrats you won!!"); UIManager.put("OptionPane.background", new Color(0XEA99D5)); UIManager.put("Panel.background", new Color(0XEA99D5)); JOptionPane.showMessageDialog(window.getContentPane(), message, "", JOptionPane.INFORMATION_MESSAGE); } } // class to handle the button clicks public static class ButtonActionListener implements ActionListener { final Controller controller; final Model model; final View view; final JFrame window; static int disabledButtonCount = 0; static JButton lastDisabledButton = null; static final Image TRAP_IMAGE = Utilities.loadImage("no_image.png"); final ReferencedIcon trap; public ButtonActionListener(Controller controller) { this.controller = controller; this.model = controller.getModel(); this.view = controller.getView(); this.window = controller.getWindow(); this.trap = new ReferencedIcon(TRAP_IMAGE, "no_image.png"); } // Method to handle the button clicks and check if two images are same @Override public void actionPerformed(ActionEvent e) { JButton button = (JButton) e.getSource(); button.setEnabled(false); ReferencedIcon thisIcon = (ReferencedIcon) button.getDisabledIcon(); disabledButtonCount++; if (!model.isGameStarted()) { // If the game has not started model.startGame(); // Start the game } if (disabledButtonCount == 2) { // If two buttons are disabled ReferencedIcon thatIcon = (ReferencedIcon) lastDisabledButton.getDisabledIcon(); boolean isPair = thisIcon.getReference().equals(thatIcon.getReference()); // Check if the two images are the same if (!isPair) { // If the two images are not the same model.decrementTries(); // Decrement the number of tries view.setTries(model.getTries()); // Update the number of tries JButton lastButton = lastDisabledButton; // Store the last button Utilities.timer(500, ((ignored) -> { // Wait 500ms before re-enabling the buttons button.setEnabled(true); // Re-enable the button lastButton.setEnabled(true); // Re-enable the last button })); } disabledButtonCount = 0; // Reset the counter } ArrayList<JButton> enabledButtons = (ArrayList<JButton>) model.getButtons().stream().filter(Component::isEnabled).collect(Collectors.toList()); if (enabledButtons.size() == 0) { // If all the buttons are disabled controller.reset(new Model(controller.getModel().getColumns())); // Reset the game Dialogs.showWinDialog(window, model); // Show the win dialog } lastDisabledButton = button; // Store the last button if (model.getTries() == 0) { // If the number of tries is 0 controller.reset(new Model(controller.getModel().getColumns())); // Reset the game Dialogs.showLoseDialog(window); // Show the lose dialog Utilities.timer(1000, (ignored) -> model.getButtons().forEach(btn -> btn.setEnabled(false))); // Wait 1s before disabling all the buttons } } } public static class Utilities { static final ClassLoader cl = Utilities.class.getClassLoader(); // Method to create a timer public static void timer(int delay, ActionListener listener) { Timer t = new Timer(delay, listener); t.setRepeats(false); t.start(); } // Method to load an image public static Image loadImage(String s) { Image image = null; try { InputStream resourceStream = cl.getResourceAsStream(s); if (resourceStream != null) { ImageInputStream imageStream = ImageIO.createImageInputStream(resourceStream); image = ImageIO.read(imageStream); } } catch (IOException e) { e.printStackTrace(); } return image; } } } // Main class to run the game class Main { static final int DEFAULT_SIZE = 4; public static void main(String[] args) { Locale.setDefault(Locale.ENGLISH); SwingUtilities.invokeLater(() -> new Game.Controller(new Game.Model(DEFAULT_SIZE))); } }
Output for Memory Game in Java:
Image Output:
Video Output:
Conclusion:
Hope you liked building the Memory Game in Java. To make the game more interesting you can try to put a timer and show the total time taken by the player to finish the game completely. All in all, we recommend you try and add more code to make this project more interesting.
Thank you for visiting our website.
Also Read:
- Dino Game in Java
- Java Games Code | Copy And Paste
- Supply Chain Management System in Java
- Survey Management System In Java
- Phone Book in Java
- Email Application in Java
- Inventory Management System Project in Java
- Blood Bank Management System Project in Java
- Electricity Bill Management System Project in Java
- CGPA Calculator App In Java
- Chat Application in Java
- 100+ Java Projects for Beginners 2023
- Airline Reservation System Project in Java
- Password and Notes Manager in Java
- GUI Number Guessing Game in Java
- How to create Notepad in Java?
- Memory Game in Java
- Simple Car Race Game in Java
- ATM program in Java
- Drawing Application In Java
- Tetris Game in Java
- Pong Game in Java
- Hospital Management System Project in Java
- Ludo Game in Java
- Restaurant Management System Project in Java
- Flappy Bird Game in Java
- ATM Simulator In Java
- Brick Breaker Game in Java
- Best Java Roadmap for Beginners 2023
- Snake Game in Java