Click here to Skip to main content
15,878,852 members
Articles / Game Development

Tic Tac Toe Implemented in C# with Computer Player

Rate me:
Please Sign up or sign in to vote.
4.22/5 (18 votes)
10 Aug 2010CPOL4 min read 157.5K   9.7K   34   43
A simple game in C# that can run on Windows, Linux(mono) and Mac(mono)

Introduction

Capture.JPGScreenshot.jpg
The game in Windows (.NET)
The Game in Linux (Mono)

This is a program for Tic Tac Toe game written in C#. It has a built in Computer Player module and can even be played in two player mode. It can be run anywhere where .NET or mono runtime is installed. The source is compatible with Visual Studio and #Develop.

Background

During my exploration of Java and C#, I found some interesting similarities and differences and ultimately learned that with study of one of them, the other one can also be learned. This program is my attempt to demonstrate the same to beginners in programming.

Using the Code

For ease of learning the program, it is divided into modules which are represented as functions in the program. Simple labels are used for display of the nine blocks involved, and corresponding code to be executed is triggered through click event of them. First, the variables used are explained as below:

  • pos: is a two dimensional array to represent the nine blocks as the operations are easy to perform on an array.
  • cnt: is a counter to track the number of moves played.
  • val: is a value corresponding to the letter. 1 for X and 4 for O. In array, the values are used instead of letters.
  • let: is to hold the letter, X or O.
  • a, b, c, d: are the integers to hold the co-ordinates of second last and last move respectively, used by computer player logic.
  • diff and vs: are used to identify difficulty level and game mode selected by the user.
  • rnd & turn: are used to generate random number and to toggle comp player mode.
  • pl1 & pl2: are used to hold the names to be displayed in status strip.

The functions with their use are as explained below:

  • reset(): This function is used to restart the game from start anytime or after win or draw is declared as well as to initialize certain components.
  • play(): This function does the work of commencing a move, thus updating the corresponding label and the array position as well as calling other functions flip() and checkwin(). It uses function link() to evaluate coordinates to corresponding labels.
  • flip(): It does the job of toggling between X and O during the moves eventually doing the same for values 1 & 4 for variables let and val respectively.
  • checkwin(): This function checks for win or draw condition after a move is played in the program. It also declares so using declare() and also manages toggle of opponents as per the rule: The first player continues to play if he wins or game draws, else the 2nd player will play first the next time.
  • compplay(): This is the computer player module which makes a computer move using the difficulty level selected by the player and calling functions winorstop() and doany() appropriately.
  • winorstop(): This function is used to play the winning move if such a situation exists as well as to stop opponents win if a losing situation exists.

The arrangement of labels and array positions are as below:

labe1label2label3 0,0 0,1 0,2
label6 label5 label41,0 1,1 1,2
label9label8 label7 2,0 2,1 2,2

The variables as well as the code for different functions is as below:

C#
int[,] pos=new int[3,3];
int cnt,val,a,b,c=1,d=1,diff=1,vs=1;
char let;
String pl1="You",pl2="Computer";
Random rnd=new Random();
bool turn=true; 
C#
void reset()
	    {
	        for (int i=0;i<3 ;i++ )
	        {
	            for (int j=0;j<3 ;j++ ){pos[i,j]=0;}  //Fill array with zeros
	        }
	        foreach(Control ctrl in this.Controls)
			{
				if (ctrl is Label) 
				{
					ctrl.ResetText();  //Clear text for 
							//all labels
				}
			}
	        cnt=0;
	        val=1;  // X->1 and O->4
	        let='X';
	        label10.Text=pl1+" to Play NOW.";  //Setting status label.
	    }
C#
bool play(int l,int m)
	    {
	        if(pos[l,m]==0)// Check to avoid overplays.
	        {
	            a=c;b=d;c=l;d=m;  //Hold coordinates of 2nd last and last moves.
	            Label ctrl=link(l,m);  //Link the coordinates to the label.
					// (used for computer player)
	            ctrl.Text=let.ToString();  //Reflecting move to screen.
	            pos[l,m]=val;  //Reflecting move in array
	            flip();  //Toggling between X and O
	            checkwin(l,m,pos[l,m]);  // Check for win or Draw situation.
	            return true;
	        }
	        else
	            return false;  //Useful if move is to be replayed.
	    }
C#
Label link(int l,int m)  //Returning appropriate label for the passed coordinates.
	    {
	        if(l==0)
	        {
	            if(m==0)
	                    return label1;
	            if(m==1)
	                    return label2;
	            if(m==2)
	                    return label3;
	        }
	        if(l==1)
	        {
	            if(m==0)
	                    return label6;
	            if(m==1)
	                    return label5;
	            if(m==2)
	                    return label4;
	        }
	        if(l==2)
	        {
	            if(m==0)
	                    return label9;
	            if(m==1)
	                    return label8;
	            if(m==2)
	                    return label7;
	        }
	        return null;
	    }
C#
void flip()   //Logic for toggle
	    {
	        if(let=='X')
	        {
	            let = 'O';
	            val=4;
	            cnt++;
	        }
	        else
	        {
	            let = 'X';
	            val=1;
	            cnt++;
	        }
	    } 
C#
void checkwin(int l,int m,int n)
       {
           if(cnt==1)
               if(vs==1)
                   turn=true;
           if(cnt>4)
           {   // Check for corresponding row first.
               if((pos[l,0]+pos[l,1]+pos[l,2]==n*3)||
               (pos[0,m]+pos[1,m]+pos[2,m]==n*3))
               {
                   cnt=n;
               }
               else
               {   //Checking for corresponding column.
                   if((pos[0,0]+pos[1,1]+pos[2,2]==n*3)||
               (pos[2,0]+pos[1,1]+pos[0,2]==n*3))
                   {
                       cnt=n;
                   }
                   else
                   {
                       if(cnt==9)
                       {   //In a draw situation.
                               cnt=0;
                       }
                   }
               }
               if(cnt==1||cnt==0)
               {  // If the first player wins or Draw occurs.
                   if(cnt==1)
                       declare(pl1+" (Playing X) Wins!");
                   if(cnt==0)
                       declare("The Game is a Draw!");
                   reset();
                   if(vs==1)
                   if(pl1=="Computer")
                   {
                       turn=false;
                       compplay(val);      //If the First player happens
                   //to be computer we need to call it.
                   }
                   else
                       turn=false;

               }
               else
               if(cnt==4)
               {
                   declare(pl2+" (Playing O) Wins!");
                   String temp=pl1;
                   pl1=pl2;
                   pl2=temp;
                   reset();
                   if(vs==1)
                   if(pl1=="Computer")
                       compplay(val);      // If the first palyer is computer,
                   // we need to call this.
                   else
                       turn=false;
               }
           }
       }

       void declare(string stmt)
       {
           if(MessageBox.Show(stmt+" Do you want to continue?",
               "",MessageBoxButtons.YesNo,MessageBoxIcon.Question)
                   !=DialogResult.Yes)
           {
               Application.Exit();     //Exit if user does
                           //not click yes.
           }
       }
C#
void compplay(int n)
	    {
	        bool carry=true;  	// Is used so that multiple moves are not played 
				// by computer.
	        if(diff==3)  	//Is called only if Hard difficulty is set.
	            carry=winorstop(a,b,n); // a & b are used so that check 
					// is performed only at last computers move.
	        if((diff==2||diff==3) && carry)  //Is called if Hard or Medium 
						// difficulty is set.
	        {// For stop require to check for opponents pieces using c & d
	            if(n==1)
	                carry=winorstop(c,d,4);
	            else
	                carry=winorstop(c,d,1);
	        }
	        if(carry)
	                doany();  // Executed in all three difficulty levels
	    }  
C#
bool winorstop(int l,int m,int n)
	    {
	        if(pos[l,0]+pos[l,1]+pos[l,2]==n*2) //check for row, 
						// if two of three are filled.
	        {
	            for(int i=0;i<3;i++)
	            {
	                if(play(l,i))
	                    return false;
	            }
	        }
	        else
	            if(pos[0,m]+pos[1,m]+pos[2,m]==n*2) //Check for column for 2/3
	            {
	                for(int i=0;i<3;i++)
	                {
	                    if(play(i,m))
	                        return false;
	                }
	            }
	            else
	                if(pos[0,0]+pos[1,1]+pos[2,2]==n*2) //Check for diagonal 
							//for 2/3 situation.
	                {
	                        for(int i=0;i<3;i++)
	                        {
	                                if(play(i,i))
	                                        return false;
	                        }
	                }
	                else
	                    if(pos[2,0]+pos[1,1]+pos[0,2]==n*2) //Check for 
						//other diagonal for 2/3 situation.

	                    {
	                            for(int i=0,j=2;i<3;i++,j--)
	                            {
	                                    if(play(i,j))
	                                            return false;
	                            }
	                    }
	
	        return true;
	    } 
C#
void doany()
	    {
	        int l=2,m=0;
	        switch(cnt)
	        {
	            case 0: play(0,0);   //First two moves are certainly played.
	                    break;       
	            case 1: if(!(play(1,1)))
	                        play(0,0);
	                    break;
	            case 2: if(!(play(2,2)))
	                        play(0,2);
	                    break;
	            case 3: if((pos[0,1]+pos[1,1]+pos[2,1])==val)
	                        play(0,1);
	                    else
	                        if((pos[1,0]+pos[1,1]+pos[1,2])==val)
	                            play(1,0);
	                        else
	                            if(pos[0,1]!=0)
	                                play(0,2);
	                            else
	                                play(2,0);
	
	                    break;
	            default : while(!(play(l,m)))
	                      {
	                        l=rnd.Next(3);  // Random moves are played
	                        m=rnd.Next(3);  //Until at least one is successful
	                      }
	                    break;
	        }
	    } 
C#
void Label1Click(object sender, EventArgs e)
		{
			if(play(0,0)&&turn==true)
                        compplay(val); // Is executed only if Players move 
				//was successful and the game is in Vs computer mod.
		}     

The fow of operation is as follows

  1. The player will click on label transferring control to play().
  2. Play() will check if the corresponding array position is empty, which is necessary for not overlapping a move by player as well as computer player module.
  3. If the move succeeds, the corresponding label is updated as well the array element corresponding to the label. And soon flip() and checkwin() are called.
  4. flip() will change the value of let and val for use by next move.
  5. checkwin() will use the coordinates passed by play() to check only the corresponding row and column, if that fails both diagonals are checked. The function is active only after at least four moves are played.
  6. The control returns to the click event function where turn determines if comp player module should be activated, in two player mode it waits for second player.
  7. If vs computer is selected, the compplay() is called.
  8. compplay() calls the other functions as per the difficulty level selected by user:
    1. Easy: Only doany() is called.
    2. Medium: winorstop() is called in stop mode first and then doany().
    3. Hard: winorstop() is called in win mode, then stop mode and finally doany() is called.
  9. When a win or draw is encountered, the first player plays again. If it happens to be the computer players turn, the compplay() is called from within the checkwin() itself.
  10. Though doany() is meant to do random moves, certain moves are played so that the Easy mode does not appear CRAZY.

Points of Interest

Applying effects such as transparency in C# and implementing the same in Java was really funny and at the same time educative. Going through the equivalent code the C#, a developer can learn Java and vice versa.

History

This is a replacement for the two player version uploaded earlier, at the same time improvement for the same. The previous version is deleted to eliminate redundancy. ;)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
I am a polyglot developer, passionate about conceptualising and engineering solutions. A keen learner myself, I firmly believe in empowerment through mentorship.

Started with C like most developers,
I later developed liking for C# due to its rapid development style(GUI editor and all),
However as I met Ubuntu, I wanted to develop apps which work on all platforms, hence Java,
As time passed, the need to quickly develop websites got me into PHP,
Finally, Javascript emerged as ultimate Swiss army knife and I could develop for everything.

Currently most of my development is in Typescript with Node.js.

While writing for devices, I use Embedded C/C++.

Comments and Discussions

 
QuestionRegarding the Tic Tac toe game developed by you Pin
Member 1038301528-May-15 5:21
Member 1038301528-May-15 5:21 
AnswerRe: Regarding the Tic Tac toe game developed by you Pin
Tejas_Pathak7-Dec-15 23:27
Tejas_Pathak7-Dec-15 23:27 
Questionhelp please Pin
Member 103615998-Nov-13 0:48
Member 103615998-Nov-13 0:48 
GeneralTank's Pin
Member 1026501210-Sep-13 6:58
Member 1026501210-Sep-13 6:58 
Questioni am doing tic tac toe. Pin
davidwong75021-Jul-13 4:13
davidwong75021-Jul-13 4:13 
GeneralIm doing a tic tac toe game too Pin
Member 1007413623-May-13 18:18
Member 1007413623-May-13 18:18 
GeneralMy vote of 3 Pin
Member 1005552919-May-13 17:23
Member 1005552919-May-13 17:23 
BugComputer skips its turn Pin
Tony Rueb17-Jan-13 8:45
Tony Rueb17-Jan-13 8:45 
GeneralRe: Computer skips its turn Pin
Tony Rueb17-Jan-13 8:57
Tony Rueb17-Jan-13 8:57 
GeneralRe: Computer skips its turn Pin
Tony Rueb17-Jan-13 14:34
Tony Rueb17-Jan-13 14:34 
GeneralRe: Computer skips its turn Pin
Tejas_Pathak17-Jan-13 18:00
Tejas_Pathak17-Jan-13 18:00 
QuestionPermission Pin
Deanwilliammills23-Oct-12 4:42
Deanwilliammills23-Oct-12 4:42 
AnswerRe: Permission Pin
Tejas_Pathak24-Oct-12 21:04
Tejas_Pathak24-Oct-12 21:04 
GeneralMy vote of 3 Pin
leena2063-Apr-12 20:55
leena2063-Apr-12 20:55 
QuestionRe: My vote of 3 Pin
Tejas_Pathak3-Jul-12 22:53
Tejas_Pathak3-Jul-12 22:53 
AnswerRe: My vote of 3 Pin
leena2063-Jul-12 23:32
leena2063-Jul-12 23:32 
GeneralRe: My vote of 3 Pin
Tejas_Pathak3-Jul-12 23:53
Tejas_Pathak3-Jul-12 23:53 
GeneralRe: My vote of 3 Pin
leena2064-Jul-12 2:13
leena2064-Jul-12 2:13 
GeneralRe: My vote of 3 Pin
leena20617-Jul-12 22:34
leena20617-Jul-12 22:34 
GeneralRe: My vote of 3 Pin
Tejas_Pathak26-Jul-12 0:17
Tejas_Pathak26-Jul-12 0:17 
GeneralMy vote of 1 Pin
Jon Artus1-Apr-12 23:46
Jon Artus1-Apr-12 23:46 
AnswerRe: My vote of 1 Pin
Tejas_Pathak3-Jul-12 22:49
Tejas_Pathak3-Jul-12 22:49 
GeneralMy vote of 3 Pin
zoma200928-Feb-11 6:59
zoma200928-Feb-11 6:59 
good approach
GeneralMy vote of 3 Pin
John Whitmire17-Aug-10 5:50
professionalJohn Whitmire17-Aug-10 5:50 
GeneralTwo dimensional Arrays for controls Pin
vytheese16-Aug-10 20:20
professionalvytheese16-Aug-10 20:20 

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.