Click here to Skip to main content
15,878,953 members
Articles / Programming Languages / C#

C# TicTacToe with AI and network support

Rate me:
Please Sign up or sign in to vote.
4.54/5 (26 votes)
30 Mar 2004CPOL2 min read 147K   6.8K   46   29
A TicTacToe game written in C# with AI and network support

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:

C#
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:

C#
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:

C#
//_____________________________________________________________________________
//
// 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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Brazil Brazil
I started development 37 years from now, since MSX basic. Started Windows programming with VB 2.0 and Web programming with ASP 3.0. Then I built Windows Forms, Web Applications, NT services and WPF applications using Microsoft.NET. I am MCP in Visual Basic 6.0, MCAD and MCSD.NET in Framework 1.1, MCPD Web in Framework 2.0, MCTS in .NET 3.5 workflow, MCTS in .NET 3.5 communication foundation, windows presentation foundation and MVC applications. Built MVC Web Application and WCF services using Micro Services architecture proposed by me. Working with AI projects to improve the business performance and customer experience. Besides programming I love running, swimming, reading and movies.

Comments and Discussions

 
QuestionCross thread operation not valid Pin
Member 1046309412-Dec-13 10:39
Member 1046309412-Dec-13 10:39 
QuestionRe: Cross thread operation not valid Pin
Hasan mohsin18-Apr-14 5:25
Hasan mohsin18-Apr-14 5:25 
AnswerRe: Cross thread operation not valid Pin
Daniel Liedke18-Apr-14 5:37
professionalDaniel Liedke18-Apr-14 5:37 
AnswerRe: Cross thread operation not valid Pin
Member 1046309419-Apr-14 11:29
Member 1046309419-Apr-14 11:29 
GeneralRe: Cross thread operation not valid Pin
Daniel Liedke19-Apr-14 12:09
professionalDaniel Liedke19-Apr-14 12:09 
GeneralMy vote of 5 Pin
Member 1027535615-Sep-13 4:55
Member 1027535615-Sep-13 4:55 
QuestionNetwork Problem Pin
Member 964290430-Apr-13 12:56
Member 964290430-Apr-13 12:56 
AnswerRe: Network Problem Pin
Daniel Liedke3-May-13 4:03
professionalDaniel Liedke3-May-13 4:03 
AnswerRe: Network Problem Pin
Member 1046309412-Dec-13 9:45
Member 1046309412-Dec-13 9:45 
QuestionHow did you make it portable? Pin
Shaharyar Ahmed14-Feb-13 7:07
Shaharyar Ahmed14-Feb-13 7:07 
AnswerRe: How did you make it portable? Pin
Daniel Liedke3-May-13 4:09
professionalDaniel Liedke3-May-13 4:09 
Questionserver name Pin
Shaharyar Ahmed14-Jan-13 8:21
Shaharyar Ahmed14-Jan-13 8:21 
AnswerRe: server name Pin
Daniel Liedke15-Jan-13 9:57
professionalDaniel Liedke15-Jan-13 9:57 
GeneralNETWORK SUPPORT & others . . Pin
kimvaldez217-Mar-11 6:40
kimvaldez217-Mar-11 6:40 
GeneralRe: NETWORK SUPPORT & others . . Pin
Daniel Liedke9-Mar-11 8:23
professionalDaniel Liedke9-Mar-11 8:23 
Questionhow do you solve who makes move first? Pin
Bilg218-Nov-09 20:03
Bilg218-Nov-09 20:03 
AnswerRe: how do you solve who makes move first? Pin
Daniel Liedke9-Nov-09 0:00
professionalDaniel Liedke9-Nov-09 0:00 
GeneralDoubt Pin
freshers5-Feb-09 20:02
freshers5-Feb-09 20:02 
GeneralRe: Doubt Pin
Daniel Liedke11-Feb-09 7:05
professionalDaniel Liedke11-Feb-09 7:05 
Generalpls help me Pin
xeric_silip8-Jan-09 20:34
xeric_silip8-Jan-09 20:34 
can you make simple tictactoe ai program using visual 6.0?... thnx pls post it asap...
GeneralRe: pls help me Pin
Daniel Liedke9-Jan-09 3:26
professionalDaniel Liedke9-Jan-09 3:26 
General[Message Deleted] Pin
Danny Rodriguez27-Jan-08 9:12
Danny Rodriguez27-Jan-08 9:12 
Questionplzzz i need help..help me please Pin
Sabrysoft23-Nov-07 7:30
Sabrysoft23-Nov-07 7:30 
QuestionAI? Pin
leppie31-Mar-04 6:28
leppie31-Mar-04 6:28 
AnswerRe: AI? Pin
Daniel Liedke31-Mar-04 6:59
professionalDaniel Liedke31-Mar-04 6:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.