CSE310 Course project (phyton)
CSE310 Course project
Design and implement an online modified version of the game Tic-Tac-Toe using Internet domain
sockets. It includes both a game client program and a game server program, these two programs
communicate with each other using your own application-layer protocol. Two players can each run
the client program to login to a game server and to play a game with each other.
In addition to a single game, you will also implement the support for multiple concurrent games.
Two bonus tasks are support for observing games and making comments. The former involves
sending game states to all observers, the latter involves concurrent client that can handle input from
the server and input from a user at the same time.
At the time of submission, state at the beginning of your documentation which tasks above you are
able to complete.
The Modified Tic-Tac-Toc Game
Modified Tic-Tac-Toc is a board game played between two players. The game board is a 3 by 3 grid
consisting of nine cells. The player who moves first uses X shaped pieces and the other player uses
O shaped pieces.
The two players take turns placing one of their game pieces into an unoccupied cell. The first player
to form a row, column, or diagonal with 3 of his pieces is the loser. So the object of the game is to
force the opponent into completing 3 in a row.
An example game is as follows:
. . X . . X . . X O . X O . X O . X O X X O X X O X X
. . . . . . . X . . X . . X . . X O . X O . X O X X O
. . . O . . O . . O . . O . X O . X O . X O O X O O X
The game ends in a draw.
Building a single game using the stream sockets
In the first part of the project, there is a game server that supports just one game. At most two
players will login at the server and play. At any time, each player is either "available" or "busy". A
player always starts with state "available". When a player is playing a game, his state is "busy". The
server is started first and waits at a known port for requests from game clients. The port number that
the server listens at can be hard-coded, or can be output to the standard output from your program
and used when starting client programs. The client program takes two inputs via command line
arguments: (i) the name of the machine on which the server program is running, (ii) the port number
that the server is listening at.
Once the client program is started, say, by you, the following commands should be supported:
help: this command takes no argument. It prints a list of supported commands, which are ones in
this list. For each command, it prints a brief description of the command function and the syntax
of usage.
login: this command takes one argument, your name. A player name is a userid that uniquely
identifies a player. Your name is entered with this command and is sent to the server. The server
keeps track of the location of each logged-in player for upcoming message exchanges. Upon
receiving a login message, the server records this player in the initial state of "available". For
simplicity, no authentication, e.g., via entering a password, is required.
place: this command issues a move. It takes one argument n, which is between 1 and 9 inclusive.
It identify a cell that the player chooses to occupy at this move.
Upon receiving a move, the server checks if it is the player's turn. If so, it checks if the move is
legal, i.e., if the indicated cell is unoccupied. If it is not the sender's turn or if the move is illegal,
the server replies the sender indicating errors. The sender can then re-issue a move.
If all is well, the new game state is calculated and sent to both players. If 3 in a row is formed,
the winner is congratulated and the loser is so informed. If a move takes the last cell without any
3 in a row, the game is a draw, both players are so informed. In both cases, a game is done. Both
players' states become "available".
exit: the player exits the server. It takes no argument. A player can issue this command at any
time. After being notified, the server will always acknowledge it, and remove this player from its
record. If the player state is currently "busy", the server will inform the other player the game is
stopped and change the state of the other player to "available"; the other player can issue an
"exit" to exit or wait to start a new game. Once this command is acknowledged by the server, the
client program exits.
After a player logs in, if there is currently no other player logged in, the server informs the sender to
wait a moment. If another player is currently logged in, the server starts a new game between them,
setting their status to "busy". Each player is told the userid of the other player.
When starting a game, the player who logged in first gets to play first. The game state is defined by
the current board positions and the turn indicating who is to play next. Game state is maintained by
the server and sent to both players initially and after every move. When a game finishes, both
players' status remains "busy" while the server automatically starts a new game between them.
Each above command invokes message exchanges between the client and the server except for the
first command. The protocol for the communication between the client and server, including the
types of messages, the syntax and semantics of each type of message, and the actions taken when
each type of message is sent and received at each party, needs to be designed and specified by you.
You can refer to the HTTP protocol (RFC2616) and use formats similar to the HTTP request and
response messages (Slides 2-26 to 2-31) for the types of messages that you define for this project.
For example, you can use methods such as "LOGIN", "PLACE", "EXIT" in the method field of the
message that is sent to the server. The player userid and player address can be put in subsequent
fields of the same message.
Each message sent to the server should be properly acknowledged by way of response messages.
Status code similar to that in the HTTP response messages should be used. At least two status codes
and corresponding phrases: 200 OK and 400 ERROR, should be implemented. You are encouraged
to define other more explicit status codes and phrases. The protocol that you define must be clearly
specified in the written documentation described below. As indicated, the server needs to maintain
state of the logged-in players and the state of the game if the game is on-going. You are free to
decide how to maintain this state at the server.
Building multiple games
In this second part of the project, there can be multiple games that are ongoing at the game server.
Each game has a unique numerical ID assigned by the server. The game server is first started, and
listens at a known TCP port. The machine name and port number can be conveyed to the clients in a
similar way to that in the single-game case. All commands except the "help" command are the same
as before. The commands that a client can issue additionally (except "help") are as follows: help: this is similar to before, except that all commands available in both parts 1 and 2 (minus the
"help" command) should be displayed.
games: this command triggers a query sent to the server. A list of current ongoing games is
returned. For each game, the game ID and game players are listed.
who: this command has no argument. It triggers a query message that is sent to the server; a list
of players who are currently logged-in and available to play is retrieved and displayed.
play: this command takes one argument, the name of a player X you'd like to play a game with.
A message is sent to the server indicating that you'd like to play with X. After receiving this
message, if X is available, the server starts a new game between you and X. If X is not available,
the server replies you that X is no longer available. You may then choose another player instead.
After a player logs in, instead of trying to match up a game as before, the server should not attempt
to match up a game among players. Rather each game is started as the result of a "play" command.
For each new game started, the player whose "play" message initiates the game is to move first.
There are anomalous scenarios that your implementation should address. For example, if a player
invites herself or a non-existent player, an error message should be returned from the server and
displayed.
Again, the protocol (message types, syntax of each, etc.) that is used for message exchanges between
the client and server should be designed and specified by you. Each message needs to be
acknowledged, a response with at least two status codes (200 OK and 400 ERROR) should be
returned to the client. The server should endeavour to maintain the up-to-date player and game state
information. The way that the server uses to maintain its state information is also your decision. All
these need to be documented in the written documentation. You can start with just two games.
Indicate in your documentation how many games your code can support.
Bonus task 1: observing games
This part implements observation of other games. To achieve so, two additional commands that a
client may issue are defined as follows:
observe: this command takes one argument: gameID. It allows a client to observe the game
identified with gameID. The gameID can be obtained from the output of the “games” command
specified in Part 2. Each time a move in the observed game is made, the new game state is sent to
all observers as well as both players.
unobserve: this command also takes one command-line argument: the gameID. After a client
issues this command, the server checks to see if the client is observing the game gameID, if yes,
it stops sending the game state to this client. Otherwise, an error message should be returned to
the client.
For simplicity, a client may observe only one game at a time.
Bonus task 2: making comments
This part implements support for game commenting by observers. While watching a game, a game
user may make comments, which are sent to the server and broadcast to all observers of the same
game. When a comment is displayed to each observer, it must be prepended with the userid of the
user who made this remark.
You are free to define your own additional commands and protocol message types that are needed.
Concurrency and robustness
Concurrency is an important subject in Computer Science. In this project, you may implement the
first single-game part without using concurrency. The second part and the bonus tasks would require
concurrency. E.g., a client may want to simultaneously listen to input from the client user and input
from the game server. At the server side, it may manage multiple games and different game clients
may send messages to the server at the same time. Concurrency support is provided by all languages
that are allowed in this project, e.g., a single threaded program using select(), or a multithreaded
program. You may choose any support you like.
Robustness is another important aspect of a network application. E.g., while a client is waiting for
the player to make a move, the other player’s network connection is broken, or the other player exits
the game. The client can wait until the player makes a move to inform him, or can inform the player
right away. In this project, you do not need to handle extensive robustness scenarios. Instead you
should focus on the basic operations mainly.
Development
You may implement the project using Java, C, or Python. You are free to implement any type of
player interface that you like, as long as it allows the player to issue the commands specified above.
You may run your code on the Linux machines for our socket programming labs or on Windows. In
any case, your code must be able to run on a CS Windows lab machines (locally or via ssh to allv).
Python stream socket programming was covered in Lab 2 as well as the textbook. For Java and C
socket programming, some simple example programs are provided to you on this page. You are also free to read online tutorials.
As to concurrency programming. For Python, you can refer to the presentation slides and code
samples at An Introduction to Python Concurrency, note that you only need to be concerned with Parts 3 and 4 in this tutorial. For Java, you can refer to Java tutorial for concurrency. For C, you may refer to Keir Davis et. al's book chapter, which contains information on concurrent server design. Additional concurrent programming pointers can be found again here.
On allv, you are responsible to clean up your processes that might be left around running. Orphan
processes consume extensive resources, slowing down both others' work and yours. Under Linux, to
kill a process, type "ps aux | grep your_id", where your_id is your allv login id, find the
process id(s) of the orphan processes, it is in the second column of the ps command output, type
"kill -9 pid" to kill the process with process id pid.
What to submit
Submit the following two materials separately before the due date:
(a) Well-documented source code files, together with a README.txt file
Each program should have proper program documentation in it. Program documentation is
the comments that appear in the source code to aid in the understanding of the program. They
tell what effect the code will have or to elucidate a complex statement. Do not reiterate in
English what is obvious from the code such as "variable x is incremented".
You can only submit the source code. No executable or object file is accepted. This means
before you submit, you must make a clean submit directory that has only the required files in
it. Name all Python program files with .py suffix. All Java program files with .java suffix and
all C program files with .c and .h suffix.
Submit a single .tar or .zip file that includes all source code files. In your README.txt file,
give the instructions on how to obtain the source files from the .tar or .zip file. This must be
able to be performed in the CS lab environment.
(b) A written project documentation that includes the following sections
Overview: indicate how much of the project you have completed. A brief description of the
major functionality in each part that you have implemented.
User documentation: it contains everything that the user of your program (and the marker)
needs to know to properly use the program to obtain desired results. This section does not
describe how the program works, but only what it does and how to use it. You should
describe the syntax and parameters used to run your programs, the program output (including
possible error messages), and program limitations (for example, "at most 16 games can be
ongoing at the same time").
System documentation: system documentation is for people who need to know what is going
on inside the program so they can perhaps change it or add new features. It describes the
client server communication protocol that you defined for this application; it describes how
concurrency is implemented if you have that done. It describes major data structures and
important algorithms if there are any, where to find things, error conditions, what causes
them and what happens, how to compile and generate the executables. Try to be complete but
concise.
Testing documentation: include a list of testing scenarios to convince the marker that the
program works. Explain what expected output are and what actual output are.
The written documentation should be type-set. Only pdf is accepted.
How to submit
All deliverables are to be submitted via Blackboard. You must check and make sure your assignment
has been submitted correctly before the deadline. Only one member of a group submits.
Due date
The project due date is 11:55pm, Saturday, May 6. No late submissions will be accepted.
Tentative marking scheme
30% of marks will be allocated to the protocol design and documentation, within which 20% will
be on logically structured, well documented, and easy to understand code, 80% for a clean
written documentation.
70% of marks will be allocated to the implementation. Parts 1 and 2 each accounts for roughly
65% and 35% respectively.
The two bonus tasks account for 3% and 5% of the project mark respectively.
Total: 100pts (Since the bonus tasks do not add too much to your course grade. You should place your priority on the final exam instead.)