CSE 142 - Summer 2003 - Homework 6 (Pairs Programming Project #3) Assigned: Monday, August 4, 2003 Written Assignment Due: MONDAY, August 11, 2003 @ 9:30pm Pairs Programming Assignment Due: MONDAY, August 11, 2003 @ 9:30pm Individual Programming Writeup Due: TUESDAY, August 12, 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. 1. Write a method called newReverseArray that takes as a parameter an array of doubles and returns a *new* array containing the same doubles in reverse order. For example, after executing double[] reverseCopy = newReverseArray(originalCopy); with originalCopy holding the values { 2.3, 4.6, 1.7, 8.3 }, reverseCopy would point to a new array containing the values { 8.3, 1.7, 4.6, 2.3 }. The originalCopy array would still exist. 2. Write a method called reverseThisArray that takes as a parameter an array of doubles and returns the *same* array containing the original numbers in reverse order. For example, after executing reverseThisArray(originalCopy); the variable originalCopy would refer to the same array (the same chunk of memory) as it did before the method call, but the values in the array would be reversed. ---------------------- Programming Assignment ---------------------- Turn in Car.java, Road.java, and Building.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 source files as you. 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 is our final project working with our City and its network of Roads and TrafficLights. The City has been upgraded to include Buildings, which will serve as Destinations for our Cars. The Roads have also been changed to maintain sorted lists of the Cars traveling along them, although it will be your job to complete this implementation. Cars will have to be upgraded to (a) follow instructions from the Director on how to reach their Destinations and (b) avoid hitting stopped Cars in front of them. Finally, it's also your job to program the (relatively simple) Building class from scratch. This assignment is even more work than HW4, so get started now! - Objective: Adjust the Car's tick() method so that the Car can follow the Director's instructions, make decisions about turning onto new Roads, announce its arrival at its Destination, stop behind stopped Cars, and speed up again when the coast is clear. - Objective: Adjust the Road class to add Cars (in the proper order) to, and remove Cars from, its sorted lists of Cars currently traveling on it. - Objective: Create the Building class from scratch to implement the Destination interface. 1. If you haven't done so already, download the cse142-hw6.zip file and unzip it. The ZIP file will be available from the Calendar page shortly after the deadline for HW5 turnins has passed. The project skeleton is in directory hw6. 2. The code will *not* compile or execute as is. See #7 below for a brief discussion of how to ignore certain components of the system so that you can test out pieces. To make the system fully operational, you must implement all the behaviors described below. 3. Here are the important changes since Homework 5, listed class by class. - Car: Instead of being created with a Road, direction, and speed, the Director will now be sending an ArrayList of instructions to each Car, and a Destination object that the Car is trying to reach. Each instruction consists of two elements -- a Road name (String) and a direction (a char inside a Character). Remember that we need to use a java.lang.Character instead of a plain char because ArrayLists can't hold atomic data types (like int, double, char). A new Character can be created from a literal char like so: Character myCharacter = new Character('W'); To retrieve the char value from a Character, you can call the Character's public "charValue()" method, like so: char direction = myCharacter.charValue(); So, the instruction list passed to the Car looks something like < String("Pike St"), Character('E'), String("7th Ave"), Character('N'), String("Pine St"), Character('W'), ... > This means that the Car should start on Pike St going east, turn north onto 7th Ave, turn west onto Pine St, etc. Now, the Car constructor has already been written for you and places the Car on the correct street going the correct direction. It has been written in such a way as to hint at a strategy for how you should access the elements of the list in general, and how to keep track of what instruction you are on. The Cars in HW6 now also have the ability to turn onto new Roads in new directions. This turn() method has been written for you. Much tinkering has gone into trying to avoid collisions during and immediately after turns, but if there is a random traffic backup on some Road, collisions might occur. If this happens every once in a while, don't worry; just restart the program. Finally, Cars now have a Destination field that stores the Destination that the Director has assigned to this Car. Now, if the Destination is null, then the Car has no particular place that it's trying to get to, and it should simply wander around according to its instructions until it leaves the GWindow. Those Cars that have a non-null Destination must begin seeking it as soon as they complete the last instruction in their instruction list. Hopefully the Director is not insane and will give Cars instructions that actually lead to their Destinations. - Road: Each Road now has a String name (and displays its name as a TextShape in the GWindow). Also, each Road now maintains two *sorted* ArrayLists of Car objects ... one in the positive direction (positiveCars) and one in the negative direction (negativeCars). As you already know, for an east-west Road, the positive direction is east. For a north-south Road, the positive direction is south. Both lists will be sorted from low x/y-position to high x/y-position. So, for an east-west Road, both the positive and negative Car lists will be sorted based on x-position, from west to east. For a north-south Road, the two lists will be sorted based on y-position, from north to south. So, for example, if there are 3 cars traveling East and 2 cars traveling West on Union St: | | | ------------------------------------| | |-------------- ___ ____ | <--- |___| <--- |____| | E D | -- -- -- -- -- -- -- -- -- -- --| -- -- -- -- -- ____ ___ | _____ |____| ---> |___| ---> | |_____| ---> A B | C ------------------------------------| | |--------------- | | | Car A will be in slot 0 of positiveCars, Car B will be in slot 1, and Car C will be in slot 2. Meanwhile, Car E will be in slot 0 or negativeCars and Car D will be in slot 1 of negativeCars. Notice, then, that there is a difference between the two lists -- the positiveCars list is sorted from "back to front", while the negativeCars list is sorted from "front to back". This same rule applies for north-south streets too. The important thing is that both are sorted from "less positive" coordinates to "more positive" coordinates. One of your responsibilities will be to maintain these lists in their sorted order as new Cars are created on Roads, and as already existing Cars leave one Road and turn onto another. These Road lists are also crucial for one of your other tasks -- to make sure that each Car avoids hitting stopped Cars in front of it. - Director: The Director object is once again in charge of the entire Scene. After creating everything, the Director loops for a certain amount of time and tells everything in the Scene to tick once per loop. Cars will be created at random intervals with random instructions. Most of the Cars will be Destination- and instruction-less ... they'll just trundle along through the scene. 4 Cars will have Destinations and instructions. Cars will always start at the beginning of their Roads, and you can assume that the Director will never create any Cars on top of, or dangerously close to, already existing Cars. - Destination: This is not a class but an interface. Any class that implements the Destination interface (such as your Building class) must be able to tell a caller how close to the Destination the given Car object is along the Road they have in common. Destinations must also be able to greet or reject Cars that attempt to finish their journey at that Destination. - Building: You must create the Building class from scratch so that it implements the Destination interface. - City / TrafficLight: These two classes are mostly the same as before. The City class is now also responsible for creating and maintaining a list of Destinations and giving other classes access to those Destination objects. 4. Your first task is to implement the methods addCar() and removeCar() in the Road class. These methods need to work before a Car can be created. - addCar(Car car): For the given Car object, determine to which list of Cars in this Road it needs to be added. Search through this list (it might be empty, though) to determine where in the list the Car must be placed such that when you're done, the list is still sorted according to the description given earlier. (NOTE: No part of this assignment requires that you use any of Java's built-in sorting mechanisms. You're welcome to try, but you should also figure out how to implement this method manually to make sure you understand the mechanics of ArrayLists.) You'll *definitely* want to plan this out conceptually on paper first by drawing Cars and Roads and whatnot. Think carefully about where in your list you need to place a Car if it appears at the beginning of the Road or if it turns onto your Road from another street. Once you've figured out how to put the Car in the right place in your diagram, translate that decision process you went through in your head and on paper into a Java loop. - removeCar(Car car): For the given Car object, remove it from the appropriate list. If it's not in the list for some reason, do nothing. This method is somewhat easier than addCar() if you implement it from scratch. It's a *lot* easier than addCar() if you've done some extra reading and have a crystal clear understanding of the java.util.ArrayList Javadoc documentation. 5. Your second task is to fill in the Car's tick() method such that it implements all of the behaviors from HW5 as well as our new requirements, including: - turning the specified directions at the intersections specified in the instructionList, still obeying the TrafficLights. Use the turn() method to accomplish these turns once you have determined that it is time for the Car to turn. You'll notice that the animation for the turns is not quite Pixar quality! The line that appears on the Road during the turn is meant to help you track the Car through the intersection, as the turn happens rather quickly. Just think of it as scorch marks. :) - stopping if another Car is less than 'speed' pixels ahead of your Car on your Road (going in your direction) and is stopped. Brake lights should be activated as usual. Use the Road's getNextCar(Car car) method in order to find the next Car in front of you on your Road. - returning to the speed limit once the Road is clear in front of the Car. The Car's stop() and resetBrakeLights() methods might help here and above a little bit. - seeking the Car's Destination *after* the last instruction in the instructionList has been executed. Once the Car is on the correct side of the correct Road, use your Building's oneDimensionalDistanceFrom(Car car) method to determine whether your Car's distance along the Road from the Destination is less than 'speed' pixels. If so, attempt to achieve the Car's goal by asking the Destination to greetOrReject(Car car). If the Destination accepts the Car, the Car will be transported onto the Destination and certain bookkeeping will take place. More about these methods is included in the Building class discussion below. - ignoring this Car if it has reached its destination. Here is a detailed conceptual decision structure that you are encouraged to follow for your tick() method. However, you can implement any of the above behaviors any way you want, as long as they all work right. ---------- if (car has been totaled) return if (car has reached its Destination) return if (there are no instructions left) if (there is a destination) if (in range of the destination) ask for entry to the destination if (gained entry) return if (waiting at stoplight) if (stoplight is still red), return else if (stoplight is now green) reset brake lights if (time to turn) record that we're no longer waiting at a light turn the corner and return else if (not time to turn) reset speed & don't return record that we're no longer waiting at a light else if (not waiting at a stoplight) if (nearing an intersection) if (stoplight is green) if (time to turn) turn the corner and return else (if stoplight is red) record that we are waiting at a stoplight stop & return any Car that is still running tick() at this point should advance by speed pixels unless there is a Car in the way if (a Car is in the way) stop & return else if (no Car is in the way) make sure speed set to Road's speed limit and brake lights are off advance the Car on its Road ---------- Naturally, you've already implemented some of these checks and behaviors in previous assignments, and you should feel free to reuse that code in order to get this system up and running. 6. Your third task is to create a Building class from scratch that implements the Destination interface. As they should, the comments in the Destination.java source file explain the purpose of classes that implement the Destination interface and their methods. - Notice that the Destination interface "extends" the Prop interface. This means that not only does your Building class have to implement all the methods specified in Destination.java, but it must also implement all the methods from Prop as well. We will learn more about this concept of "extending" classes and interfaces (called inheritance) in the last couple weeks of the quarter. - public int oneDimensionalDistanceFrom(Car car) This method should return the horizontal pixel distance from the X-coordinate of the upper-left corner of the Building to the X-coordinate of the upper-left corner of the given Car (assuming that the Road on which the Car and the Building currently sit runs East-West) or the vertical pixel distance from the Y-coordinate of the upper-left corner of the Building to the Y-coordinate of the upper-left corner of the given Car (assuming that the Road runs North-South). - public boolean greetOrReject(Car car) This method should test the given Car (using the oneDimensionalDistance method) to see if the Car is within 'speed' pixels of the Building. If so, the Car should be stopped, moved to the inside of the Building (however you want to do this), and removed from the car's Road's appropriate Car list. A welcome message should also be printed out, and the method should return true. If the Car in question is not in range of the Building, the method should print a reproving message and return false. 7. Obviously many pieces of this code are interrelated. For example, the way City is currently written, it requires a functioning Building class in order to run your program. Feel free to comment out the appropriate parts of the City class that deal with Buildings until you've written the Building class. Do the same for any other components of the system that you want to ignore until later. But in the end, make sure you're testing everything as originally provided, since that's how we'll be evaluating your system after you turn it in. Another thing you can do to get your code running right away is to copy your tick() method from HW5 into the new Car.java. Then you can start adjusting pieces of it as you please. 8. You *will* be graded on your comments in this Programming Assignment. Most if not all of the Javadoc comments for the methods are already present in the code you downloaded, but if and when you add any additional methods, create any new classes (such as Building), or change anything from the way it was initially implemented, make sure to add or change all relevant comments so that your code and your documentation both say the same thing. 9. This assignment requires quite a fair bit of thinking and coding. You have one week to work on it, which means you also have one week's worth of time to talk to your TAs, attend office hours, send mail to the staff e-mail list, and converse on the discussion board. That's a lot of time, so use it!