Traffic Project: Part 3
Many vehicles, intersections, and route finding
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
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,
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:
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.
- 'loc :: posn
- 'update :: void
- 'draw-self :: (image -> image)
- 'report-status :: symbol
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:
- 'draw-self :: (image -> image)
- 'update :: void
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.
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.
- 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.
- 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.
- 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.
- 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.
- random-vehicle: -> vehicle. Write the function to generate
a random vehicle with random speed, source and sink.
- 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).
- 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.
- 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.
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.