Java Code to Demonstrate Recursion

The Java code implements a simple graphical application that visually represents and counts blobs within a grid by using recursion. A blob is a group of adjacent filled squares in the grid.

The application uses Java Swing for creating the graphical user interface (GUI) components. It includes buttons for generating a new set of blobs, counting the number of blobs, and a grid where users can click to get information about the blob size at that specific position. This Java code uses recursion in the getBlobSize method to calculate the size of a blob.

The squares are arranged in a grid, and each position in the grid can be either empty or filled. A blob is defined to be a filled square and any square that can be reached from that square by moving horizontally or vertically to other filled squares. The application fills the grid randomly. If the user clicks on a filled square, all the squares in the blob that contains that square are colored red, and the number of squares in the blob is reported. The applet can also count and report the number of blobs. When the user clicks a “New Blobs” button, the grid is randomly re-filled.

Recursion is a natural fit for problems involving exploration of connected components, such as counting the size of blobs in this case. It simplifies the code and leverages the call stack to keep track of the positions to explore.

How this Code Works?

Class Structure:

  • The main class is named BlobsApp, which extends JFrame and implements ActionListener and MouseListener interfaces.
  • The application is structured with an outer JFrame which represents the main window and an inner JPanel named Content serving as the content pane.

Initialization:

  • The init method is called during the initialization of the applet. It sets up the GUI components, initializes the grid, and creates buttons for generating new blobs and counting them.

Grid and Blob Generation:

  • The grid is represented by a 2D array of boolean values (filled). Each cell in the grid represents a square, and the boolean value indicates whether the square is filled.
  • The fillGrid method generates a new grid of blobs based on a user-specified probability.

Blob Counting:

  • The countBlobs method counts the number of blobs in the grid using a recursive algorithm (getBlobSize). The algorithm marks visited squares to prevent counting the same blob multiple times.
  • The result is displayed in a message label on the GUI.

Blob Size Calculation:

  • The getBlobSize method recursively calculates the size of a blob starting from a given position in the grid.

Mouse Interaction:

  • Users can interact with the grid by clicking on squares. The mousePressed method retrieves blob information for the clicked position and displays it in the message label.

GUI Presentation:

  • The GUI is presented with buttons for user actions, a grid of squares representing the blobs, and a message label for displaying information.
  • The Content class extends JPanel and is responsible for painting the grid based on the state of the blobs and visited squares.

Java Blob Source Code

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class BlobsApp extends JFrame implements ActionListener, MouseListener {

    private static final int SQUARE_SIZE = 8;

    private JLabel message;
    private JComboBox<String> percentFill;
    private int rows;
    private int columns;
    private boolean[][] filled;
    private boolean[][] visited;

    public BlobsApp() {
     setTitle("Blobs App");
        setSize(600, 400); // Set your preferred initial width and height
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(true);

        Content content = new Content();
        setContentPane(content);

        content.setLayout(null);
        content.setBackground(new Color(220, 220, 255));
        content.addMouseListener(this);
        content.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.blue));

        int width = 600; // Set your preferred width
        int height = 400; // Set your preferred height

        rows = (height - 100) / SQUARE_SIZE;
        columns = (width - 20) / SQUARE_SIZE;

        filled = new boolean[rows][columns];
        visited = new boolean[rows][columns];

        for (int r = 0; r < rows; r++)
            for (int c = 0; c < columns; c++)
                filled[r][c] = (Math.random() < 0.3);

        message = new JLabel("Click a square to get the blob size.", JLabel.CENTER);
        message.setForeground(Color.blue);
        message.setFont(new Font("Helvetica", Font.PLAIN, 14));

        percentFill = new JComboBox<>();
        for (int i = 1; i <= 9; i++) {
            percentFill.addItem(i * 10 + "% fill");
        }
        percentFill.setBackground(Color.white);
        percentFill.setSelectedIndex(2);

        JButton newButton = new JButton("New Blobs");
        newButton.addActionListener(this);
        newButton.setBackground(Color.lightGray);

        JButton countButton = new JButton("Count the Blobs");
        countButton.addActionListener(this);
        countButton.setBackground(Color.lightGray);

        content.add(message);
        content.add(newButton);
        content.add(percentFill);
        content.add(countButton);

        message.setBounds(15, height - 75, width - 30, 18);
        countButton.setBounds(15, height - 50, width - 30, 18);
        newButton.setBounds(15, height - 25, (width - 40) / 2, 18);
        percentFill.setBounds(width / 2 + 5, height - 25, (width - 40) / 2, 18);

        pack();
        setLocationRelativeTo(null); // Center the frame on the screen
        setVisible(true);

    }

    public void actionPerformed(ActionEvent evt) {
        String cmd = evt.getActionCommand();
        if ("New Blobs".equals(cmd))
            fillGrid();
        else if ("Count the Blobs".equals(cmd))
            countBlobs();
    }

    void fillGrid() {
        double probability = (percentFill.getSelectedIndex() + 1) / 10.0;
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < columns; c++) {
                filled[r][c] = (Math.random() < probability);
                visited[r][c] = false;
            }
        message.setText("Click a square to get the blob size.");
        repaint();
    }

    void countBlobs() {
        int count = 0;

        for (int r = 0; r < rows; r++)
            for (int c = 0; c < columns; c++)
                visited[r][c] = false;

        for (int r = 0; r < rows; r++)
            for (int c = 0; c < columns; c++) {
                if (getBlobSize(r, c) > 0)
                    count++;
            }

        repaint();
        message.setText("The number of blobs is " + count);
    }

    int getBlobSize(int r, int c) {
        if (r < 0 || r >= rows || c < 0 || c >= columns) {
            return 0;
        }
        if (!filled[r][c] || visited[r][c]) {
            return 0;
        }
        visited[r][c] = true;
        int size = 1;
        size += getBlobSize(r - 1, c);
        size += getBlobSize(r + 1, c);
        size += getBlobSize(r, c - 1);
        size += getBlobSize(r, c + 1);
        return size;
    }

    public void mousePressed(MouseEvent evt) {
        int row = (evt.getY() - 10) / SQUARE_SIZE;
        int col = (evt.getX() - 10) / SQUARE_SIZE;
        if (row < 0 || row >= rows || col < 0 || col >= columns) {
            message.setText("Please click on a square!");
            return;
        }
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < columns; c++)
                visited[r][c] = false;
        int size = getBlobSize(row, col);
        if (size == 0)
            message.setText("There is no blob at (" + row + "," + col + ").");
        else if (size == 1)
            message.setText("Blob at (" + row + "," + col + ") contains 1 square.");
        else
            message.setText("Blob at (" + row + "," + col + ") contains " + size + " squares.");
        repaint();
    }

    public void mouseReleased(MouseEvent e) {}

    public void mouseClicked(MouseEvent e) {}

    public void mouseEntered(MouseEvent e) {}

    public void mouseExited(MouseEvent e) {}

    class Content extends JPanel {

        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            int width = getSize().width;
            int height = getSize().height;

            g.setColor(Color.white);
            g.fillRect(10, 10, columns * SQUARE_SIZE, rows * SQUARE_SIZE);

            g.setColor(Color.black);
            for (int i = 0; i <= rows; i++)
                g.drawLine(10, 10 + i * SQUARE_SIZE, columns * SQUARE_SIZE + 10, 10 + i * SQUARE_SIZE);
            for (int i = 0; i <= columns; i++)
                g.drawLine(10 + i * SQUARE_SIZE, 10, 10 + i * SQUARE_SIZE, rows * SQUARE_SIZE + 10);

            for (int r = 0; r < rows; r++)
                for (int c = 0; c < columns; c++) {
                    if (visited[r][c]) {
                        g.setColor(Color.red);
                        g.fillRect(11 + c * SQUARE_SIZE, 11 + r * SQUARE_SIZE, SQUARE_SIZE - 1, SQUARE_SIZE - 1);
                    } else if (filled[r][c]) {
                        g.setColor(Color.gray);
                        g.fillRect(11 + c * SQUARE_SIZE, 11 + r * SQUARE_SIZE, SQUARE_SIZE - 1, SQUARE_SIZE - 1);
                    }
                }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new BlobsApp().setVisible(true);
        });
    }
}

When you run the program you will see a similar window as showing below:

M. Saqib: Saqib is Master-level Senior Software Engineer with over 14 years of experience in designing and developing large-scale software and web applications. He has more than eight years experience of leading software development teams. Saqib provides consultancy to develop software systems and web services for Fortune 500 companies. He has hands-on experience in C/C++ Java, JavaScript, PHP and .NET Technologies. Saqib owns and write contents on mycplus.com since 2004.
Related Post