Lab: Plotting Pictures in a 2D Data Structure

Alyce Brady
Kalamazoo College

 


Introduction

In this lab you will implement methods for drawing in a two-dimensional grid by changing the colors of the cells in the grid.  This will give you practice with developing algorithms for two-dimensional data structures.

The two-dimensional data structure used in this lab is represented by a BoundedEnv (bounded environment) object made up of rows and columns. A BoundedEnv object models a bounded rectangular grid that contains objects at various grid locations. Each cell contains zero or one objects.  In this program, cells that are not empty will contain color blocks (objects of the ColorBlock class).

  0 1 2 3 4 5 6 7 8
0
     
obj1
         
 
obj2
             
   
obj3
 
obj4
       
               
obj5
1
2
3

We refer to locations in the grid by their row and column numbers in parentheses, such as location (2, 7). Row and column numbers start at 0 rather than 1, so location (0, 0) refers to the first row and first column. Object obj1 in the grid shown above is in the first row and fourth column, or at location (0, 3). Object obj5 is at location (3, 8). (This is similar to the way Java array and ArrayList indices are numbered.)

In this lab you will define methods for drawing in the two-dimensional grid by putting color blocks in the cells of the grid.



Getting Started

In this exercise you will be experimenting with the Environment Plotter program to see how it works.

Exercise Set 1

  1. Download the zip file that contains the starting code files for the Environment Plotter program (EnvPlotter.zip) and unzip it. When you unzip the file and look in the Code folder, you will see files representing the following classes.
    • EnvPlotterApp (contains the main method)
    • EnvPlotter (the class you will be enhancing)
    • EnvPlotterGUI (a class that implements the program's graphical user interface; you are not expected to read or understand this class)
     
    There are also three jar files (mbsbb.jar, mbsenv.jar, and genericEnv.jar) that contain additional classes the program needs in order to run. These include:
    • BoundedEnv (class that represents the two-dimensional grid)
    • Location (class that represents the row and column positions of a location in the grid)
    • ColorBlock (class whose objects are used to draw in the grid)

    You can find documentation for all of these classes in the Documentation folder. (Note: All of the classes are covered by the GNU General Public License, including the BoundedEnv and Location classes which come from the AP® Marine Biology Simulation case study.)

  2. Compile and run the program. As the program starts up you will be asked for the dimensions (number of rows and columns) of the grid in which you will be drawing. For now you can go with the default values, since your purpose for this exercise is just to experiment with the user interface. Once you have chosen the environment dimensions, click on the "rowMajorFill" drawing button; you should see color blocks filling the locations of the grid in row-major (top-down, left-to-right) order. Experiment with the "Adjust Speed" slider while the program is drawing color blocks.

  3. Experiment with the program to discover what the "Create New Environment" and "Clear" buttons and the "Background Color" and "Drawing Color" menus do. You may need to move the Environment Plotter window aside so that you can see the console window in order to see messages the program sometimes prints out. What happens if you press the "rowMajorFill" button twice in a row?  Does the behavior appear different if you change the drawing color between "rowMajorFill" button presses?  What could explain this behavior?



Studying the Algorithms

The starting point of the Environment Plotter application is the EnvPlotterApp class, which contains the main method. If you look over the class, you will see that it does remarkably little. It creates two constants that define the size of the window containing the graphical user interface and two more that define the extreme values for the speed adjustment slider. The class's main method creates the graphical user interface and makes it visible on the screen. 

Exercise Set 2

  1. Experiment with the constants defined at the top of the EnvPlotterApp class to see how changing them affects the application.

We will not look at the EnvPlotterGUI class, which includes some quite advanced features of Java. Instead, let's look at the EnvPlotter class. The graphical user interface calls methods of this class whenever a user constructs a new environment, presses one of the drawing buttons, or presses the clear button.

Exercise Set 3

  1. What instance variables does an EnvPlotter object have? How does it use them?

  2. What does the constructor do?

  3. What does the rowMajorFill method do? How do the statements in the rowMajorFill method ensure that the order in which the application colors cells will be row-major order? (Row-major order means stepping through a two-dimensional data structure row-by-row.  It first visits all the locations in row 0, then all the locations in row 1, and so on.  Within each row, it steps through the locations left-to-right.)

  4. What do the placeColorBlock and ensureEmpty methods do? Research the class documentation for the BoundedEnv class to verify that you understand what is happening in the placeColorBlock and ensureEmpty methods. How does a ColorBlock object get added to an environment? What happens if a drawing method tries to place a color block in a location that already has a color block?
  5. Complete the implementation of the clearEnv method, using the rowMajorFill method as a guide. Test your code by filling the environment and then clearing it. Make sure to test it with several different environments of different sizes, in both empty and filled environments, and using different colors.  You should not see it clear block-by-block — why not?

 



Adding New Drawing Methods

Now it's time to write some drawing methods of your own.

Exercise Set 4

  1. Complete the colMajorFill method, using rowMajorFill as a guide. Test your class by running the program in several environments of various sizes and watching the traversal. Are the cells filled in left-to-right, going down each column?  (A traversal through a two-dimensional data structure is an algorithm that steps through all the elements of the data structure, visiting each element exactly once.  A traversal through an environment steps through all the locations in the environment.  Column-major order means stepping through a two-dimensional data structure column-by-column.  It first visits all the locations in column 0 top-to-bottom, then all the locations in column 1, and so on.)

  2. Write a reverseRowMajorFill method, using rowMajorFill as a guide. This algorithm should fill in cells bottom-up, going left-to-right across each row. In other words, the row order is reversed, but the column order is not. If your new method has the same number and type of parameter(s) and the same return type as the rowMajorFill method, then something magical will happen when you run the program —  a new button will appear as part of the graphical user interface!  Actually, it's not magic, it's some advanced Java code in the EnvPlotterGUI class. Click on the button to test your new method.

  3. Write a reverseColMajorFill method, using colMajorFill as a guide. This algorithm should fill in cells right-to-left, going up each column from the bottom. In other words, both the row and column orders should be the reverse of colMajorFill. Test your new method.

  4. Write a diagonal method. This algorithm should color cells along the diagonal from the upper-left corner towards the lower-right corner. It will actually end up in the lower-right corner only if the environment is square.  If it is not square, the algorithm steps down and to the right until it comes to the last column or the last row, depending on whether the environment is higher than it is wide or wider than it is high. The diagrams below show the behavior for a 5 x 5 environment, a 3 x 5 environment, a 5 x 3 environment, and a 1 x 1 environment.
    Before you attempt to write the code, list the locations that you want to fill. When you're done with the implementation, test your new method in various sized environments, such as the ones above.

  5. Write a triangle method. This algorithm should fill in all the cells on and below the diagonal you produced in the preceding exercise. (It will form a true triangle only if there are at least as many columns in the environment as there are rows.)  Before you attempt to write the code, list the locations that you want to fill. When you're done with the implementation, test your new class. The diagrams below show the behavior for a 5 x 5 environment, a 3 x 5 environment, a 5 x 3 environment, and a 1 x 1 environment.

  6. Write a second diagonal method similar to the first one, but going from the upper-right corner towards the lower-left corner.  (Again, whether it actually reaches the lower-left corner depends on whether or not the environment is square.)  Give your method an appropriate name and test it in a variety of environments.
  7. Write a method that draws an 'X' in the environment, giving it an appropriate name. Reuse existing methods as appropriate.  When you're done, test your new method. The diagrams below show the behavior for a 5 x 5 environment, a 4 x 5 environment, a 5 x 4 environment, and a 1 x 1 environment.

    Hint: The best implementation of this method consists of two statements, with no loops.

  8. Write a method that draws a border around the environment's perimeter. Before you attempt to write the code, list the locations that you want color in order to find a pattern. When you're done with the implementation, test your new method.  The diagrams below show the behavior for a 5 x 5 environment, a 2 x 5 environment, a 3 x 1 environment, and a 1 x 1 environment.

  9. Write three (or more) new methods that you could use to draw a picture.  For example, you could create a method that draws the walls of a house, a method that draws a roof, and a method that draws four windows.  A user could then use your methods to draw black walls, a red roof, and blue windows.  Your picture should draw in environments of different sizes, scaling up or down as necessary.  You may, however, specify a minimum size if you want; for example, this picture will only draw correctly in an environment that has at least 20 rows and at least 20 columns.  You may also want to specify that the environment has to be square, or that the number of columns must be twice as many as the number of rows.  Whatever your constraints are, be sure to document them for the appropriate methods in the EnvPlotter class!