CMPS 144 Spring 2020
Prog. Assg. #5: MapRegionFinder
Due: 11:59, May 5

Background

For the purposes of this assignment, a map is a two-dimensional array in which each location holds a value of type char. Two locations are considered to be neighbors if one is immediately to the "east", "west", "north", or "south" of the other (i.e., either their row numbers or column numbers differ by one, but not both). A path on a map is a sequence of locations such that consecutive locations in the sequence are neighbors of one another.

A region on a map is a maximal set of locations such that they all contain the same value and such that every pair of locations in the set is connected by a path that includes only locations within the set.

Files

Provided are the following Java artifacts and sample data file:

User/Program Dialog

Enter input file name: map1.txt
The map:
  A  A  A  C  C  B  A  A
  A  C  C  C  B  B  A  C
  A  A  C  C  C  B  A  C
  C  B  B  B  B  A  A  C
  A  C  B  B  A  A  A  B
  A  B  B  C  C  C  C  B

Region IDs:
  1  1  1  2  2  3  4  4
  1  2  2  2  3  3  4  5
  1  1  2  2  2  3  4  5
  6  7  7  7  7  4  4  5
  8  9  7  7  4  4  4 10
  8  7  7 11 11 11 11 10
To the right is shown a run of the MapRegionFinderApp program, provided with the input in the map1.txt file (see link above). Note that the user is prompted to enter the name of the input file. Alternatively, that name can be provided to the program via a command line argument (in which case the user will not be asked to enter a file name). (jGrasp calls these "run arguments"; here are instructions for using run arguments when running a program from within jGrasp.)

The program reads the map from the input file, passes that map to the constructor of MapRegionFinder class, and then uses the resulting object's methods to display the original map followed by an "overlay" that shows, for each map location, in which region it lies. Each region is identified by a positive integer; region numbers form a consecutive range of postive integers starting at one and ending with the number of distinct regions.

How to Solve

You will notice a stubbed method, computeRegions(), in the MapRegionFinder class. (It is a private method, and thus you can rename it if you like.) What it should do is to iterate over every location in the map, and, for each location L that has yet to be identified with a region ID, it should "explore" from that location by calling a recursive method. The result of that call should be that every location in the same region as L has been marked as being so. (Which is to say that all the elements of the instance variable regionID[][] corresponding to locations in that region have had the same value placed into them.)

The recursive method just mentioned, for which exploreRegion() is an appropriate name, could work as follows. First, either via parameters passed to it or values of instance variables, it would have to "know" which location it was "exploring from", which char value it was "hoping" to find there, and what region ID to assign to that location, if appropriate.

The base case of the method would apply when the location it was exploring from

In this case, the method should do nothing. Otherwise (the recursive case), it should mark the location by the approprate region ID and then recursively explore from each of its four neighbor locations (to the north, east, south, and west).


Additional/Optional

Enter input file name: map1.txt
The map:
  A  A  A  C  C  B  A  A
  A  C  C  C  B  B  A  C
  A  A  C  C  C  B  A  C
  C  B  B  B  B  A  A  C
  A  C  B  B  A  A  A  B
  A  B  B  C  C  C  C  B

Region IDs:
  1  1  1  2  2  3  4  4
  1  2  2  2  3  3  4  5
  1  1  2  2  2  3  4  5
  6  7  7  7  7  4  4  5
  8  9  7  7  4  4  4 10
  8  7  7 11 11 11 11 10

Region IDs (wraparound):
  1  1  1  2  2  3  1  1
  1  2  2  2  3  3  1  4
  1  1  2  2  2  3  1  4
  4  5  5  5  5  1  1  4
  1  6  5  5  1  1  1  7
  1  5  5  2  2  2  2  7
This section describes a task that is optional but which, if done well, will earn you a slightly better grade.

You will notice that the first constructor in the MapRegionFinder class has a second parameter, of type boolean. Its purpose is to tell the constructor whether or not the new object should interpret the map that is given to it as having a wraparound nature. In a wraparound map, corresponding locations in the "topmost" and "bottommost" rows are considered to be neighbors, and likewise corresponding elements in the "leftmost" and "rightmost" columns. Under this interpretation, every location on a map has exactly four neighbors. Of course, when a map is interpreted in a wraparound fashion, it is likely to have fewer distinct regions than one interpreted in the "normal" way.

To test this feature, you should "uncomment" the last section of code in the main() method of the MapRegionFinderApp. With these statments not commented out, the program would produce as output (when given the map1.txt file as input) that shown to the right.

Notice that, when the map is interprted in the wraparound mode, what had been regions 1, 4, and 8 become a single region, as do regions 2 and 11, as do regions 5 and 6, which explains why there were eleven regions when interpreting the map in the normal way but only seven when interpreting it in the wraparound fashion.