Traffic Project: Part 3
Many vehicles, intersections, and route finding

Sample animation for deliverable 2

For the third deliverable, you will continue to build on what you implemented previously. In this installment, you will encapsulate vehicle functionality within a class, or interface, and generate many vehicles that will traverse your network at the same time. As before, your vehicles should stop for red lights, but now your intersections will also be encapsulations and only one light at a given intersection will be green at any time.

Extending and Encapsulating Vehicles

Using the techniques presented in class and in Sections 39-41 of the first edition of How to Design Programs, create an interface that encapsulates the state-variables pertaining to a vehicle. That is, instead of representing vehicles as a make-vehicle structure, we will represent vehicles as the service-managers returned by our encapsulating function, make-encapsulated-vehicle. You should remove your structure-definition for vehicles as they will be entirely represented by persistent objects created by your make-encapsulated-vehicle function, which should return instances satisfying the following interface:
A vehicle is an interface:

  1. 'loc :: posn
  2. 'update :: void
  3. 'draw-self :: (image -> image)
  4. 'report-status :: symbol
A vehicle should respond to a 'loc message with its current location; to an 'update message by updating its internal state-variable(s) appropriately depending on its route, current roadsegment, current position, and light status of traffic lights that may be present; to a 'draw-self message by providing a function that consumes an image and returns a corresponding image that has this car's image placed on it; and to a 'report-status message with one of two symbols -- 'done or in-route according to whether the vehicle has finished its route or not. Our cars will ignore each other. Faster vehicles can drive through slower ones in front of them.

Encapsulating Intersections

As discussed in the previous deliverable, a single light at an intersection must coordinate with the state of the lights signaling other directions of travel through an intersection. Thus, we want an encapsulation of the lights on all roadsegments entering an intersection and a mechanism for controlling them.

An intersection will consist of the roadsegments on which vehicles enter, a fixed (but intersection-specific) duration for the green-phase, a phase-clock time, and an indication of which roadsegment has the right-of-way (with a corresponding green light).

An intersection encapsulates several state-variables; primarily, it encapsulates the phase-clock and light-status. However, since only one roadsegment at an intersection may have a green light, we add a state-variable right-of-way, indicating which of several incoming roadsegments has the green light. All others are assumed to be red.

The incoming roadsegments at an intersection are represented in a vector, or array (i.e., not a posn). We use a natural number for the right-of-way state-variable so that we can index into the vector of roadsegments. When the light changes from green to red at the end of its green-phase, the right-of-way can be incremented, and wrapped back to the beginning after the last roadsegment. You should include an ‘all-red’ phase of a short duration prior to the next roadsegment receiving the right-of-way (and corresponding green light).

The intersection objects you will be creating should conform to the following interface:
A intersection is an interface:

  1. 'draw-self :: (image -> image)
  2. 'update :: void

Travel Routes

You should have a moderately complex road network consisting of at least two sources and two sinks. For the purposes of our simulation, we will create vehicles with a random source and random sink. (It is your responsibility to ensure that there exists a path between each source-sink pair.) At time of creation, the vehicle should initialize its route state-variable using a program that searches through your road network looking for a path from the source to the sink. In class, we will go over a find-route function that does this but you can also find much of the code and explanation in Section 28 and Section 31 of the first edition of HtDP.

Requirements

This is an individual project; working together must be limited to asking specific questions about Racket functionality.

As always, follow the design recipe and make sure your code conforms to the specifications. Function names and argument order must be followed precisely. I may test your program with code of my own so errors at testing time will result in significant penalties even if your code ‘works’ with your own tests.

  1. Changes, updates, and general cleanup. Update templates to reflect any changes to our data definitions. The data-definition for a roadsegment should indicate that the light field is now either a boolean or symbol. The field should be false if there is no light (i.e., the road does not enter an intersection) or a symbol (either 'red or 'green). You should remove your template for vehicles since they no longer have a corresponding structure-definition. Remove top-level state-variables and global constants that will now be encapsulated. You should remove functions and constants that are no longer needed. Your utilities should be organized together in one section, with the posn-operator utilities that I prescribed together and any other utilities that you have created placed in a coherent order. Use this new structure definition, (define-struct traffic-world (vehicles intersections)), as our world representation; the two field values are lists of vehicle and intersection, respectively.
  2. make-encapsulated-vehicle: number image roadsegment roadsegment -> vehicle. Write this function as the encapsulation of a vehicle, where the number is its speed, the image is the overhead car-image, and the two roadsegments are the source and sink respectively. This function should encapsulate the vehicle's location, direction of travel, speed, image, and route. The functionality with this encapsulation may either refer to utilities defined at the top level or may include locally defined functions that interact closely with the state-variables.
  3. place-vehicle: vehicle image -> image. Modify this function to perform the same functionality as before and following the same signature as before but with the meaning of a vehicle modified as above. That is, since vehicles are now objects, this function should send the 'draw-self message to the given vehicle.
  4. place-vehicles: [ListOf vehicle] image -> image. Since we will be simulating many cars, write a function that takes a list of vehicles and draws each one of them. Do the same for updates to vehicles.
  5. random-vehicle: -> vehicle. Write the function to generate a random vehicle with random speed, source and sink.
  6. do-updates. Modify this function as needed to reflect the new representation worlds and vehicles. Also add functionality to this function so that periodically (on a random basis) new random vehicles are created and added to the vehicles component of the world representation (i.e., a make-traffic-world).
  7. make-encapsulated-intersection: [VectorOf roadsegment] number -> intersection. Write this function to return instances of the intersection class (or interface). It should consume a vector of roadsegments that are entering the intersection and a single number representing the number of ticks for the green-phase for this intersection. Notice, each intersection can have its own green-phase value. However, you should define an ‘all-red’ global constant that all intersections must abide by between green phases. Hint: when an intersection wants to switch the right-of-way from one road to another, it should use the structure mutator command for the roadsegment light field.
  8. Animate with big-bang. You should define complete road network of roadsegments. As before, you can define and name these and create a single roadbed image that renders the roads; use this as your ‘empty-scene’. Animate the simulation with big-bang for about 20 seconds, after which the simulation should end. As vehicles complete their routes (i.e., when their report-status responds with 'done) the vehicles should be removed from the list of vehicles found in the traffic-world object.

Submission

Do not forget to include the standard acknowledgements header at the top of your file. To grade this deliverable, I will review your code (including signatures, purpose statements, indentation, etc.), and then call big-bang with your your update-vehicle and place-vehicle functions, together with a roadsegment of my choosing.

Submit a single file with your username followed by “P3.rkt” as the name of the file, which should contain your code fulfilling the requirements as well as your acknowledgements.