University of Virginia, Department of Computer Science
CS201J: Engineering Software, Fall 2002

Problem Set 7: Ophidiophobia Out: 19 November 2002
Due: (code) Wednesday 4 December, 11:59pm
Due: (turnin) Thursday 5 December, beginning of class

Collaboration Policy (read carefully)

For this problem set, you are required to work with an assigned group. Unlike other assignments, your group should strive to divide the work in such a way that you can work independently on different parts, and combine your work to solve the problem. In your turnin document, you must document clearly what each team member did.

Aimone Laura
Barrett Brian
Lin Joyce
Chung Helen
Geyer Scott
Rose Sarah
Connors Andrew
Lucas Erin
Zhang Zhannan
Croft Tucker
Lee Diane
Guttridge Katherine
Dennehy Kevin
Stockdale Spencer
Wu Doris
Eaton Darnell
Hoon Sherlynn
Winstanley Katie
Fournier Jacques
Huntley Daniel
Lai Wei-Han
Lee Alex
Assanah Fayekah
Franchak John
Rutherford Christopher
Seirafi Reza
Wiygul Alicia



The game of Snakes is quite simple: a player controls a snake which is continuously moving forward. The player's goal is to turn the snake left and right (relative to its current trajectory) to eat as many apples as possible. If the snake's head hits the boundaries of the snake pit or the body of the snake, the snake dies and the game is over. When the snake eats an apple, the player's score is increased, but at the same time the length of the snake is increased. The length increases by extending the neck for the next several timesteps (but leaving the rest of the sanke body where it is). As the snake grows in length, it becomes harder to eat the apples without running into the snake's body.

For this assignment, you will design and implement the client software to play Snakes over a network. This version of the game will differ from traditional versions in that it will support multiple players (each player will control one snake in the snake pit). This means that it is now possible to end the game by colliding with another player, in addition to going out of bounds or colliding with yourself. The winner of the game is the player with the highest score.

You will implement two versions of your client:

You should design your implementation carefully to reuse as much code as possible between these two versions (hint: use subtying and inheritance where it is sensible!)

When the client is started, it will connect to a server and then send a command to alert the server that it is ready to join the game. The server's responsibilities are as follows:

Since you are not required to write the server for this assignment (only the client), a server to test your code with is provided in (class files only, the source code for our server will not be provided). A similar server will be used for the contest. Also, you will be provided with classes to help parse the information from the server into usable data.

Your snake client must:

When started, your client will need to create a socket to connect to the server. Next, it will pass this connected socket to the SnakeInterface class below, and will use this class to pass commands to the server and to parse information from the server. This information will then be used to update the client's display of the game board. Once your snake has quit running, you must close the socket and then reconnect to the server if you would like to play another game. To learn how to use network sockets, we recommend reading: The Java Tutorial: All About Sockets.


We have provided two abstract types to assist with your implementations (in addition to the Direction type from PS5).


This class provides an abstraction for the coordinates on the game board. Internally, it stores two ints representing an x and a y coordinate. Appropriate mutators and inspectors are provided as well as some other members:

public class Coordinate extends Object
  // OVERVIEW: A Coordinate represents a point in a two-dimensional 
  //    plane.  A typical Coordinate is (x, y) where x and y are
  //    integers.

  public Coordinate (int x, int y)
    // EFFECTS: Initializes this to the coordinate (x, y).
  { }
  public Coordinate (/*@non_null@*/ Coordinate c)
    // EFFECTS: Initializes this to the coordinate (c.x, c.y).
  { }
  public int getX ()
    // EFFECTS: Returns the x component of this.
  { }
  public int getY ()
    // EFFECTS: Returns the y component of this.
  { }
  public void setX (int x)
    // MODIFIES: this
    // EFFECTS: Changes the x component of this to x.
  { }
  public void setY (int y)
    // MODIFIES:  this
    // EFFECTS: Changes the y component of this to y.
  { }
  public String toString ()
     // EFFECTS: Returns a String representing the Coordinate.
  { }
  public boolean equals (Object c)
     // EFFECTS: Returns true iff c is a Coordinate with the
     //    the same x and y component values as this.
  { }


This class implements the communication protocol that the client must use to properly communicate with the server.

In addition to simpifying the process of reading data from the server, the SnakeInterface class also simplifies the process of the client sending information to the server. This is made possible by the turnLeft and turnRight methods. The SnakeInterface class is a subtype of the Thread class. It works such that after the constructor is called (by passing it a connected Socket), a Thread is created that enters a loop listening to the Socket. This Thread simply updates the private data members with the information it receives from the server. Note that the SnakeInterface class does not provide a good abstract model of the world that you would want to use in your automated client implementation. Good automated clients will probably develop a better representation of the snake pit world (possibly by creating a subtype of SnakeInterface).

// SnakeInterface.spec

import java.util.Vector;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;

abstract public class SnakeInterface extends Thread {
    // OVERVIEW: A SnakeInterface provides a connection between
    //    a snake and the snake server.  The SnakeInterface
    //    runs in a separate thread.  It provides methods for
    //    sending commands to the server (e.g., turnLeft turns the
    //    snake's head towards the left), and for observing the state
    //    of the snake pit (e.g., getScore).
    public SnakeInterface (/*@non_null@*/ Socket sock) throws IOException {
	// REQUIRES: sock has already been initialized and is 
	//    connected to the server.
	// MODIFIES: sock
	// EFFECTS: Creates a new Thread to listen for data being sent by
	//    the server.  Throws an IOException if there is a problem with
	//    the socket.

    // Abstract method that will be called whenever the state of the world has changed.
    abstract public void updateState ();

    public void startGame () {
	// EFFECTS: Sends the command to inform the server that the client 
	//   is ready to play. 

    public void setSnakeName (String name) {
	// EFFECTS: Sends a command to inform the server that the client's name is name.
    public void turnLeft () {
	// EFFECTS: Sends the command to turn the snake left (relative to 
	//   its current trajectory).
    public void turnRight () {
	// EFFECTS: Sends the command to turn the snake right (relative to
	//    its current trajectory).
    public int getScore () {
	// EFFECTS: Returns the client's current score as an int.
    public boolean isPlaying () {
	// EFFECTS: Returns false if the player is out of the game for any reason,
	//    otherwise returns true if the player is still alive.
    public /*@non_null@*/ PlainDirection getDirection () {
	// EFFECTS: Returns the current trajectory of this (N, S, E or W).
    public /*@non_null@*/ Coordinate getBoardSize () throws RuntimeException {
	// EFFECTS: Returns the size of the board as a Coordinate, where the maximum  
	//     Coordinate that can be moved to is:
	//            Coordinate (getBoardSize ().getX () - 1, getBoardSize ().getY () - 1)
    public /*@non_null@*/ Vector getSnake () 
        //@ensures \result.elementType == \type(Coordinate) 
        //@ensures \result.containsNull == false
	// EFFECTS: Returns an ordered Vector filled with Coordinates indicating 
	//    which coordinates on the board the client's snake currently occupies.
	//    The first element in the Vector is the head, and the last is the tail.
    public int getId () throws RuntimeException 
       //@ensures \result >= 0
	// EFFECTS: Returns the id number of this snake.

    public /*@non_null@*/ Vector getApples () 
 	 //@ensures \result.elementType == \type(Coordinate)
 	 //@ensures \result.containsNull == false
	// EFFECTS: Returns a Vector filled with Coordinates indicating where on
	//    the board apples are located.
    public int getNumberOfSnakes () {
	// EFFECTS: Returns the number of snakes in the snake pit (including
	//    this snake).

    //@requires n >= 0
    public Vector getNthSnake (int n) {
	// REQUIRES: n < the number of snakes in the snake pit.
	//     and n != getId (), the id of this snake.
	// EFFECTS: Returns an ordered Vector that contains all the
	//    Coordinates in the snake pit that are currently occupied
	//    by snake number n.  The snakes in the snake pit are numbered
	//    sequentially starting from 1.  If the requested snake is dead, 
	//    returns an empty vector.

Download: You will need to download this file to your machine: code/ [Updated: 1 December 2002]

You may use any other code you have written or we have provided (including in Problem Set solutions). In particular, we expect you will find much of the code from PS5 useful.

Create a cs201j sub-directory in your home directory, and a ps7 subdirectory in that directory. Unzip in that subdirectory by executing unzip in a command shell. This file contains our server code for use in testing your client. Run the server by typing java server.Snakes #port#, where #port# is a port number between 1024 and 65536. Your client should connect on this same port number.

Snake Fest

On the last day of class (December 5), we will have a contest pitting both your human-controlled and automated snakes against each other in a bloody battle. There will be separate contests for human-controlled snakes (where your snake driving abilities may be as important as your software engineering expertise!) and for automated snakes (where the snake owners will not be allowed to interfere at all during the game). In addition to untold glory and everlasting fame, the winners of the contest will receive token prizes (possibly, but not necessarily, better that "gold stars"!) The best prizes will go to the winner of the automated snake contest (i.e., you should spend more time thinking how to make your automated snake behave smartly, then practicing your snake driving skills).

To be eligible to participate in the contest, your code must be submitted by 11:59pm on Wednesday, 4 December. Only programs that pass the required tests (some of which will be revealed, others will be kept secret) will be entered in the contest. In addition, your submitted code must have been checked with ESC/Java. This does not mean it must be checked without producing a single warning message, but it must include sufficient ESC/Java annotations to enable useful checking and all remaning warnings must be explained in code comments (what you think the message means, and why you believe your code is okay).

Turn-in Checklist: On December 5th, turn in:
  • A document describing your design, including a modular dependency diagram (that also shows inheritance relationships).
  • A clear and precise explanation of what each team member did.
  • An explanation of any known problems with your program.
  • A printout of all the code you wrote.

Related links:

Credits: This problem set was developed for UVA CS 201J Fall 2002 by Serge Egelman, David Evans and Mike Peck. We thank the College of Charleston for providing Internet access.

CS201J University of Virginia
Department of Computer Science
CS 201J: Engineering Software
Sponsored by the
National Science Foundation