5,448,104 members and growing! (15,924 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Game Development » Games     Intermediate

C# TicTacToe with AI and network support

By Daniel Carvalho Liedke

A TicTacToe game written in C# with AI and network support
C#, Windows, .NET 1.1, .NETVisual Studio, VS.NET2003, Dev

Posted: 30 Mar 2004
Updated: 30 Mar 2004
Views: 43,203
Bookmarked: 26 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
15 votes for this Article.
Popularity: 3.79 Rating: 3.22 out of 5
3 votes, 20.0%
1
2 votes, 13.3%
2
0 votes, 0.0%
3
2 votes, 13.3%
4
8 votes, 53.3%
5

TicTacToe

Introduction

This is an example of a Tic Tac Toe game with AI and network support, written in C#. It is possible to play against the computer and against another player. There are three levels of difficulty when playing against the computer. When playing against another player, it is possible to play local or over a LAN or Internet (it uses TCP sockets for communication). The control can be either by mouse or keyboard, using the NumPad or QWE, ASD, ZXC keys.

AI support

I tried to implement AI the best way I could, even with a long code. It tries to win the game at first, preventing the other player to win, and then tries to make a move avoiding "traps" and putting two computer pieces in a row. If none of this is possible, a random move is made, first trying on the corners and then on the sides. I implemented the level of difficulty by not processing the defensive move routine every time if the difficulty was set to easy or average.

Network support

Network support for a two-player game over a network was implemented using TcpListener and TcpClient classes for TCP sockets communication. The protocol for communication is really simple, a two-bytes packet: first byte indicating the row and second byte indicating the column. There is also a control packet with the first byte 'R' that controls game restart. Both client and server can restart the game anytime.

Here is a code snippet of the thread for receiving data in the server:

private void ThreadReceivingServer()
{
    //________________________________________________________________________

    //

    // Thread for receiving packets from client

    //________________________________________________________________________


    try 
    {
        byte[] buf = new byte[512];
        IPHostEntry localHostEntry = Dns.GetHostByName(Dns.GetHostName());
        int bytesReceived=0;

        tcpListener = new TcpListener(localHostEntry.AddressList[0],SERVERPORT);

        tcpListener.Start();

        //____________________________________________________________________

        //

        // Thread is blocked until it gets a connection from client

        //____________________________________________________________________


        soTcpServer = tcpListener.AcceptSocket();

        serverSockStream = new NetworkStream(soTcpServer);

        objTicTacToe.RestartGame();
        objTicTacToe.SetStatusMessage("Connected!");

        wReceivingServer=true;

        while (wReceivingServer)
        {

            //________________________________________________________________

            //

            // Thread is blocked until receives data

            //________________________________________________________________


            try 
            {
                bytesReceived=serverSockStream.Read(buf,0,2);
            }
            catch
            {
                return;
            }

            //________________________________________________________________

            //

            // Processes network packet

            //________________________________________________________________


            if (bytesReceived>0) 
            {

                //____________________________________________________________

                //

                // Control packet for game restart

                //____________________________________________________________


                if (buf[0]==byte.Parse(Asc("R").ToString()))
                {
                    objTicTacToe.RestartGame();
                    continue;
                }

                //____________________________________________________________

                //

                // Packet indicating a game move

                //____________________________________________________________


                int wRow=int.Parse(Convert.ToChar(buf[0]).ToString());
                int wColumn=int.Parse(Convert.ToChar(buf[1]).ToString());

                if ((wRow>0 && wRow<4) && (wColumn>0 && wColumn<4))
                {
                    objTicTacToe.wNetworkPlay=true;
                    objTicTacToe.MakeMove(wRow,wColumn);
                }

            }    //if (bytesReceived>0) 

    
        }    //while (wReceivingServer)

    }
    catch (ThreadAbortException) {}
    catch (Exception ex)
    {
        MessageBox.Show("An error ocurred: " + ex.Message + "\n" + ex.StackTrace);
        objTicTacToe.mnDisconnect_Click(null,null);
        return;
    }
}

Here is the code snippet for sending a game move over the network:

public void SendMove(int wRow,int wColumn)
{
    //________________________________________________________________________

    //

    // Sends packet that shows move position

    //________________________________________________________________________


    byte[] buf = new byte[2];
    buf[0]=byte.Parse(Asc(wRow.ToString()).ToString());
    buf[1]=byte.Parse(Asc(wColumn.ToString()).ToString());

    SendPacketTCP(buf);

}

public void SendPacketTCP(Byte[] pDados)
{
    //_________________________________________________________________________

    //

    // Sends a packet via TCP

    //_________________________________________________________________________


    try
    {
        if (objTicTacToe.wClient==true)
        {
            if (clientSockStream==null)
                return;

            if (clientSockStream.CanWrite)
            {
                clientSockStream.Write(pDados, 0, 2);
                clientSockStream.Flush();
            }
        }
        else
        {
            if (serverSockStream==null)
                return;

            if (serverSockStream.CanWrite)
            {
                serverSockStream.Write(pDados,0, 2);
                serverSockStream.Flush();
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("An error ocurred: " + ex.Message + "\n" + ex.StackTrace);
        objTicTacToe.mnDisconnect_Click(null,null);
        return;
    }

}

Points of Interest

I had some problems while doing this project. The first one was doing the simple line that shows the winner. I tried drawing a line in the game form, but the PictureBoxes were redrawn after I draw the line. I tried drawing in the PictureBoxes but the code was too extensive and the result wasn't good. So I had the idea of capturing game screen with GDI32.dll BitBlt function, putting the image in a big PictureBox and simply drawing the line over this PictureBox.

The other problem, I had took some time to solve. I had the client and server thread to show the big PictureBox when there was a winner. But when I used picWinner.Visible=True the program got unstable and froze. I researched a lot and found out that only the form's thread can update de UI and no other thread. So I had to use Control.Invoke to update the visibility of the PictureBox:

//_____________________________________________________________________________

//

// Show the picure using Invoke because of socket thread 

// (locks the game if you set picWinner.Visible=True)

//_____________________________________________________________________________


object[] p = new object[1];
p[0] = picWinner;
picWinner.Invoke(new MakeVisibleHandler(MakeVisible), p);

public delegate void MakeVisibleHandler(Control control);

public void MakeVisible(Control control)
{
    //_________________________________________________________________________

    //

    // Make changes to UI using Invoke because of socket thread

    //_________________________________________________________________________


    control.Visible = true;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Daniel Carvalho Liedke


I work with development for 15 years now, since MSX basic. Started Windows programming with VB 2.0 and Web programming with ASP 3.0. Now I build Windows Forms, Web Applications and NT services using Microsoft.NET. I am MCP in Visual Basic 6.0, MCAD and MCSD.NET in Framework 1.1 and MCTS Web in Framework 2.0. Besides programming I love surfing.
Occupation: Web Developer
Location: Brazil Brazil

Other popular Game Development articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 8 of 8 (Total in Forum: 8) (Refresh)FirstPrevNext
Subject  Author Date 
General[Message Deleted]memberDanny Rodriguez10:12 27 Jan '08  
Questionplzzz i need help..help me pleasemembersabrysoft8:30 23 Nov '07  
GeneralAI?memberleppie7:28 31 Mar '04  
GeneralRe: AI?memberDaniel Carvalho Liedke7:59 31 Mar '04  
GeneralRe: AI?memberRui Dias Lopes8:24 31 Mar '04  
GeneralRe: AI?memberDaniel Carvalho Liedke8:41 31 Mar '04  
GeneralRe: AI?memberDevelopStuff9:13 31 Mar '04  
GeneralRe: AI?memberThe_Grand_Inquisitor9:50 23 Feb '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 30 Mar 2004
Editor: Smitha Vijayan
Copyright 2004 by Daniel Carvalho Liedke
Everything else Copyright © CodeProject, 1999-2008
Web16 | Advertise on the Code Project