13
Com S 227 Spring 2017 Assignment 4 300 points Due Date:, Wednesday, April 26 11:59 pm (midnight) “Late” deadline (25% penalty): Thursday, April 27, 11:59 pm Figure 1: The Snowflake.txt map. General information This assignment is to be done on your own. See the Academic Dishonesty policy in the syllabus, http://www.cs.iastate.edu/~cs227/syllabus.html , for details. You will not be able to submit your work unless you have completed the Academic Dishonesty policy acknowledgement on the Homework page on Blackboard. Please do this right away. If you need help, see your instructor or one of the TAs. Lots of help is also available through the Piazza discussions. This is the final homework. Please start the assignment as soon as possible and get your questions answered right away!

Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Com S 227Spring 2017

Assignment 4300 points

Due Date:, Wednesday, April 26 11:59 pm (midnight)“Late” deadline (25% penalty): Thursday, April 27, 11:59 pm

Figure 1: The Snowflake.txt map.

General information

This assignment is to be done on your own. See the Academic Dishonesty policy in the syllabus, http://www.cs.iastate.edu/~cs227/syllabus.html , for details.

You will not be able to submit your work unless you have completed the Academic Dishonesty policy acknowledgement on the Homework page on Blackboard. Please do this right away.

If you need help, see your instructor or one of the TAs. Lots of help is also available through the Piazza discussions.

This is the final homework. Please start the assignment as soon as possible and get your questionsanswered right away!

Page 2: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Introduction

You will be writing the logic for a highly customizable “Snake” game. There are several versionsof “Snake”, all of which originate from the game Blockade written in 1976. Our version has a simple snake that chases the user's mouse along a uniform grid eating food. Each time it eats food, it grows in length until the player accidentally crashes into something. Our version also showcases the powers of polymorphism and it asks you to implement the following (approximate relative weights of each part are shown in parentheses):

• Several types of state.State:

◦ hw4.Wall (10%)

◦ hw4.Food (12%)

◦ hw4.DungeonessCrab (12%)

◦ hw4.SnakeHead (16%) - also implements the Snake interface

• One type of color.ColorGenerator:

◦ hw4.RainbowColorGenerator (12%)

• One type of graph.GraphMap:

◦ hw4.SquareMap (20%)

• A Recursive Path Finding Algorithm:

◦ hw4.CellUtil#updateMouseDistance() (18%)

*Note: normally code is separated into packages containing groups of related types. Here, we have separated the code you must do into the hw4 package. You should not expect this in your future jobs.

Figure 2: What you should see when you run main.

Figure 3: What you should see after implementing RainbowColorGenerator.

Page 3: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

But first, try to import and run your project (run main.Main#main(String[] args)). The first time you run your project it should look like Fig. 2. Each time you successfully implement one of the above features, you can immediately see a change when you run main. For example, when you implement RainbowColorGenerator, the map will change to Fig. 3. Some of the features depend on others as shown in the UML in Fig. 4. For example, if you want to see updateMouseDistance() in action, we suggest that you first implement SnakeHead, but in orderto implement SnakeHead first you need to implement Food. (The UML below shows where thecode would normally belong, instead of isolating the work in the hw4 package.)

Figure 4: Partial Class Diagram showing what needs to be implemented and in what order.

Navigating the sample code

In every software project it is a challenge to figure out what parts of an existing code base you really need to read and understand in order to perform the tasks assigned to you, and this project is fairly realistic in this respect. The discussion in the “Overview” section below attempts to give an overview of how the game works and to specifically mention the parts you'll need to reador interact with. But here is a summary of the parts of the existing code that you'll specifically need to be aware of:

• Be familiar with State, since you shall implement several subtypes of it. You probably do not need to read SnakeSegment, which is already implemented.

• Be familiar with Cell, since your SnakeHead implementation will have to use the Cell methods to find an adjacent cell, and to move to that cell.

Page 4: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

• Be familiar enough with GraphMap that you can write a subclass that extends it and implements the abstract methods. It's important to recognize that most of the initialization takes place in the already written initialize() method, and that you must create a Polygon for each cell and a neighbor list for each cell by examining the cell array. You may want to take a look at TriangleMap or HexagonMap to see how things are done, since SquareMap will have some similar features, though the math is much simpler.

• Be familiar with ColorGenerator, since you need to write a class that implements it.

• To run the game use main.Main. Optionally, you can pass in, as command-line arguments, a “-d” for debug mode and/or the name of a text file for a custom game. (See the end of this document if you are not sure how to use command-line arguments)

Overview

In theory, it should be possible for you to simply read the javadoc and the detailed requirements (in the next section) for each required class and implement it from there. In practice it will likelybe helpful to understand, at a high level, how the pieces fit together. That is the purpose of this section. The game is based on a 2d array of Cell objects. Each Cell contains a State (possibly null). State is an interface defined in the state package, and part of your task will be to implement several classes that implement State, including Wall, Food, DungeonessCrab, and SnakeHead. There is an additional implementation of State, SnakeSegment, that is already fully implemented for you.

The GUI code uses a clock that periodically calls update() on each Cell, which in turn calls handle() for each State within the Cell. This handle method may modify the internal state of theState, and it may also change the contents of the Cell or of a neighboring Cell.

One important example is the motion of the snake. What appears to be a snake on the screen is just a collection of adjacent cells containing the state SnakeSegment, plus one additional cell with state SnakeHead. When you implement handle() for SnakeHead, it will use some methods of Cell to find an adjacent Cell to move to, and it will move itself to that adjacent Cell, and then it will create a new SnakeSegment and make that the current Cell's state. It might seem like the snake would just get longer and longer, but each SnakeSegment gradually fades away so that the snake always appears to be the same number of cells (that is, until it finds Food). The speed at which the segments fade away is determined by the getLength() method that you'll implement in SnakeHead.

Page 5: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

A State may be designated as passable or not, which determines whether the snake can "pass" through a Cell with that state. Not surprisingly, the Wall class is not passable, but Food is passable, as is DungeonessCrab (which is a subclass of Food). Not surprisingly, it's Food that makes the snake longer, which you'll accomplish by increasing the value returned by getLength() in your implementation of SnakeHead whenever the SnakeHead passes through a Cell containing food. Note that the SnakeHead and SnakeSegment states are not passable; that is, the snake can't go through itself.

The abstract class GraphMap contains a 2d array of Cell objects. This abstract class implements all but four abstract methods. As part of your work on this project, you shall implement a new subclass of GraphMap, called SquareMap. The code also includes two existing concrete implementations of GraphMap, HexagonMap and TriangleMap. (These are similar in structure to SquareMap so you can look at them for inspiration, but the math is more complicated because of the angular shapes.)

The goal, as you can probably see, is to have a flexible framework that can support many different types of grid patterns. The key point is that each Cell object “knows” its adjacent or neighboring cells, and it “knows” its shape and position. It is up to the particular GraphMap subclass to correctly provide these values, which it does by implementing the first two abstract methods. One is createPolygon(), which creates a Polygon describing the vertices for the a cell,and createNeighbors(), which creates a list of the neighboring cells. (For your SquareMap, thelist would have two, three, or four elements, since only horizontal or vertical neighbors are included.) The vertex positions are described in pixel coordinates, that is, the actual dot locations on a graphical window, as measured from the upper left corner. There is a detailed example in the description of the requirements for SquareMap.

When you implement SquareMap you don't have to worry about creating the 2d array of Cell objects. That happens in the initialize() method, which is implemented in GraphMap. It is important to note that the abstract methods getPixelWidth() and getPixelHeight(), which you will need to implement, depend on the size of the 2d array, so you should assume they will not be called until after initialize() has been called.

There is just one simple user control in the game: moving the mouse near the snake's head. The snake's head will move toward the mouse. You are responsible for implementing the key method for this feature, the method calculateMouseDistance() in the CellUtil class. Basically what this method does is label the cells near the mouse cursor with their "distance" from the mouse, where "distance" is based on the number of cells that would be traveled to get from the cell to the mouse. There is a more detailed example of this algorithm later in this document. When you implement the algorithm, you can view the mouse distance for each cell by running the game using the “-d” debug mode option.

Page 6: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

The color of a cell is determined by an instance of ColorGenerator. One of your tasks is to write the class RainbowColorGenerator that implements this interface. The details are given later in this document.

As always, everything you write can and should be tested independently to make sure it corresponds to the specification. To actually run the game, you can run the class main.Main. Optionally, you can pass in “-d” for debug mode and/or the name of a text file as command-line arguments. The game uses this text file when initializing that describes the ColorGenerator to use, the type of GraphMap to use, the width in pixels to use for the cells, and the layout of the cells (this is similar to the String descriptors used for hw3). The cell layout includes initial states for some of the cells, represented as letters. Thus you'll notice that the State interface includes a method toChar() that returns the character that represents the state in a text descriptor.If you look at the main method, you'll notice that it does not directly create the ColorGenerator and GraphMap; rather, they class GraphMapFactory creates them, which takes the class names from the text file and uses some Java magic to construct the correct class based on the name.

What You Shall Implement

The following requirements will tell you exactly what you have to do. Things that the program already does will use the verb “will.” Things that you must implement will use the verb “shall.” Constants in the specification will be specified in main.Config. Read carefully...

• Wall: For full points, walls shall be white, they shall not move or do anything with their cell, and they shall not be passable. We shall represent walls in text files with a '#'.

• Food: Food shall have a timer (counter) that gets updated each time it handles a cell. When it reaches the MAX_FOOD_TIMER, food shall reset its timer to its initial value, 0. The color of food shall depend on the timer, using the timer as an index into FOOD_COLORS to slowly increase in color. Finally, snakes shall mow through food, so food shall be passable. We shall represent food with an 'F'.

• DungeonessCrab: A subtype of Food that shall walk! Whenever the dungeoness crab's timer resets, it shall look fora randomly open cell. If one exists, it shall move to that cell. We shall represent crabs with a 'D'.

• SnakeHead: Similar to food, the head of the snake shall have a timer with initial value 0. Upon reaching MAX_SNAKE_TIMER, the timer resets. SnakeHeads also keep track of the length of a snake

Page 7: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

(i.e., they inherit from Snake), which should initially be set to 4. When the timer resets, the snake shall try to find a random cell closer to the mouse, using the appropriate method of the Cell class. If no such cell exists, it will then try to find any random open cell. If no such second cell exists, then the player loses the game, and the program shall use a static method in Config toend the game. The score is the total length of the snake at that point.

If the snake successfully found a next cell, it shall move to that cell (using the moveState method of Cell), and create a new SnakeSegment inside its current cell. If the next cell contained Food, the snake shall increment its length. We shall represent SnakeHeads with an 'S'. You can use any color you wish for the snake head.

• RainbowColorGenerator: RainbowColorGenerator shall randomly return (with uniform probability) the following six colors. Specifically, as a percentage of the possible amount of Red, Green or Blue, each Color shall be constructed with the following:

R G BRed 25% 0% 0% Orange 25% 12.5% 0% Yellow 25% 25% 0% Green 0% 25% 0% Blue 0% 0% 25% Purple 25% 0% 25%

It is up to you to find and use the appropriate constructor in Color to achieve this.

• SquareMap: Every Cell (the colored squares) in the SquareMap has an column and row index into a 2D array holding the cells. In Fig. 5, the top left cell has the index (column, row) = (0, 0), and its neighbor to the right has (1, 0), and so on. The neighbors for a cell at index (column, row) shall constitute the following if they're within the map:

1. The cell at index (col-1, row) 2. The cell at index (col+1, row) 3. The cell at index (col, row-1) 4. The cell at index (col, row+1)

Depending on the cell's index in the 2D array, it can have as few as two neighbors and as many as four. (Note: here we're describing cell indices using the pairs (horizontal, vertical) as in mathematical coordinates. Remember when you access elements of the 2D array, you have to reverse them, since for a 2D array the row index is first.)

Page 8: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Figure 5: Schematic for the SquareGraphMap

In addition to its column and row index, each cell is associated with a location in pixels within a graphical window. Pixels are measured from the upper left corner. The GraphMap class includes an attribute distance representing the size in pixels of each Cell. When creating Polygons for each cell, the coordinates in pixels shall follow the scheme shown in Fig. 5. There shall be an empty border around the cells with width of distance/2. The createPolygon method then shall return a square with width distance. The orange dot in Fig. 5 represents the point (0, 0) in pixels. For any point in pixels, the selectClosetIndex method shall return the cell's column and row if the given (x, y) is within its square. For example, focus on the pink dot in Fig. 5:

Let's say that distance equals 10, and let's say that the pink dot belongs to the point (19, 21) in pixels. Then the closest column and row would be (1, 1). A point on the boundary between cells is assumed to belong to the square to the right and/or below.

Finally, the width of the GraphMap in pixels shall equal the sum of the widths of the polygons we need to draw in a row, plus the empty border on either side of the row. The height shall work similarly.

• CellUtil.calculateMouseDistances()

Each update of GraphMap will call the Cell method recalculateMouseDistances for the cell that has the mouse hovering over it as shown in Figure 6 (the pink cell). This method immediately calls CellUtil.calculateMouseDistances(), which you shall implement. As you cansee in the recalculateMouseDistances code,, the initial calling cell's mouseDistance will equal the MAX_MOUSE_DISTANCE. Each of its neighbors shall set their mouseDistance to the calling cell's mouseDistance minus 1. Then their neighbors shall set their distances to one less than that, and so on until all neighboring cells have a mouseDistance either higher than the calling cell's or the calling cell's mouseDistance is 1. The mouseDistance of impassable states shall never be updated; however, passable states and empty states shall update their mouseDistance using this method. It may help to implement this method using recursion.

Page 9: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

How the mouse distance is used

Fig.s 6-8 shows how the Snake will use the mouseDistance numbers to find the mouse. In Fig. 6 the cell highlighted in yellow is the head of the snake. It looks at its passable neighbors, and randomly picks one of the ones with the highest value. It then moves to this state (Fig. 7), and during the next frame the mouseDistances will be updated. It will continue searching for higher mouseDistances until it reaches the the cell with the mouse over it. Fig. 8 shows one possible path.

Figure 6: How updateMouse distance affects each cell.

Figure 7: Moving the snake closer to the mouse.

Figure 8: A possible path for themouse.

Figure 9: The Arena.txt map. Figure 10: The Default.txt map.

Testing and the SpecChecker

As always, you should try to work incrementally and write simple tests for your code as you develop it. You are given 3 different maps that you can play for fun as shown in Fig.s 1, 9 and 10. Pass the file name in as a parameter to main(String[] args) to load that map. Optionally you can also pass in the “-d” option for debugging the updateMouseDistance() method.

Page 10: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Do not rely solely on the GUI code for testing! Trying to test your code using a GUI is unreliable. When we grade your work we are NOT going to run the GUI, we are going to verify that each method works according to its specification.

Since test code that you write is not a required part of this assignment and does not need to be turned in, you are welcome to post your test code on Piazza for others to check, use and discuss.

We will not provide a comprehensive SpecChecker. At this point in the course, you should not need one. Thus, you must read the specification carefully, otherwise you will lose points. You will be provided a SpecChecker to verify class and method names, and for turning in your assignments.

Style and documentation

NOTE: When a class implements or overrides a method that is already documented in the supertype (interface or class) you normally do not need to provide additional Javadoc,unless you are significantly changing the behavior from the description in the supertype. You should include the @Override annotation to make it clear that the method was specified in the supertype.

Roughly 15% of the points will be for documentation and code style. Here are some general requirements and guidelines:

• Use instance variables only for the “permanent” state of the object, use local variables fortemporary calculations within methods.

o You will lose points for having lots of unnecessary instance variableso All instance variables should be private.

• Accessor methods should not modify instance variables.

• Each class, method, constructor and instance variable, whether public or private, must have a meaningful and complete Javadoc comment. Class javadoc must include the @author tag, and method javadoc must include @param and @return tags as appropriate.

o Try to state what each method does in your own words, but there is no rule against copying and pasting the descriptions from this document.

• All variable names must be meaningful (i.e., named for the value they store).

Page 11: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

• Your code should not be producing additional console output. You may add println statements when debugging, but you need to remove them before submitting the code.

• Internal (//-style) comments are normally used inside of method bodies to explain how something works, while the Javadoc comments explain what a method does. (A good rule of thumb is: if you had to think for a few minutes to figure out how something works, you should probably include a comment explaining how it works.)

o Internal comments always precede the code they describe and are indented to the same level.

• Use a consistent style for indentation and formatting.

o Note that you can set up Eclipse with the formatting style you prefer and then use Ctrl-Shift-F to format your code. To play with the formatting preferences, go to Window->Preferences->Java->Code Style->Formatter and click the New button to create your own “profile” for formatting.

If you have questions

For questions, please see the Piazza Q & A pages and click on the folder assignment4. If you don’t find your question answered, then create a new post with your question. Try to state the question or topic clearly in the title of your post, and attach the tag assignment4. But remember, do not post any source code for the classes that are to be turned in. It is fine to post source code for general Java examples that are not being turned in, and for this assignment you are welcome to post and discuss test code. (In the Piazza editor, use the button labeled “tt” to have Java code formatted the way you typed it.)

If you have a question that absolutely cannot be asked without showing part of your source code,make the post “private” so that only the instructors and TAs can see it. Be sure you have stated aspecific question; vague requests of the form “read all my code and tell me what’s wrong with it”will generally be ignored.

Of course, the instructors and TAs are always available to help you. See the Office Hours section of the syllabus to find a time that is convenient for you. We do our best to answer every question carefully, short of actually writing your code for you, but it would be unfair for the staffto fully review your assignment in detail before it is turned in.

Any posts from the instructors on Piazza that are labeled “Official Clarification” are considered to be part of the spec, and you may lose points if you ignore them. Such posts will always be placed in the Announcements section of the course page in addition to the Q&A page. (We promise that no official clarifications will be posted within 24 hours of the due date.)

Page 12: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Suggestions for getting started

As always, start with simple usage examples or test cases for each method you write, so that you know what you want the code to do before you start to write it. None of the code is acutally verycomplex. Much of your work will be to read and interpret the specification and to learn to find your way around the sample code.

What to turn in

Note: You will need to complete the "Academic Dishonesty policy questionnaire," found onthe Homework page on Blackboard, before the submission link will be visible to you.

Please submit, on Blackboard, the zip file that is created by the SpecChecker. The file will be named SUBMIT_THIS_hw4.zip. and it will be located in the directory you selected when you ran the SpecChecker. It should contain one directory, hw4, which in turn contains the seven files youare to implement.

Please LOOK at the zip file you upload and make sure it is the right one!

Submit the zip file to Blackboard using the homework 4 submission link and verify that your submission was successful by checking your submission history page. If you are not sure how to do this, see the document "Assignment Submission HOWTO" which can be found in the Piazza pinned messages under “Syllabus, office hours, useful links.”

We recommend that you submit the zip file as created by the specchecker. If necessary for some reason, you can create a zip file yourself. The zip file must contain the directory hw4, which in turn should containthe seven required files. Make sure all files have the extension .java, NOT .class. You can accomplish this easily by zipping up the src directory of your project. The file must be a zip file, so be sure you are using the Windows or Mac zip utility, and not a third-party installation of WinRAR, 7-zip, or Winzip.

Appendix: Using command-line arguments

To run the game in the “debug” mode that shows the mouse distances, or to run using a text file with a different grid, you'll need to pass command-line arguments to the Java runtime. If you areusing Eclipse, you can do the following: right-click on the Main class, go to Run As and select Run Configurations. On the Arguments tab, enter the text in the Program arguments text area. For example, if you want to use the sample file Arena.txt and run in debug mode, you'd enter the text shown in the screenshot below. You can then click Run. To run with the same arguments later, just go back the same run configuration.

Page 13: Com S 227 Spring 2017 Assignment 4 300 pointsweb.cs.iastate.edu/~smkautz/cs227s17/homework/hw4/hw4.pdf(The UML below shows where the code would normally belong, instead of isolating

Note that using the menu at left you can create and delete run configurations. (Note there are two for Main in this person's workspace, possibly using different command-line arguments. When you run your code, be sure you know which configuration you're actually choosing!)

Of course, you can also enter command-line arguments on the command line. If you open a command shell or terminal and navigate to your project directory, you can enter the command

java -cp bin main.Main -d Arena.txt

to run the game using Arena.txt and the “-d” option. The option “-cp bin” tells the runtime to look for the compiled class files beneath the “bin” directory, which is where Eclipse puts them by default.

If you run with the -d option, you may find the cells are too small for the numbers. This is easy to fix. Just edit the second line of the text file, which includes the cell size in pixels. For example, the first two lines of Arena.txt are

color.RandomGreenGeneratorhw4.SquareMap 15

so you can double the size of each cell by changing it to

color.RandomGreenGeneratorhw4.SquareMap 30