CSE 142 - Summer 2003 - Homework 4 (Pairs Programming Project #1) Assigned: Monday, July 14, 2003 Written Assignment Due: MONDAY, July 21, 2003 @ 9:30pm Pairs Programming Assignment Due: MONDAY, July 21, 2003 @ 9:30pm Individual Programming Writeup Due: WEDNESDAY, July 23, 2003 @ 9:30pm A link to the turn-in pages will appear on the course calendar webpage. ------------------ Written Assignment ------------------ To gain full credit on each question, your answer must have no significant flaws, must be clear to the reader, and must be complete (but remember that complete does not mean verbose -- be concise and to the point). As always, you should record your answers to the questions in a plain-text file (for example, "answers.txt") and then submit that text file along with the rest of your electronic turn-in. Do not collaborate with (i.e. copy from) your programming partner when writing your answers to the Written portion of the Assignment. These questions are meant to make you more familiar with a few basic algorithms that you will find yourself using over and over in programming projects both in this class and afterwards. Making some headway into these questions first will probably help you a fair amount with this week's Programming Assignment. However, the Programming Assignment will take quite some time to get working, so you need to start it right away. 1. Loops. In (a), convert the 'for' loop into a 'while' loop. In (b), do the opposite. You might want to use DrJava to make sure your translation is legal and generates the correct output. In all written coding exercises (and exams) from this point on, you will be expected to write down Java code that would work if we ran it. (Minor syntax errors may be forgiven from time to time.) a) for (int i=0, j=2; (i < 10) && (j < 100) ; i++, j*=2) { System.out.println(i + " , " + j); } b) int divisor = 27; int number = 100; while (number % divisor != 4) { System.out.println(number--); } 2. More loops. When programming, we are often asked to write a method which will receive data from an outside source not under our control. In such cases, we have to rely on the outside source's specification (documentation) to tell us, for example, when there is no more data. Let's say we want to model a Player at a poker table where after each game is over, a new person becomes the Dealer and decides what variant of poker to play next. The Dealer does not announce ahead of time how many cards she will be dealing; instead, the specification for her dealACard() method says: public Card dealACard(): returns either a Card object or null when there are no more cards to be dealt Assuming our Player class already has: - a variable 'myDealer', referring to an existing Dealer object - a method called 'addToDeck(Card card)' that adds Card objects to its deck write a while loop that gets cards from the Dealer one at a time and puts them into the Player's deck until the Dealer gives out no more cards. 3. Imagine that you run a school for wizards, and you store student data by maintaining an object of type Student for each student. The definition for this class is as follows: public class Student { String name; // name of student int year; // what year the student is in (1, 2, ...) boolean witch; // true = witch; false = wizard int detentions; // number of detentions received since year 1 /* ... constructors and methods here ... */ } Write a method for this class called calculateTuition() that will return the yearly tuition (in units of Galleons) for a student. The method used to calculate the tuition is as follows: - Start with 100 Galleons if the student is a 1st or 2nd year, 120 G if 3rd through 5th year, or 140 G otherwise. - If the student is a wizard, add 0.5 G for each detention the student has received since his first year. If the student is a witch, add 0.4 G for each of her detentions. Make sure to add appropriate Javadoc-style comments before your method and (as mentioned above) to check your code for syntax errors. 4. a) Write a method named "factorial" that takes an integer 'n' as a parameter and returns the (integer) factorial of n -- that is, the value n * (n-1) * (n-2) * ... * 3 * 2 * 1 Again, add the proper Javadoc-style comments. Note: if you plan to test your method in DrJava, don't bother trying values of 'n' much bigger than 10; the factorial function quickly produces numbers that are too large to be stored in an integer variable. b) Now write a method named "factorialTable" that takes an integer 'x' as a parameter and prints out a two-column table of all the numbers from 1 to x, followed by their factorials. You should use your factorial() method from part (a) inside your factorialTable() method -- that is, you should make a call to factorial() rather than rewriting the code from part (a) inside your new method. As an example of the output, factorialTable(6) would print out: 1 1 2 2 3 6 4 24 5 120 6 720 Add Javadoc comments as appropriate. ---------------------- Programming Assignment ---------------------- Turn in Car.java when you have completed this task. You should not have to modify any of the other source files. Your partner should submit the same Car.java file. Then, each of you should submit a separate individual project report as outlined on the "Project Report Guidelines" web page, which is linked from the course calendar page. The deadlines for these turn-ins are listed at the top of this file. This project includes a more dynamic use of the UWCSE graphics and animation libraries and gives you more practice implementing a class according to a given specification. - Objective: Fill in the implementations for the methods in Car.java. 1. If you haven't done so already, download the cse142-hw4.zip file and unzip it. The project skeleton is in directory hw4. 2. Before you can compile the code that is provided, you'll need to at least provide dummy return values for all of the methods in Car.java that require return values. 3. This project consists of three classes: Director, Road, and Car. The Director's job is to create a small network of Road objects and a series of Cars that will drive along these Roads. See the example pictures linked from the Calendar web page. The Director places each Car on a Road and animates the Car by calling its advance() method every few milliseconds (just like it did with the Sun object in Homework 3). The Director stops animating each Car when it has reached the end of its Road. The Director also fulfills one more special function, discussed in #9 below. Some aspects of the Director class (such as ArrayLists) have not yet been taught to you, but the above information is all you should need to know to complete your assignment. You are certainly welcome to read through Director.java to see how everything works. Roads and Cars both implement the Prop interface -- just like the Horizon, Sun, and Tree classes in Homework 3. Again, we haven't taught you about interfaces yet, but what this means is that Roads and Cars are created, added to a GWindow, and removed from their GWindow in exactly the same way as the objects you dealt with in the last assignment. You should think of Roads as rectangles with an orientation (East-West or North-South). Read the Road documentation to see what queries a Road object can answer for you. Notice that even though we've told you that Roads are rectangles, it does NOT mean that they necessarily use Rectangle objects. It just so happens that they do ... but you don't have to know that to complete the assignment. Since you're implementing the Car object, it *is* important for you to know that Cars use Rectangles. They also implement a number of other responsibilities. Follow along in Car.java or in the Javadoc documentation we have provided for the Car class (in the 'doc' directory) as you read the rest of the assignment ... 4. There is one constructor for the Car class. The constructor takes seven parameters. /** * Construct the Rectangle avatar for the Car given the Road it is on * and the direction of travel. * @param director the Director object that will need to be queried by * the Car to determine intersections with other roads * @param road the Road on which the car is to be traveling initially * @param direction the initial direction of the car's travel: N/E/S/W * @param width width of the car's Rectangle * @param height height of the car's Rectangle * @param speed number of pixels to move the Car per frame * @param color color of the Car */ public Car (Director director, Road road, char direction, int width, int height, int speed, Color color) { Implement the following behaviors in the constructor: - Create a Rectangle body using the values of the width, height, and color parameters. Store a reference to this new Rectangle in an instance variable called 'body' (or whatever you want to call it). - Determine where in the scene to place the Rectangle by asking the Road object you're given about its coordinates. Place the Car at the very beginning of the Road and in the correct lane. Notice that which end is the "beginning" of the Road and which lane is the "correct" side of the Road both depend on the direction in which the Car is supposed to travel. You don't want your Car traveling in the wrong lane! - Finally, center your Car in its lane. To do this you'll need to do a bit of math ... drawing a picture and labeling it with important distances such as the x, y, height, and width of the Road and the height and width of the Car should help a great deal. Be sure to think about how north-south Roads differ from east-west Roads. You can assume that the Director will only place east- and west-bound Cars on east-west Roads, and similarly for north-south Roads. - Once you have created and stored your new Rectangle body, also store references to the Director and Road parameters in instance variables (say, "masterDirector" and "currentRoad"), as you'll need to access them later. Do the same for the direction and speed parameters. 5. Just as in Homework 3, Props need to remember the GWindow that they're in so that they can remove themselves from the scene when instructed to do so. So, implement the addTo(GWindow) and removeFromWindow() methods accordingly. 6. Every few hundred milliseconds (i.e., every "frame") the Director will call the Car's advance() method in order to get the Car to move. You should therefore implement the advance() method to make the Car move 'speed' pixels in the correct direction. That way it will be moving precisely 'speed' pixels per frame. 7. Implement the getCurrentRoad() method to return the Road that the Car is currently traveling on. 8. Implement the method carIsOnRoad(Road) to return true if the Car is on that Road. A Car is considered to be on a Road when its upper-left corner is within the boundaries of the Road. The Director stops animating a particular Car only when carIsOnRoad() returns false, so if this method isn't working properly, your animation might go on forever, or it might never start! 9. The final function of the Car is to speed up when it hits an intersection of two Roads. To make this work, you'll implement two new methods: "getCrossRoad" and "speedUpIfInNewIntersection". The second one will call the first one (just like in problem #4b in the Written Assignment), and the first one will call "carIsOnRoad". Writing methods that use other methods you've written is an important concept (called "modularity") in designing complex systems. By separating a process into simpler components, it will be easier for you to figure out what you need to do in each one and to find errors in your code. a) Method "getCrossRoad" will check all the Roads in the scene -- other than the one the Car is traveling on -- to see if the Car happens to be on one of those Roads. It will use your "carIsOnRoad" method to check each Road. If the Car is on any of those other Roads, it will return that other Road object. If not, it will return null. - Since only the Director knows about all the Roads in the scene, you'll have to ask it to give you each of the Roads in succession so you can test them all. This will be just like asking the Dealer for Cards in Problem #2 in the Written Assignment. The way to ask the Director for the next Road is through the Director's "getRoad(int number)" method. - Here's how it works: "getRoad" returns the Road object that corresponds to the number that you give it, or it returns null if there is no Road with that number. In the Director's list of Roads, each Road has a number, starting with 0. If there are 5 roads, for example, they will be numbered 0, 1, 2, 3, and 4. Asking the Director to getCrossRoad(5) will return null instead of a valid Road object. - So, all you have to do to check all the Roads in the scene is write a loop that keeps asking the Director for higher and higher Road numbers until the Director returns null instead of a valid Road object. Once that happens, there are no more Roads to check. (DO NOT "cheat" by using the fact that you can read the Director.java file to find out how many Roads there are; we might change the Director.java file when we test out your program!) - Each time you get a Road, check if the Car is on it (but skip the Car's "currentRoad", since you'll always be on that.) If you find a Road that you are on, you can "return" it right away, which will (of course) terminate the loop early and return the flow of control to the calling method. That way, if the program execution ever reaches the end of your loop, you (obviously) haven't returned anything yet. Which means the Car must not have been in intersections with any of the Roads, right? Which means you can then return null. Easy! - This might sound complicated, but (a) we've spelled everything out for you, and (b) it only takes 10 lines of code. b) Method "speedUpIfInNewIntersection" asks your "getCrossRoad" method if the Car is in any intersection. If so, it doubles the Car's speed, but only if the Road the Car is crossing is NOT the same as the Road it was crossing in the previous frame. This means you'll need another instance variable (say, "roadLastIntersected" or something) to keep track of the last Road the Car intersected. If "getCrossRoad" reports null, then you should set roadLastIntersected to null to indicate that the last time it checked, the Car wasn't in an intersection. The reason not to double the Car's speed if it's still in the same intersection that it was the last time it checked, is that some intersections may be wider (or taller) than your Car travels in one frame. So, there may be several frames in a row during which your Car is in some intersection, but we only want it to speed up once for that intersection. 10. That's it! Once it's working correctly you should see one Car at a time traveling along each Road in the scene, in each of the four directions. The will have different colors, sizes, and speeds, and they will double their speed when they pass through intersections. HINTS: - With lots of comments and spacing to make things look nice, our Car.java file ended up being 179 lines long. Yours may be shorter or longer, but this is a big chunk of code to write. That's why you have a partner and a full week, so get going! - It can be REALLY helpful to use System.out.println() calls to print out the values of variables (or the values that method calls are returning) in places where you think your code is doing something wrong. For example, if a loop never seems to end, you might want to print out the values of the variables involved in the termination condition each time through the loop. This might help you discover what's going wrong. Same thing for math -- a small typo might put your Car next to its Road instead of on it! It might help to print out the values you are calculating so you can find the error. Such println() statements are called "scaffolding code", and we would appreciate your commenting them out or removing them before you turn in your final code. - The best way of going about this assignment is probably to tackle each requirement in order and then test it out after you've done each one to make sure everything you've done so far is working as you expect. Write empty methods or, if a return value is required, methods that return dummy values for the methods that you haven't implemented yet, just so you can compile the code and run it. - Plan out your methods on paper or a whiteboard first! Conceptual diagrams (doodles) of your objects can help a lot.