Our project was to sucessfully write and implement a client/server Scrabble game. The Scrabble game is based on the Milton Bradley game by the same name where the object is to form interlocking words in a crossword fashion on the Scrabble board using letter tiles of different values. Each players is competing for the highest score by taking advantage of the letter values, as well as the premium squares on the board. The players will all log on with a unique identity and maintain that login for the duration of the game. There must be at least two people and at most four people playing the game. The user will place a word on the board by clicking the mouse on the desired position on the Scrabble board. A window will pop up where the user can type in the desired word and also specify which direction he/she wants the letters to flow in (either in the top down direction or in the left right direction, the only two direction flows a word can be placed in). The project was broken down into three different parts, a client side, a server side, and a side that takes care of all the logic involved with handling the words and deciding whether they are valid or not. The server will be written in C on the Sun Sparc platform being OS independent. The client side will be written in Java. The logic portion of the project will be written in C.
On the client end, we had a total of 4 different GUI's designed. We designed a login GUI, a Scrabble Board GUI, a word layout GUI, and then finally an error messages GUI. The login GUI is there simply to define a name for the user to be known throughout the game. It's not necessary for the user to have either a username or password on the system. The second GUI is the Scrabble Board GUI. It is the most complex out of all the GUI's and contains the playing board as well as the chat screen and the player's score. The third GUI is the word layout GUI, which is a user interface for the player to type in the word that he wants to submit. Our Scrabble board will require the user to click a button on the square he/she wants to place the BEGINING of the word. This will then pop up a screen on which the user will type in the word itself, and also specify which direction the word will flow in (i.e. from up to down or from left to right, the only directions that a word can be placed on our board). From there, the word and it's direction will be sent to the server to check it's validity and also to determine if there has been a collision with any other words. The last GUI we are implementing is a simple error message GUI where error messages will display if the user makes a mistake. All of the client code has been packaged together under the package name "Client".
We first started out by designing the Scrabble board and how we would want it to look. The board has 15*15 squares with special scores on certain strategic spots. We decided that the easiest way to display the scrabble board would be to draw the entire scrabble board out and paint it the colors that we would want. Then, to figure out where on the Scrabble board the users was clicking on (to place tiles), we used a series of MouseDown actions that determine the x and y locations of the mouse, and then decide where on the board that x and y location is. Once we got down with the Scrabble side of the board, we turned our focus to the Chat Window. We wanted a little window so that the user could chat back and forth with other players on the team. At this point, we discovered the need to thread the replies that the client was receiving from the server because otherwise, the client would freeze up while waiting for the server to send a reply. The chat box to display other players' message was a TextArea with scroll bars, while the chat box to send out messages from the player was a TextField. A score board was then added as well as some buttons on the bottom of the screen. In order to find an appropriate layout for the frame, I decided to use a series of panels. Each little sub-section would lie within their own panel, while would be within another panel, and then so on until they were incorporated into the final main panel. I used Border Layout, Grid Layout, and Flow Layout in some of the different sections in order to achieve a certain effect. The other GUI's were simple GUI's written to display certain information using mainly Text Fields, Labels, and Buttons.
The project uses a client-server method to handle the networkind issues.
The server was written in C. The first thing the server does is set up a
socket to listen to. Once the socket is set up, it listens for new
connections. Once connections have been made, the server will use a
polling method to listen to the various connections for incoming messages,
or the socket for incoming connections. It uses the select() system call
to do this. The select() function will put the CPU to sleep, and once
incoming messages or connections have been made, it wakes up the CPU and
sets a bit in an integer array to signify which file descriptor received
new information. The server then searches through all the current file
descriptors and finds any descriptors that have new information. If the
file descriptor belongs to a player, it knows that it is a message passed
to the server from a client, or the player associated with the descriptor
has logged off. The incoming message is then parsed. All messages have
the format:
opcode:arguments
The server then takes the apropriate actions based on the opcode. Here are
the meanings of a few different opcodes:
1: Set name
2: Set play now flag for player
3: Chat message
4: Place a word
5: Challenge recent word
6: Trade tiles
Once enough connections have been made to play a game, the server will
create a child process which is an exact copy of itself using the fork()
system call. The child process will handle all client-server interactions
for that game. The parent process will then listen for new connections for
a new game.
The only time the server will send out messages is after it has read something in. The client does not have this synchronized messaging method available to it. Specifically, the client may receive information from the server whether or not it has written a message to the server. One clear example of this is the chat window. Many messages can come in for the player to read without the player having sent out a single message. In order to accomidate this asynchronous behaviour, a special networking class had to be created.
The new networking class needed to run on its own thread. It basically
consists of a loop where the thread reads off new incoming messages from
the socket. Once a new incoming message has been read, the thread will
pass the message back to the Scrabble class for parsing and where the
apropriate actions are taken. It then goes back and listens for more
incoming messages. Incoming message have the same format as mention above,
and the opcodes were designed to take on the same type of meaning. A
typical chat message would be handled by the network class in the following
manner:
1) Read new incoming message from the socket (3:Hello World)
2) Pass message to Scrabble class where it is parsed.
3) The message has been identified as a chat message, therefore print the
string sent with the message in the chat window
4) Wait for new message
The main resource used to create the server code was UNIX Network
Programming by W. Richard Stevens. The resources for the client
networking were the required and recommended textbooks for the class.
server.c
game.c
Part of the random tile generator code:
int Random_Tile(int *letter_is, int j) { int rn = 0; /*RANDOM NUMBER*/ int found = 0; /*ARRAY PLACE TRACKER*/ rn = rand(); rn = rn%MAX_TILES; while(counter[found] != 0){ /*GETS RANDOM NUMBER*/ { if (rn>=0 && rn<9){ *letter_is = A_LETTER; found = rn; } .................................................. EDITED OUT TO CONSERVE SPACE ................................................. if (rn>=98 && rn<100){ *letter_is = BLANK_LETTER; found = rn; } } if (counter[found] == 0) /*CHECKS TO SEE IF RN WAS CHOSEN ALREADY*/ Random_Tile (letter_is,j); counter[found] = 0; /*NEW RN FOUND!!! REPLACES 1 WITH A 0 IN ARY*/ T_board[j] = found; }/*END OF while(counter[found]!=0)*/ Players_Sideboard[j] = *letter_is + 96; found = MAX_TILES+1; /*SO WE CAN RUN THE LOOP AGAIN =)*/ }/*END OF Random_Tile()*/
Part of the tile placement code:
void Tile_Placement(int Down_or_Right, char *Players_Sideboard, int x, int y, char *word) { count = strlen(word); for(l = 0; l < count; l++){ for(p = 0; p < 7; p++) if (word[l] == Players_Sideboard[p]){ Tile_Num = p; break; } if(Tile_Num < 7) { if (m==0) U_board[l] = Players_Sideboard[Tile_Num]; else U_board[l+m] = Players_Sideboard[Tile_Num]; if(Scrabble_board_CHAR[x][y] == '_') { if(m==0) { Scrabble_board_CHAR[x][y] = U_board[l]; if(Down_or_Right == 0) x++; else y++; } .................................................. EDITED OUT TO CONSERVE SPACE ................................................. else{ printf("YOUR WORD IS NOT VALID!!\n"); break; } j = Tile_Num; Random_Tile (letter_is,j); } count = 0; m = 0; }/*END OF void Tile_Placement(int Down_or_Right, char *Players_Sideboard, int x, int y, char *word)*/