258 lines
9.9 KiB
Java
258 lines
9.9 KiB
Java
Blobs (applet)
|
|
|
|
import java.awt.event.*;
|
|
import java.applet.Applet;
|
|
|
|
public class Blobs extends Applet implements ActionListener, MouseListener {
|
|
|
|
final static int SQUARE_SIZE = 8; // Size of one square in the grid.
|
|
|
|
Label message; // For displaying information to the user.
|
|
|
|
Choice percentFill; // When the user clicks the "New Blobs" button
|
|
// to randomly fill the grid, this menu controlls
|
|
// the probability that a given square in the grid
|
|
// is filled.
|
|
|
|
int rows; // Number of rows in the grid. This depend on the size of the applet.
|
|
int columns; // Number of columns in the grid. This depend on the size of the applet.
|
|
|
|
boolean[][] filled; // filled[r][c] is true if the square at row r, column c is filled.
|
|
|
|
boolean[][] visited; // visited[r][c] is true if the square at row r, column c has
|
|
// has already been visited by the getBlobSize() method.
|
|
|
|
|
|
public void init() {
|
|
// Initialize the applet. Use a null layout and set the bounds
|
|
// of the components in the applet directly. The applet listens
|
|
// for mouse clicks on itself.
|
|
|
|
setLayout(null);
|
|
setBackground(new Color(220,220,255));
|
|
addMouseListener(this);
|
|
|
|
/* Determine the number of rows and columns and create the
|
|
filled and visited arrays. Fill the squares at random. */
|
|
|
|
int width = getSize().width;
|
|
int height = getSize().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);
|
|
|
|
/* Create the components. */
|
|
|
|
message = new Label("Click a square to get the blob size.", Label.CENTER);
|
|
message.setForeground(Color.blue);
|
|
message.setFont(new Font("Helvetica",Font.PLAIN,14));
|
|
|
|
percentFill = new Choice();
|
|
percentFill.add("10% fill");
|
|
percentFill.add("20% fill");
|
|
percentFill.add("30% fill");
|
|
percentFill.add("40% fill");
|
|
percentFill.add("50% fill");
|
|
percentFill.add("60% fill");
|
|
percentFill.add("70% fill");
|
|
percentFill.add("80% fill");
|
|
percentFill.add("90% fill");
|
|
percentFill.setBackground(Color.white);
|
|
percentFill.select(2);
|
|
|
|
Button newButton = new Button("New Blobs");
|
|
newButton.addActionListener(this);
|
|
newButton.setBackground(Color.lightGray);
|
|
|
|
Button countButton = new Button("Count the Blobs");
|
|
countButton.addActionListener(this);
|
|
countButton.setBackground(Color.lightGray);
|
|
|
|
/* Add the components to the applet and set their sizes and positions. */
|
|
|
|
add(message);
|
|
add(newButton);
|
|
add(percentFill);
|
|
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);
|
|
|
|
} // end init();
|
|
|
|
|
|
public void paint(Graphics g) {
|
|
// Paint the applet, showing the grid of squares.
|
|
|
|
int width = getSize().width;
|
|
int height = getSize().height;
|
|
|
|
/* Draw a blue border around the applet. */
|
|
|
|
g.setColor(Color.blue);
|
|
g.drawRect(0,0,width-1,height-1);
|
|
g.drawRect(1,1,width-3,height-3);
|
|
|
|
/* Fill the area occupied by the grid with white, then draw
|
|
black lines around this area and between the squares of
|
|
the grid. */
|
|
|
|
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);
|
|
|
|
/* Fill "visited" squares with red and "filled" squares with gray.
|
|
Other squares remain white. */
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
} // end paint();
|
|
|
|
|
|
public void actionPerformed(ActionEvent evt) {
|
|
// When the user clicks a button, call the appropriate method.
|
|
String cmd = evt.getActionCommand();
|
|
if (cmd.equals("New Blobs"))
|
|
fillGrid();
|
|
else if (cmd.equals("Count the Blobs"))
|
|
countBlobs();
|
|
}
|
|
|
|
|
|
void fillGrid() {
|
|
// When the user clicks the "New Blobs" button, fill the grid of squares
|
|
// randomly. The probability that a given square is filled is given by
|
|
// the percentFill Choice menu. The probabilities corresponding to the
|
|
// items in that menu are 0.1, 0.2,... 0.9. The visited array is cleared
|
|
// so there won't be any red-colored squares in the grid.
|
|
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() {
|
|
// When the use clicks the "Count the Blobs" button, find the number
|
|
// of blobs in the grid and report the number in the message Label.
|
|
|
|
int count = 0; // Number of blobs.
|
|
|
|
/* First clear out the visited array. The getBlobSize() method will
|
|
mark every filled square that it finds by setting the corresponding
|
|
element of the array to true. Once a square has been marked as
|
|
visited, it will stay marked until all the blobs have been counted.
|
|
This will prevent the same blob from being counted more than once. */
|
|
|
|
for (int r = 0; r < rows; r++)
|
|
for (int c = 0; c < columns; c++)
|
|
visited[r][c] = false;
|
|
|
|
/* For each position in the grid, call getBlobSize() to get the size
|
|
of the blob at that position. If the sixe is not zero, count a blob.
|
|
Note that if we come to a position that was part of a previously
|
|
counted square, getBlobSize() will return 0 and the blob will not
|
|
be counted again. */
|
|
|
|
for (int r = 0; r < rows; r++)
|
|
for (int c = 0; c < columns; c++) {
|
|
if (getBlobSize(r,c) > 0)
|
|
count++;
|
|
}
|
|
|
|
repaint(); // Note that all the filled squares will be red!
|
|
|
|
message.setText("The number of blobs is " + count);
|
|
|
|
} // end countBlobs()
|
|
|
|
|
|
int getBlobSize(int r, int c) {
|
|
// Counts the squares in the blob at position (r,c) in the
|
|
// grid. Squares are only counted if they are filled and
|
|
// unvisited. If this routine is called for a position that
|
|
// has been visited, the return value will be zero.
|
|
if (r < 0 || r >= rows || c < 0 || c >= columns) {
|
|
// This position is not in the grid, so there is
|
|
// no blob at this position.
|
|
return 0;
|
|
}
|
|
if (filled[r][c] == false || visited[r][c] == true) {
|
|
// This square is not part of a blob, or else it has
|
|
// already been counted, so return zero.
|
|
return 0;
|
|
}
|
|
visited[r][c] = true; // Mark the square as visited so that
|
|
// we won't count it again during the
|
|
// following recursive calls to this method.
|
|
int size = 1; // Count the square at this position, then count the
|
|
// the blobs that are connected to this square
|
|
// horizontally or vertically.
|
|
size += getBlobSize(r-1,c);
|
|
size += getBlobSize(r+1,c);
|
|
size += getBlobSize(r,c-1);
|
|
size += getBlobSize(r,c+1);
|
|
return size;
|
|
} // end getBlobSize()
|
|
|
|
|
|
public void mousePressed(MouseEvent evt) {
|
|
// The user has clicked the mouse on the applet. If the
|
|
// user has clicked on a position in the grid, count
|
|
// the number of squares in the blob at that position.
|
|
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; // Clear visited array before counting.
|
|
int size = getBlobSize(row,col);
|
|
if (size == 0)
|
|
message.setText("There is no blob at (" + row + "," + col + ").");
|
|
else if (size == 1)
|
|
message.setText("The blob at (" + row + "," + col + ") contains 1 square.");
|
|
else
|
|
message.setText("The blob at (" + row + "," + col + ") contains " + size + " squares.");
|
|
repaint();
|
|
}
|
|
|
|
|
|
public void mouseReleased(MouseEvent e) { } // Methods required by MouseListener interface
|
|
public void mouseClicked(MouseEvent e) { }
|
|
public void mouseEntered(MouseEvent e) { }
|
|
public void mouseExited(MouseEvent e) { }
|
|
|
|
|
|
} // end class Blobs
|