Othello
Multithreaded Othello Project
code
A few years ago I did this project for my Data Communications class, I did all of the program logic and thread handling while my partner took care of the GUI. This program allows users to connect to a server and play games of Othello with each other. It is multithreaded and can run multiple games at the same time. The scope was a bit limited as this was just a project for a class so this current iteration is just designed to run on one computer. I spent a lot of time on this project and am quite proud of how it turned out. I had a lot of fun making it so I think I might revisit it sometime soon. I included the report we wrote for the class as well as some screen shots down below.
Intro
We decided to do the game Othello using C-S architecture where both players connect to the
server. The server will manage the connection between two players and send game moves to
each player. This project is multithreaded so many clients can connect and many games can be
played at once. We decided to build this entire project in java as that is our most well known
language, as well as ease of handling the multi-threading, socket programming, and
input/output streams. We also create a GUI for the game itself.
The program has seven Java files total. Four of the files are code for the client and server
connections: ClientHandler.java, GameClient.java, GameServer.java, and GameHandler.java.
Two of the files are for the GUI: OthelloPanel.java and OthelloGUI.java. The last file is for game
logic: Othello.java.
The following commands are implemented:
connect: This allows the user to connect to a specified port number on the server.
create: This is from the client side. Once the client has connected to the server (which happens
automatically when the program is ran), they are able to type create in order to create a game.
join<id>: This command followed by the game number allows the user to join a specific game.
list: This command allows the user to see if there are any available games to join.
close: This terminates the program.
Program Logic
GUI Files:
There are two main files that implement the OthelloGUI that we created: OthelloGUI and
OthelloPanel. OthelloPanel has a function that we created called ButtonListener that
implements ActionListener. This makes it so that when any of the buttons are hit, there is a
signal sent out. It also has createBoard and updateBoard functions to ensure that the GUI
updates (on both of the player’s screen) whenever a player picks a spot to move. OthelloGUI is
mostly just setting up the frame and the way that the frame should look.
Game Logic Files:
Othello.java is where the core logic lies, there is a driver in GameHandler.java that uses and
runs Othello.java. Othello.java has several toString methods that convert the board state into
strings which the GameHandler sends to the client
Server and Client Flies:
There are four files for the server and client connections: GameServer.java, GameHandler.java,
GameClient.java, and ClientHandler.java. GameServer.java sets up the server that accepts
clients. Clients are passed into the ClientHandler which sets up a connection with
GameClient.java and takes in and executes the commands. When a game is created the
ClientHandler records the address of the client and adds it to the list of games, when the game
is joined the ClientHandler launches the GameHandler with the two clients addresses. Each
client starts a new connection with the GameHandler, the GameHandler connects to each client
and the game is played.
GameClient.java
This is the client class which relies on the two gui files OthelloPanel.java and OthelloGUI.java.
When the program starts the client is prompted to connect to the server, when the client
connects they are put into a while(true) loop where they can input commands into the command
line. When a game is created or joined a new GameClient class is created with the server and
port information. The client then creates a new socket and waits for the server to connect to it.
The way the port numbers are determined is based on the gameID, the client creating the game
uses 3030+(id*2) +1, which always evaluates to an odd number. The client joining a game
creates their game on port 3030 +((id+1)*2), which always evaluates to an even number. This
math is being done on the server side so that the server will always connect to the right port.
Once the game is running the client awaits connection, when this happens the server will send
the boardState to the client in the form of a string, which is parsed and converted into a 2d grid.
The client takes in grids from the server every time the board is updated. The server is also
sending an integer at the beginning that tells the client if the game is over, if the game is over
the client loop will stop and the game will end on the client side closing the gui and
disconnecting the socket. If the client receives a grid with a “P” it means that there are possible
moves which means it is the clients turn, if there is no “P” then it is not the clients turn. This was
a relatively simple way to let the client know whose turn it is. This also means that the popups
telling the client that they are making a wrong move or its not their turn are handled on the client
side.
GameServer.java
This is where the server is started on port 3030. Every time a new client connects they are
added to the ClientHandler.
ClientHandler.java
This is where the clients are handled. Whenever a client inputs a command through the
command line it is run through here. The ClientHandler sets up a data input and output stream
with the client to receive the commands.
When a client creates a new game they are added to a list of hosts, and a new entry is added to
the list of available games. The GameHandler is not started until another client joins the game
so the client is simply waiting until then. Once a client joins another game a new GameHandler
is created in the games list, The host and guest ports are determined the same way as in
GameClient.java, where the host gets an odd port and the guest gets an even port. Once the
game is started the GameHandler takes over.
When the game finishes the host will send out the “over” command when the ClientHandler
receives this it increments counter by 1. The gameID increases for every new game and does
not reset. When the client calls the list: command it looks at the available list and sends them
out.
GameHandler.java
The GameHandler takes in the address and ports of the client and guests. Both clients should
be waiting for a connection so the GameHandler will connect to both of them and start the game
by creating a new Othello(). The GameHandler will then send the initial boardstate to both
clients in the form of a string that will be parsed. The GameHandler sends the game status
“0”(game not over) along with the board state with possible moves to the host(since they go
first) and the normal board state to the guest(since its not their turn)
Then the driver() is called in a while(true) loop until the game is over. The driver reads in the line
from whoevers turn it is and parses the input. The GameHandler then places the disk in that
spot, flips the turn, and then sends out the updated board to the host and guest. The player
whose turn it is gets the board with possible moves. Once the game status is not 0 isOver is set
to true which ends the while loop and ends the game. The GameHandler then disconnects while
the clients are disconnecting and the GameHandler ends.
Problems Encountered:
On the GUI side, there weren’t many issues to account for other than remembering how to
make a GUI in java. The game logic wasn’t too bad as both of us have coded similar projects in
the past that dealt with Othello in general. We also were initially going to be doing this project
with more students, but after trying to get in touch with them for a few days and not getting
prompt responses, we decided to go ahead with this project by ourselves.
There were a few strange problems I’ve never encountered before. I had multiple instances
where the program would work fine while in debug mode, but not work while running normally. I
assume this has to do with threads and the timing of things. I was able to figure out one of the
earlier problems with this by changing the order some things connected in. But there is a
remaining bug where if you press the “X” in the gui the command line will not continue so you
have to ctrl+c out of it, I am not sure why.
I also had some problems with just getting everything to connect to the right ports and making
sure there were no overlapping ports, as you can see I ended up with a slightly complicated
looking solution of determining which port to connect to using the gameID the host connects to
port: 3030+ (gameID*2)+1, and the guest connects to port: 3030+((gameID+1)*2)), This just
ensure that the host is connecting to odd numbers and the host is connecting to even numbers
so that the ports will never overlap no matter how many games are created(until we run out of
ports of course)
Overall there were just a lot of problems trying to get everything to connect and work properly as
this is just a fairly large project. I had problems with the Othello.java class as well that I created
a Driver.java class to use for debug purposes so that I didn't have to go through the trouble of
connecting to the server every time I wanted to test things.