
All problems must be submitted electronically through the online submission system.
The procedure server-loop is a thunk that is called from server-game
in a separate thread. It is a simple tail-recursive loop whose sole
purpose is to listen for incoming connection requests and create a new player
for each new connection. It creates a thread on the server for each new
player that listens on the input port for messages from the client.
Here is what server-loop must do:
tcp-accept, wait for the next connection. This will block
until a connection request is received from a client. The
values returned from tcp-accept are the input and output ports to the client.*max-players*)
playing. If so, inform the client and close the ports.make-net-player.make-net-player is implemented, if
it fails to create the player for some reason, it just kills the thread,
which would prevent any new connections if we didn't do it in a separate
thread.
TURN IN your code for server-loop.
The *event-queue* is a priority queue that holds all the game
events. In the single-player version of the game, there is only one thread
that ever accesses the event queue. However, in the multiplayer version,
the event queue is shared among several processes. We need to protect the
queue with a semaphore to make sure that only one process accesses the event
queue at a time. This should be done for all queue operations--reading as
well as writing--since two threads accessing the event queue simultaneously can
result in aberrant behavior and can lead to inconsistent states.
Create a new semaphore *event-mutex* and use it to enforce
mutual exclusion on *event-queue*.
TURN IN your definition of *event-mutex*
and show all places where you use it.
When a player leaves the game, there should be a way to get rid of all vestiges of that player. This was not as much of an issue in single-player mode, since when the player quits, the game is over; but not so with the multiplayer version. We would like to gracefully remove all traces of the player and leave the world in a consistent state so that other players who may still be playing notice no abnormalities.
Right now when destroy is called on a <net-player>,
the method for its superclass <player> is dispatched.
This removes the player from the active player list *players* among
other things. However, there are several things that need to be done for a <net-player>
in addition to the actions already done for a <player>.
Write a method
(defmethod (destroy (p <net-player>)) ... )
that overrides the destroy method for <player>s.
Your destroy procedure should do the following:
*players*. These actions are
already taken care of by the destroy methods of the <net-player>'s
superclasses, so you can just (call-next-method).
However, the active player list is shared among the different player
threads, and you must prevent access by more than one thread at a time lest
the list be corrupted by two threads trying to modify it
simultaneously. Use the semaphore *players-mutex* (in
server.ss) for
this purpose.TURN IN your code for destroy
and any other code that you modify.
Implement a pair of walkie-talkies, which are two-way radios that allow two
players to communicate secretly with each other. They should be ordinary <inanimate>s
that can be dropped, taken, stolen, etc. The holder of a walkie-talkie
communicates with the holder of the other walkie-talkie by typing a message
string beginning with a period (.), something like .we attack
at dawn. The holder of the other walkie-talkie hears:
Walkie-Talkie: we attack at dawn
If no one is currently holding the other walkie-talkie, no one hears
anything. This should work similar to the way 'hi there
(short for say "hi there") results in the message
You say: hi there
TURN IN your code implementing walkie-talkies.
Many people did a less-than-ideal job on PS4. There were a lot of silly errors, and we suspect that in many cases it was because you did not allow yourself enough time to complete the assignment.
We would like to give you a second chance. Please correct all your bugs from PS4. If you do a nice job, we will give you back up to half of the points you lost in the first grading.
TURN IN your corrected PS4 code.
Please use your imagination to implement some enhancement to the game of your own choice. You may do anything you like here. The sky's the limit! This is the fun part of the problem set, and we have seen some very cool things in the past. Get the mundane stuff above (problems 1-5) out of the way first so you can concentrate on this.
You will be graded on how much fun your enhancement is and the correctness and appropriateness of your implementation. One criterion is how well your enhancement integrates into the existing game structure. Contrary to what you might expect, we regard it as a good thing if the implementation turns out to be not too difficult, because it will mean that you have chosen something that allows you to take advantage of the existing infrastructure.
TURN IN all code that you write or modify, as well as a short written description of what you tried to do and your approach. Since this is an open-ended question, it will be important that you give us a lot of information here and that you comment your code adequately so that we can figure out what is going on.