Othello/Reversi

Due 29 Apr

For our third project, you are going to implement a board game on your own.

Reversi is a strategy boardgame often known by the trademarked name "Othello". It is played with two players on an 8x8 grid. The players each start with 32 disks, colored black on one side and white on the other. The goal of the game is to have the most discs of your color facing up when the game ends.

You are going to create a complete program that will allow two players on different computers to compete against each other head-to-head. You are going to create a network connection between the two players, draw the game board, and enforce the rules.

We are not going to give you any code to start this project, and we are not going to explain the full rules of the game. Before you start, it is important that you read the rules at the game manufacturer's official site below, and that you understand how points for the project will be allocated. There are multiple "official" versions of rules for Reversi. In order to reduce ambiguity, we are going to use the formal "Othello" version described below.

Learning Othello

The official rules you need to follow are listed here

Here are some online versions to help you understand the game:

You can use the following commands on your Linux VM to install a copy of the game that you can run locally:

sudo apt-get install grhino   # installs the program
grhino                        # runs the game

Overall Program

Your program must run from a file named "Reversi.java".

The purpose of this program is to allow two people to play Reversi head-to-head over a network connection. Each will be running the program in their own terminal.

Here are some thoughts on architecture:

You should submit code for the highest step that you achieve in its entirety. Note that these points are not cumulative; that is, if you have a perfect Step 2, you have 20 points (out of 100). You do not get 10 for Step 1 and another 20 for Step 2.

Javadoc is recommended for your personal use, but is not required for points.

The Assignment

Step 1: [10 pts] Usage Statement

Your program parses the command line and prints a usage statement if the user passes the "-h" flag. Sample usage is shown below.

$ java Reversi -h
Usage: 
   Reversi -s <port>       Starts the Server for a networked game on the requested port
                           e.g. java Reversi -s 12300
   Reversi -c <IP> <port>  Connects as a Client to an existing game on the requested socket
                           e.g. java Reversi -c 10.10.1.4 12300
   Reversi -h              prints this usage

Step 2: [20 pts] Create an initial socket between two processes

This step establishes a basic connection between the client and server processes. It does not need to move any text across the channel, it just needs to verify that connectivity has been achieved.

The "server" and "client" processes are both from code within Reversi.java. They act very differently. When you parse the command-line, you want to check whether a process is a server or client and act accordingly.

The server process opens a socket and starts listening for a connection.

The client process tries to connect to the remote server application.

Once both processes have completed the connection, they each need to print a message to the user saying that the connection is established. The program can end at this point.

The following requirements must be met to get points for this step:

  1. A player starts the server process from the command-line, e.g. java Reversi -s 12300
  2. The server process prints a helpful message (e.g. "Server started. Waiting for another player to connect...") to let the player know to wait.
  3. A second player starts the client process from the command-line and connect to the server, e.g. java Reversi -c 10.10.1.4 12300
  4. The client process is automatically designated the black player and has the first move.
  5. When the client first establishes the connection, each user gets a printed message that says:
    Game started. You are the (Black||White) player. It is Black's turn.

Step 3: [40 pts] Create a two-way communications channel between the processes

This step builds the necessary logic to let two players alternate typing text to place their game pieces. You will essentially create a Chat Window where only one person can speak at a time.

Assume that the two users are in separate buildings and cannot communicate except through the game. This text channel has to tell them when to move and when to wait.

Only one user can make a move at a time. The other user needs to know whether they are waiting or should be making a move. For this Step, a "move" consists of entering any text. So first the Black player enters text, then the White player, and so forth.

A player should not be able to enter text if it is not their turn.

Players are notified when it is their turn.

Scanner objects can read from either sockets or from the terminal. Since a socket "blocks" the program (pauses the program at the socket.nextLine() method) it is difficult to listen to both the terminal and the socket at the same time.

The best way to implement this is to have two Scanners running in each application - one listening to the terminal and one to the keyboard.

The server and client need to coordinate their moves so that one is always listening to the keyboard and the other is listening to the socket.

The workflow should look like this:

  1. The Black player goes first. It remains their turn until they enter some text (Assume they type "D4")
  2. Once a player enters text, it appears on both players' screens: e.g.
    Black's move: D4
  3. White then is able to input text at the terminal. Black listens at the socket to hear White's move. They continue to alternate, with only one being able to type at a time.

The following shows an example of what should be displayed on each terminal as the players alternate their moves. On Moves #1 & 3, Only the Black player (client) can enter text. On Moves #2 & 4, only the White player (server) can enter text.

Move no.White's TerminalBlack's Terminal
1 Game started. You are the White Player. It is Black's turn... Game started. You are the Black Player. It is your turn.
[types "D4"]
2 Black's move: D4. It is your turn. Black's move: D4. It is White's turn...
[types "A1"]
3 White's move: A1. It is Black's turn... White's move: A1. It is your turn.
[types "C3"]
3 ... ...

Step 4: [50 pts] Initial error-checking of moves

This Step validates the move that each player enters to ensure that it is a 2-character entry that corresponds to a valid location on the Reversi board.

Valid codes include "A1" through "H8" and "a1" through h8".

A player's turn ends when they have entered a string that represents a valid space on the board. It does not matter whether that space can actually be played at the time.

The most important aspect of this Step is to correctly coordinate both processes when a player makes an illegal move. The game will stop functioning correctly if both players think they are allowed to move at the same time.

Make sure that your solution to this Step is extensible. You will want to use the same logic for a future Step where you have to check whether a move is within the rules.

HINT - you should put all of the game intelligence into the server process. Have the client send its text to the server to be checked. Do not do it in the client process. This will make things easier later on.

The following requirements must be met to get points for this step:

  1. If the active player enters any spot on the board from A1 to H8 or a1 to h8, their move will be printed out for both players and their turn will end.
  2. If the active player types anything else, they will be told they have made an illegal move, and requested to try again.

The following shows an example of what should be displayed on each terminal if one player enters an illegal move. In this case, the White player enters "QWERTY" in Move 2, and has to try again. He correctly enters "A1" the second time around:

Move no.White's TerminalBlack's Terminal
1 Game started. You are the White Player. It is Black's turn. Game started. You are the Black Player. It is your turn.
[types "D4"]
2 Black's move: D4. It is your turn. Black's move: D4. It is White's turn...
[types "QWERTY"]
White entered "QWERTY". That is not a legal move. Try again.
[types "A1"]
3 White's move: A1. It is Black's turn... White's move: A1. It is your turn.
... ...

Step 5: [60 pts] Graceful exit

This Step will allow either player to end the game. Ending the game means closing the socket and shutting down both processes.

If you do not close the socket correctly, the operating system may think that you are still using it. The port number would be inaccessible to other applications until the computer reboots.

You should call the close() method for both the Socket and any Streams that access it.

Either player can shut down the game by typing /quit during their turn.

The following requirements must be met to get points for this step:

  1. If either user types /quit, their process sends a message to the other process telling it to shut down.
  2. Once the message has been sent, each process closes its network socket, InputStreams, and OutputStreams.
  3. Each process prints a helpful message about what is happening, e.g.: White has quit. Game is over.
  4. Each process exits.

NOTE - in Linux, you can use the command netstat -lpunt to see what port numbers are open for listening. You can use this to verify whether your ports are being opened and closed.

Step 6: [70 pts] Render the board

Render the basic gameboard and its pieces. Rendering it with unicode characters as we did with Chess is perfectly acceptable.

The board must be redrawn on each player's terminal at the end of each player's turn.

The players' pieces do not have to be rendered yet for this Step.

You are free to recycle any code you want from the Chess project.

The following requirements must be met to get points for this Step:

  1. The board must be an 8x8 grid.
  2. The gridlines must be clearly shown.
  3. The grid must be labeled "A" though "H" across the top and "1" through "8" down the left side. (As shown in the image to the right)
  4. The board is redrawn at the end of each player's turn.
  5. The board is displayed on each player's terminal.

HINT - you should put all of the game-engine into the server process. Do all of the drawing in the server, not the client. At the end of each turn, have the server generate the unicode string that draws the board, and then just send it across the text channel to the client.

Here are some helpful links that show some unicode characters you may want to use for drawing a grid and some disc pieces.

  1. http://en.wikipedia.org/wiki/Box-drawing_character
  2. http://en.wikipedia.org/wiki/Geometric_Shapes

Step 7: [80 points] Place pieces in any open space on the board

In this Step, you will implement logic to allow the players to place their colored discs in any open space on the board.

You will need to implement a data structure that holds the location and color of each piece.

You do not have to put your pieces adjacent to an opponent's - any open space is fine.

You do not flip any of your opponent's pieces over in this Step.

The following requirements must be met to get points for this step:

  1. The players alternate placing pieces.
  2. A player's turn only ends when they have chosen the location of an open grid on the board.
  3. The server's internal data structure is updated so that it knows about the new piece.
  4. If a player chooses a grid location that is already full, they get a helpful error message (e.g. That location is full. Choose another.) It is still their turn.
  5. The new pieces must be rendered on the board after they are placed.
  6. The game ends when all 64 locations have been filled. (Or a player types /quit)

Step 8: [95 points] Flip over your opponent's pieces

In this Step, when a player places a disc, you will flip over any of the opponent's pieces that should be flipped according to the rules.

It is not necessary that an opponent make a legal move (i.e. one that will cause discs to flip.) Players may place their discs on any open location.

The following requirements must be met to get points for this step:

  1. Whenever a player makes a move, all of the opponent discs that should be flipped, are flipped.
  2. Remember that it is possible for a disc to flip other discs in multiple directions (e.g. to the north and to the east) on a single move.
  3. The server must update its internal data structure with the new colors of the pieces.
  4. The rendering of the board must show the newly flipped pieces.

Step 9: [100 points] Legal placement of pieces only

In this Step, you will implement the most important rule in Reversi: a player is only allowed to make a move if they are able to flip over an opponent's piece. Implementing this rule has vast implication on the players' strategy.

You will also start keeping score. Every move, the player's will see a message indicating the last move and the current score. e.g.

White's move: D4  Score: Black 26  White 8. It is your turn.

The following requirements must be met to get points for this step:

  1. Players can only make a move that results in flipping a disc.
  2. After each turn, the players get a printout of the last move and the current score.

EXTRA CREDIT*: 5 points each

5 points for each of these bullet points. These will ONLY be considered and awarded points if you have a successful Step 9 project.

* Remember - there is no such thing as "Extra Credit". Get all the points you can, whenever you can.

What to hand in

  1. Write a README.txt that states the highest step you achieved and what extra features you've implemented (for example, if you implemented Hints, tell us so we know and can test for it).
  2. Submit all of your *.java files, along with README.txt.
  3. NOTE - do not forget any .java file. We should be able to compile and run with this command: javac Reversi.java && java Reversi -h
  4. Delete any *.class or other unneeded files prior to submitting
  5. Delete all the files created by running javadoc.
  6. All of the above must be in a directory named 'Project3'
  7. When you run the submit script, the directory and its contents get zipped and sent to your instructor. Ask for help early if you are having problems running the submit script.

Make sure that you run the correct submit script for your instructor:

Notes 1:

START EARLY. You cannot write this program in 1-2 sittings. Start work before this weekend so you get a feel for the complexity of this assignment.

Notes 2:

Review the course policy statement on Honor and Projects.

Why do we make these rules for Projects? It is true that you can learn a lot about programming by working with another student. That is why we let you collaborate for Labs. The downside is that the relationship is often uneven - one student usually does the bulk of the programming. The weaker student can often skate by an entire semester without really being challenged to program themselves. We insist that everybody program their Projects alone so that we (and you) can identify weak programmers early and get them some extra instruction.

IN SUMMARY:

     Asking Professors == OKAY
     Asking other students == BAD