Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Swing

Tic Tac Toe Implemented in Java with Computer Player

4.59/5 (15 votes)
9 Aug 2010CPOL4 min read 123.1K   10.5K  
A platform independent game that runs on Windows, Mac and Linux
Capture2.JPG Screenshot-1.jpg

Introduction

This is a program for Tic Tac Toe game written in C#. It has a built in Computer Player module and can be even played in two player mode. It can be run anywhere where JRE is installed. The source is compatible NetBeans.

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 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 the 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 uses 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 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(): 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 is as below:

label1label2label3 0,0  0,1  0,2
label6label5 label41,0  1,1  1,2
label9label8label72,0  2,1   2,2 

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

Java
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();
    boolean turn=true;
Java
void reset()
    {
        for (int i=0;i<3 ;i++ )
        {
            for (int j=0;j<3 ;j++ ){pos[i][j]=0;} //The array is filled with zeros.
        }
        Component[] cmpnt=this.getContentPane().getComponents();
        for(int i=0;i<cmpnt.length;i++)
        {
            if(cmpnt[i] instanceof JLabel)
                ((JLabel) cmpnt[i]).setText("") ; //All the labels are cleared.
        }
        cnt=0;
        val=1;  //X->1 and O->4
        let='X';
        jLabel10.setText(pl1+" to Play NOW."); //Status label is set.
    }
Java
boolean play(int l,int m)
    {
        if(pos[l][m]==0)  //Check for overplaying of a move.
        {
            a=c;b=d;c=l;d=m;  // Store coordinates for 2nd last and the last move.
            JLabel ctrl=link(l,m);  //linking the label to corresponding coordinates.
            ctrl.setText(String.valueOf(let)); //Reflecting the move in label.
            pos[l][m]=val;  // Reflecting the move in array.
            flip();  //Toggling between X and O.
            checkwin(l,m,pos[l][m]);  //Checking for the win situation.
            return true;
        }
        else
            return false;  // If the move fails(if already played)
    }
Java
JLabel link(int l,int m)//Linking is used for mainly computer player logic.
    {
        if(l==0)
        {
            if(m==0)
                    return jLabel1;
            if(m==1)
                    return jLabel2;
            if(m==2)
                    return jLabel3;
        }
        if(l==1)
        {
            if(m==0)
                    return jLabel6;
            if(m==1)
                    return jLabel5;
            if(m==2)
                    return jLabel4;
        }
        if(l==2)
        {
            if(m==0)
                    return jLabel9;
            if(m==1)
                    return jLabel8;
            if(m==2)
                    return jLabel7;
        }
        return null;
    } 
Java
void flip()  // Easiest part of code.
   {
       if(let=='X')
       {
           let = 'O';
           val=4;
           cnt++;
       }
       else
       {
           let = 'X';
           val=1;
           cnt++;
       }
   }
Java
void checkwin(int l,int m,int n)
   {
       if(cnt==1)
           if(vs==1)
               turn=true;
       if(cnt>4)
       {   //Checking only the corresponding row and column for win situation.
           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 only the corresponding diagonals for win situation.
               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)
                   {
                           cnt=0;
                   }
               }
           }
           if(cnt==1||cnt==0)
           {  //When either first player wins or a 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); //To be called if computer is to play first next.
               }
               else
                   turn=false;
           }
           else
           if(cnt==4)
           {   // When 2nd player wins.
               declare(pl2+" (Playing O) Wins!");
               String temp=pl1;
               pl1=pl2;
               pl2=temp;//Toggling between player one and two.
               reset();
               if(vs==1)
               if(pl1=="Computer")
                   compplay(val); //To be called if computer is to play first next.
               else
                   turn=false;
           }
       }
   }
Java
void declare(String stmt)
   {
       if(JOptionPane.showConfirmDialog(this,stmt+" Do you want to continue?","",0)!=0)
       {
           System.exit(0); // Exiting if user does not click yes.
       }
   }
Java
void compplay(int n)
   {
       boolean carry=true; // Is used so that only one module is executed.
       if(diff==3)
           carry=winorstop(a,b,n); // Checking for 2/3 win situation.
       if((diff==2||diff==3) && carry)
       {
           if(n==1)
               carry=winorstop(c,d,4); //Checking for situation where loss may occur.
           else
               carry=winorstop(c,d,1);
       }
       if(carry)
               doany();// To play random move.
   }
Java
boolean winorstop(int l,int m,int n)
    {
        if(pos[l][0]+pos[l][1]+pos[l][2]==n*2)	//Checking corresponding row
						// for 2/3 situation.
        {
            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)	// Checking corresponding
						// column for 2/3 situation.
            {
                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)	// Checking diagonal for 2/3.
                {
                        for(int i=0;i<3;i++)
                        {
                                if(play(i,i)) 	// Play the move.
                                        return false;
                        }
                }
                else
                    if(pos[2][0]+pos[1][1]+pos[0][2]==n*2)// Checking other diagonal
							// for 2/3.

                    {
                            for(int i=0,j=2;i<3;i++,j--)
                            {
                                    if(play(i,j))  	// Play the move.
                                            return false;
                            }
                    }

        return true;
    } 
Java
void doany()
    {
        int l=2,m=0;
        switch(cnt)
        {
            case 0: play(0,0);// Some certain steps are used.
                    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.nextInt(3);//Play random moves
                        m=rnd.nextInt(3);//Until at least one is successful.
                      }
                    break;
        }
    } 
Java
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
      if(play(0,0)&&turn==true)
           compplay(val);  // Execute only if the move was successful
           // and if the game is in Computer Player mode.
   }

The flow 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, 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 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 at the same time educative. Going through the equivalent code in C#, a developer can learn Java and vice versa.

History

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

License

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