import java.io.File; import java.io.IOException; import java.util.Scanner; /** * A class representing a 2D world containing blobs of various sizes. */ public class BlobWorld { /** * The 2D grid containing the contents of the world. * Each cell is either part of a blob (true) or not (false). */ private boolean[][] grid; /** * Number of rows of the world. */ private int numRows; /** * Number of columns of the world. */ private int numCols; /** * Construct a new blob world from an input file containing a text * representation of the world. * * @param blobFile The input text filename to process. */ public BlobWorld(String blobFile) { try { Scanner scan = new Scanner(new File(blobFile)); numCols = 0; numRows = 0; while (scan.hasNext()) { numRows++; String line = scan.nextLine(); int lineLen = line.length(); if (lineLen > numCols) { numCols = lineLen; } } scan.close(); } catch (IOException e) { throw new IllegalArgumentException("failed to read " + blobFile); } grid = new boolean[numRows][numCols]; try { Scanner scan = new Scanner(new File(blobFile)); for (int r = 0; r < numRows; r++) { String line = scan.nextLine(); for (int c = 0; c < numCols; c++) { grid[r][c] = (line.charAt(c) != ' '); } } scan.close(); } catch (IOException e) { throw new IllegalArgumentException("failed to read " + blobFile); } } /** * Get the number of rows in the world. * * @return The number of rows. */ public int getRows() { return numRows; } /** * Get the number of columns in the world. * * @return The number of cols. */ public int getCols() { return numCols; } /** * Produce a nice textual representation of the blob world. * * @return The textual world representation. */ @Override public String toString() { String s = " "; for (int c = 0; c < numCols; c++) { s += c % 10; // label each col using a single digit } s += "\n"; for (int r = 0; r < numRows; r++) { s += (r % 10) + " "; // label each row using a single digit for (int c = 0; c < numCols; c++) { if (grid[r][c]) { s += 'X'; } else { s += ' '; } } s += "\n"; } s += "\n"; return s; } /** * Make a copy of the internal grid to avoid modification of the actual grid. * @return A fresh copy of the 2D grid array. */ private boolean[][] makeGridCopy() { boolean[][] gridCopy = new boolean[numRows][numCols]; for (int r = 0; r < numRows; r++) { gridCopy[r] = new boolean[numCols]; System.arraycopy(grid[r], 0, gridCopy[r], 0, numCols); } return gridCopy; } /** * For each cell that is part of a blob, print out the total size of * the blob that contains that cell. */ public void findAllBlobs() { boolean[][] gridCopy = makeGridCopy(); // save an unmodified copy of the world for (int r = 0; r < numRows; r++) { for (int c = 0; c < numCols; c++) { int blobSize = blobSize(r, c); // count this blob if (blobSize > 0) { System.out.println("Blob of size " + blobSize + " at (" + r + "," + c + ")"); } } } grid = gridCopy; // restore the original grid (containing all blobs) } /** * Erase the blob that contains the cell at the given row and column positions. * * @param r The row of the desired blob. * @param c The column of the desired blob. */ public void eraseBlob(int r, int c) { if (r < 0 || c < 0 || r >= numRows || c >= numCols || !grid[r][c]) { return; } else { grid[r][c] = false; eraseBlob(r, c - 1); eraseBlob(r, c + 1); eraseBlob(r - 1, c); eraseBlob(r + 1, c); } } /** * Find and return the size of the blob that contains the cell at the given * row and column positions. * Note: also erases the blob in the course of counting it, so the * original grid should be saved prior to calling this method. * * @param r The row of the desired blob. * @param c The column of the desired blob. */ public int blobSize(int r, int c) { if (r < 0 || c < 0 || r >= numRows || c >= numCols || !grid[r][c]) { return 0; } else { int size = 1; grid[r][c] = false; // don't re-count this square size += blobSize(r - 1, c); size += blobSize(r, c - 1); size += blobSize(r + 1, c); size += blobSize(r, c + 1); return size; } } /** * Constructs a blob world from an input filename, displays all blobs * in the world, then allows the user to erase specific blobs. */ public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.print("Enter blob filename: "); String fileName = scan.next(); BlobWorld world = new BlobWorld(fileName); while (true) { System.out.println(); world.findAllBlobs(); System.out.println(); System.out.println(world); System.out.print("Enter a row and col number to erase a blob: "); int row = scan.nextInt(); int col = scan.nextInt(); if (row >= world.getRows()) { System.out.println("Invalid row, try again"); } else if (col >= world.getCols()) { System.out.println("Invalid col, try again"); } else { System.out.println("Erased blob at (" + row + "," + col + ")"); world.eraseBlob(row, col); } } } }