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.Purpose
Aimone Laura
Barrett Brian
Lin Joyce
Chung Helen
Geyer Scott
Rose Sarah
Connors Andrew
Lucas Erin
Zhang ZhannanCroft 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
- Apply knowledge accumulated during this course to make a fun game
Background
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!)
- a human-controlled snake that a human user can control (using the keyboard or mouse)
- an automated snake that plays the game without any human intervention
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:
- Keeping track of the player's score
- Alerting the client of their current position on the board
- Alerting the client of the current positions of apples on the board
- Alerting the client of the current positions of all other players on the board
- Indicating the direction that the player's snake is moving
- Indicating when the player is out of the game (due to violating one of the previously mentioned rules)
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 ps7.zip (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:
- Display the game board with all snakes and apples
- Set up and maintain a connection with the server
- Control the behavior of the snake — in the user-controlled version, by accepting input from the player to move their snake (the snake can only turn left or right); in the automatic version, by programming the snake to make decisions based on the state of the world.
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.
Classes
We have provided two abstract types to assist with your implementations (in addition to the Direction type from PS5).Coordinate
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. { } }
SnakeInterface
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; import java.net.*; import java.io.*; 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/ps7.zip [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 ps7.zip in that subdirectory by executing unzip ps7.zip 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.
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.
University of Virginia Department of Computer Science CS 201J: Engineering Software |
Sponsored by the National Science Foundation |
cs201j-staff@cs.virginia.edu |