/* An instance of this class identifies the "regions" of a two-dimensional ** (i.e., rectangular) "map". Each location on the map has an associated ** character value (e.g., 'A'). Two locations are defined to be in the ** same region if they are connected by a path in which all locations are ** associated to the same character. Two locations can appear consecutively ** in a path only if they are "neighbors". Under the default mode, locations ** (r,c) and (r',c') are neighbors if |r-r'| + |c-c'| = 1, which is to say ** that they share a common border (i.e., one location is to the immediate ** "north", "south", "east", or "west" of the other). Under the "wraparound" ** mode, the first and last rows are adjacent to each other, as are the ** first and last columns, so that every location has exactly four neighbors. ** ** Author: R. McCloskey and < STUDENT's NAME > ** Collaborated with: ... ** Known Defects: ... */ public class MapRegionFinder { // class constant // -------------- private static boolean WRAP_AROUND_DEFAULT = false; // instance variables // ------------------ private char[][] map; // the map private int[][] regionID; // the locations' region ID's private final int M; // # rows in the map private final int N; // # columns in the map private int numRegions; // # of regions identified private boolean wrapAround; // Are rows 0 and M-1 and columns 0 and N-1 // interpreted to be adjacent? // constructor // ----------- /* Computes the regions of the given map in preparation for calls to ** the regionOf() (and other) methods. The second argument dictates ** whether or not the map is assumed to "wrap around" so that the ** top and bottom rows are adjacent to each other and likewise for ** the leftmost and rightmost columns. ** pre: Each row of the given map has the same number of columns ** (i.e., theMap is rectangular rather than "ragged") */ public MapRegionFinder(char[][] theMap, boolean wrapMode) { wrapAround = wrapMode; map = theMap.clone(); M = theMap.length; // # of rows in the map N = theMap[0].length; // # of columns in each row computeRegions(); } /* Does what the constructor above does, with wraparound mode ** set to the default. */ public MapRegionFinder(char[][] theMap) { this(theMap, WRAP_AROUND_DEFAULT); } // observers // --------- /* Returns the number of rows on the map. */ public int numRows() { return M; } /* Returns the number of columns on the map. */ public int numCols() { return N; } /* Returns the number of distinct regions on the map. */ public int numRegions() { return numRegions; } /* Returns the ID of the region in which the specified location ** lies, which is an integer in the range [1..numRegions()]. */ public int regionOf(int row, int col) { return regionID[row][col]; } /* Prints the map, showing the character value associated ** to each location. */ public void printMap() { for (int i=0; i != M; i++) { for (int j=0; j != N; j++) { System.out.printf("%3c", map[i][j]); } System.out.println(); } } /* Prints the map, but with each location's region ID showing ** (rather than its associated character). */ public void printRegionIds() { for (int i=0; i != M; i++) { for (int j=0; j != N; j++) { System.out.printf("%3d", regionOf(i,j)); } System.out.println(); } } // private method (that does all the interesting work) // --------------------------------------------------- /* Creates the regionID[] matrix and places into each location a ** region ID satisfying the condition that two locations have the same ** region ID iff they lie in the same region. Also, the region ID's ** should form the consecutive range of integers [1 .. numRegions()]. */ private void computeRegions() { numRegions = 0; regionID = new int[M][N]; // STUB!! // Here should be code that iterates over every location in // the map. Any location found not already to have been marked // as being in some region should be "explored from" using a // recursive method that marks all locations in the same // region as that location. } }