Word Building Network Game With Intelligence






3.36/5 (8 votes)
Feb 7, 2005
5 min read

48983

2194
Word building game using C#.
Introduction
The word building game is a well known game all over the world. It is also called as scrabble. In this network-supported game, four players can play the game together sharing the same matrix board. Players can join their corresponding opponents directly by searching. I have used UDP sockets for searching the hosted game and TCP sockets for game processing. This game can be played within the subnet.
This network-supported game is intelligent. A player cannot fool the game by submitting non-English words. This game uses an English word list of around 55903 words. HashTable
of C# is used for this implementation. This data structure is used to store the words. The game performs lookup operation when a player submits the word. New words can be added in wordlist.txt file present in the bin folder. The network infrastructure developed in this game is general purpose. Any game can use this underlying network infrastructure. I have added Howtoplay.pdf file for the instructions to play the game.
Game
In general, this game is a two-player game. Like all other games, these two players will have turns to put a single English alphabet in the given matrix of boxes so that they can form an English word in vertical direction or horizontal direction. Each player will get points equal to the length of the English word they form. Finally, the player with more points will win the game.
Game roles
After hosting or joining the game, the game instance can run one of the following roles:
- Server Role
- Client Role
- Client Inactive Role
Server Role
The game will enter this role once it hosts the game. In this role, the client will act as a server where it will perform three tasks. First, it will listen for clients searching for an active host and reply to them with an acknowledgement message informing them of its presence. Second, it will wait for clients to request for joining the game. Once it receives the join request, it will process this request and it will reply to the sender with an acceptance message that has some needed information. Third, it will initialize and start the game by sending every client a special message notifying them about the game start event along with some other information to initialize the game state. The game will exit this role once it starts the game.
The following code snippet is a thread that will handle this role.
private static void TcpServerRole()
{
// start a TCP listener
ServerListener = new TcpListener(GamePort);
ServerListener.Start();
//declare some variables
Socket ss ; //server socket
NetworkStream ns ;
StreamReader sr;
StreamWriter sw;
string IncomingMessage ;
while (true)
{
// wait for incoming messages
ss = ServerListener.AcceptSocket();
// create network, reader and writer streams
ns = new NetworkStream(ss);
sr = new StreamReader(ns);
sw = new StreamWriter (ns);
IPAddress ip;
// read the incoming message
IncomingMessage = sr.ReadLine();
// ((Type 1))
// request for total number of connected players
if (IncomingMessage=="NumberOfPlayers?")
{
// reply with the number of players
sw.WriteLine(Game.ConnectedPlayers.Count.ToString());
sw.Flush();
}
// ((Type 2))
// request for all connected players
if (IncomingMessage=="Players?")
{
// loop over all connectd players
for ( int i=0 ; i < Game.ConnectedPlayers.Count ; i++)
{
// send the player object
sw.WriteLine(Game.ConnectedPlayers[i].ToString());
sw.Flush();
// send the player IP Address
sw.WriteLine(ClientsAddresses[i].ToString());
sw.Flush();
}
}
// ((Type 3))
// request to join the game
if (IncomingMessage.StartsWith("Join"))
{
// get the player string by removing un-needed part
string PlayerStr = IncomingMessage.Remove(0,4);
// get the client (new player) IP Address
ip = ((IPEndPoint)ss.RemoteEndPoint).Address;
// send back the client, the Turn Index
sw.WriteLine(Game.ConnectedPlayers.Count);
sw.Flush();
// add the new player IP Address
ClientsAddresses.Add(ip);
// Add the new player to connected players
Game.ConnectedPlayers.Add(Game.ConvertStringToPlayer(PlayerStr));
// update all other clients of the new player
NewClientUpdateOthers(PlayerStr,ip);
}
// close the socket, end of request
ss.Close();
} //end while
}
Client Role
The game will enter this role by two ways: either by starting the game where it will switch from server role, or by receiving the turn message (the turn message notifies the client that it is his/her turn to play). In this role, the client can do two tasks. The first task is to receive the played action from the game and then send it to all other clients to update their internal game state. The second task is to pass the turn to the next player once the current player finishes his/her turn.
Inactive Client Role
This role is the entry role for clients joining the game. The game will also enter this role once it is finished playing and has passed the turn to the next player. In this role, the client will wait for update messages that can be one of the following:
- New player joined the game
- Game has started, initialize your state
- New action
- It is your turn
Once clients join the game, they will wait to receive a new player update message. This message will contain both the new player object along with the IP address, thus enabling the clients to update their player list. Also, clients will need to initialize their game state according to the "Start Game" update message. Once the player list is complete and the game state is initialized, the clients are ready to receive new actions played by the current player in order to update their game states as needed. The client will switch to Client role once it receives "Your Turn" message which indicates the current player has finished playing and it is now your turn to play.
Following code snippet will handle this role:
private static void UnactiveClient()
{
// set the port that I will listen to
int port = GamePort + Game.MyTurnIndex ;
// create a TCP Listener
TcpListener Client = new TcpListener(port);
Client.Start(); // start listening
// define variables
TcpClient cs ;
NetworkStream ns ;
StreamReader sr;
string update;
bool MyTurnFlag = true;
// loop until you receive your turn
while (MyTurnFlag)
{
// wait for updates
cs = Client.AcceptTcpClient();
// create network & reader streams
ns = cs.GetStream();
sr = new StreamReader(ns);
// read the update
update = sr.ReadLine();
// string array to deal with the update
string[] updateMsg;
// is it a NEW PLAYER Update Message
if (update.StartsWith("New Player -->"))
{
// remove first part (Length of NewPlayer --> is 14)
update = update.Remove(0,14);
// add the new player object
Game.ConnectedPlayers.Add(Game.ConvertStringToPlayer(update));
// reads the new player IP Address
update = sr.ReadLine();
// add the new player IP Address to Address List
ClientsAddresses.Add(update);
// close the socket
cs.Close();
}
// is it a Game Start Update Message
else if(update.StartsWith("Start Game-->"))
{
// A received message can be "Start Game-->5#2
// Upto 5#2 everything is removed
// 5 is the number of columns
// 2 is the number of rows
//remove unneeded info.
update = update.Remove(0,13);
string[] rowcol = update.Split(new char[] {'#'});
int row = Convert.ToInt32(rowcol[0]);
int col = Convert.ToInt32(rowcol[1]);
// These values will be used by MatrixDisplay function
form.row = row;
form.col = col;
Game.IsGameStarted = true; // game state is started
// close the client
cs.Close();
// display matrix on the user form
form.Invoke(new displayMethod(form.MatrixDisplay),null);
}
else if ( update.StartsWith("alphabet"))
{
// Example alphabet-10-10-a#colour#
string x1s;
string y1s;
int index;
index = update.IndexOf("-");
update = update.Remove(0,index+1);
index = update.IndexOf("-");
x1s = update.Substring(0,index);
update = update.Remove(0,index+1);
index = update.IndexOf("-");
y1s = update.Substring(0,index);
string update1 = update.Remove(0,index+1);
update1 = update1.Substring(0,1);
index = update.IndexOf("#");
string colour = update.Remove(0,index+1);
colour = colour.TrimEnd('#');
// pass the parameters to DisplayAlphaBet method
// This function displays the alphabet
form.DisplayAlphaBet(Convert.ToInt32(x1s),
Convert.ToInt32(y1s), update1,colour);
cs.Close();
}
else if(update.StartsWith("Game Over"))
{
string[] ln = update.Split(new char[] {'#'});
ln[0] = ln[0].Remove(0,9);
MessageBox.Show(ln[0] + " Won the game " + "Score:" + ln[1]);
cs.Close();
}
else if (update.StartsWith("word"))
{
int index;
string Stringtemp1;
string Stringtemp2;
Stringtemp1 = update;
Stringtemp2 = update;
// index extraction
index = Stringtemp1.IndexOf("#");
Stringtemp1 = Stringtemp1.Remove(0,index+1);
index = Stringtemp1.IndexOf("@");
Stringtemp1 = Stringtemp1.Substring(0,index);
int LabelIndex = Convert.ToInt32(Stringtemp1);
index = Stringtemp2.IndexOf("@");
Stringtemp2 = Stringtemp2.Remove(0,index+1);
int LabelScore = Convert.ToInt32(Stringtemp2);
index = 0;
index = update.IndexOf("#");
update = update.Substring(0,index);
index = 0;
ArrayList xs = new ArrayList();
ArrayList ys = new ArrayList();
index = update.IndexOf("-");
update = update.Remove(0,index+1);
index = update.IndexOf("W");
string coordinates = update.Substring(0,index);
update = update.Remove(0,index+1);
index = update.IndexOf("-");
update = update.Remove(0,index+1);
string[] ln = coordinates.Split(new char[] {'-'});
for (int i=0;i < ln.Length;i+=2)
xs.Add(ln[i]);
for (int i=1;i < ln.Length;i+=2)
ys.Add(ln[i]);
form.DisplayColour(xs,ys,update,LabelIndex,LabelScore);
cs.Close();
}
// is it a Your Turn Message
else if (update.StartsWith("TURN"))
{
Game.MyTurn = true; // Set my turn
MyTurnFlag = false; // exit from this state
cs.Close(); // close the socket
Client.Stop(); // stop client mode; do not listen for updates
// Current player is the local Player
Game.CurrentPlayerObj = Game.LocalPlayer;
}
else //ignore other messages
cs.Close();
} // End of while(true) statement
}
Diagrammatic view
When a user clicks the Host button, three threads will be started. Under Form1.cs class, a thread called as UpdateThread
is started. This thread takes the information from ICommon
interface and updates the information to the user interface form. UdpServerRole
thread listens for UDP broadcast messages and acknowledges with the IP address of the machine where the game is hosted.
TcpServerRole
deals with network messaging. It receives the messages from the network and responds to them and also updates to the interface ICommon
. When a user clicks the Start Game button, TcpServerRole
and UdpServerRole
threads will be stopped and the main user will do some action. The following figures show a nice multi-threading environment.
When a user clicks the Join button, UpdateThread
and ClientThread
start executing. ClientThread
is a general purpose thread. When a user joins the game or loses his turn, this thread will run. It accepts New player, Start Game, Alphabet, Game Over, Word, and Turn messages from the network and updates to the interface ICommon
.
Limitations
- Only four players can play.
- Cannot play if behind a firewall or a NAT.
- Players must agree before playing in order for them to know their IPs.
- Since it is implemented in C#, it will not run on machines without .NET runtime environment.
Conclusion
In this article, a general-purpose network infrastructure is presented. Any game that is similar to the implemented word building game can be plugged into this infrastructure. The article serves as a re-usable component in other developments.
Acknowledgment
This game implementation is a course project for course ICS-571 (Information and Computer Science) namely Client/Server programming, taught by Assistant Professor Nasir Al-Darwish at King Fahad University of Petroleum and Minerals, Kingdom of Saudi Arabia, Dhahran. His email address is darwish@kfupm.edu.sa. From this course, many new concepts have been learned and implemented.