Tic Tac Toe Part 2

Modules - CSE2120 Arrays, CSE 2110 Procedural Programming 1

 

Teacher’s Notes:

=======================================

This is the continuation of last week's Tic Tac Toe part 1 assignment.

 

There are many ways to solve each part of the assignment.  In some cases, like checking for wins, I use a brute force approach because even though it is less elegant, it is easier to code for such a small grid.

 
 

Assignment:

=======================================

 

 

Computer Science 2: 

JAVA ~ Arrays 

Tic Tac Toe Part 2:

In this project we are going to continue in the creation of a Tic Tac Toe game.  So far, you should have a program that creates a game board and displays the board in a neat form.  In this project, we will assume that the user is the X player and goes first.  From here, you should:


  1. Write a game loop that prompts the user to choose a spot from 1 to 9 where they will place their mark.  When they enter a value, this number should be passed to a method that checks if this is a valid move.  If the move is valid, the spot will be populated with the X.

  2. Write a method that will determine the computer’s move.  In this method the program should make its move in the following way:

    1. Check if there is an imminent win. This means that there is a spot where the computer can win if it makes its mark there.  If this is available, the computer will choose this spot.

    2. If there is no imminent win, it will check for an imminent loss.  This means that the X player will win on the next turn if an O is not placed in this spot.  The computer will choose the spot that will block the imminent win.

    3. If there is neither an imminent win or loss, the computer will choose a random location to place its O.  If the spot is already taken, the computer will generate another spot and keep doing this until a free spot is chosen.

  3. Write a method that checks to see if someone has won the game by making three of the same mark in any row, column, or diagonal. If this has happened, the method will return TRUE. If this has not happened, the method will return FALSE.  This method will be called after each move from both the player and the computer in the game loop from #1 above.

  4. Modify the game loop so that when the player or computer wins, the program prompt the user to see if they wish to play again.  If they do, the program will track the score, reset the board and play the game again.

 

BONUS: Modify the program so that the first player (the X player) is chosen at random such that sometimes it will be the user and sometimes it will be the computer.

 

 

 

 

Solution (JAVA):

=======================================

public class TicTacToe {
    
    public static void initialize(char[][] board){
        for(int x = 0; x < 3; x++)
            for(int y = 0; y < 3; y++)
                board[x][y] = ' ';
    }
    
    public static void display(char[][] board){
        for(int x = 0; x < 3; x++) {
            for(int y = 0; y < 3; y++) {
                if(board[x][y] == ' ')
                    System.out.print(" " + (3*x+y%3+1)+" ");
                else
                    System.out.print(" " + board[x][y] +" ");
            if(y != 2)
                System.out.print("|");
            }    
            System.out.println();
            if(x != 2)
                System.out.println("----------");
        } 
        System.out.println();
    }
    
    public static void makeMove(char[][]board, char symbol) {
        
        int spot = 0;
        boolean symbolPlaced = true;
        do {
            
            symbolPlaced = true;
            do
            {
                System.out.print("Where would you like to place your " + symbol + ":");
                spot = input.nextInt();
            }while(spot < 1 || spot > 9);
            
            int x = (spot-1)/3;
            int y = (spot-1)%3;
            
            if(board[x][y] == ' ')
                board[x][y] = symbol;
            else
                symbolPlaced = false;
                
        }while(!symbolPlaced);
    }
    public static int imminentWin(char[][] board, char symbol) {
    
        int symbolCount = 0;
        int spaceCount = 0;
        //checking horizontal rows
        for(int x = 0; x < 3; x++)
        {
            symbolCount = 0;
            spaceCount = 0;
            for(int y = 0; y < 3; y++)
            {
                if(board[x][y] == symbol)
                    symbolCount++;
                else if(board[x][y] == ' ')
                    spaceCount++;
            }
            
            if(symbolCount == 2 && spaceCount == 1)
            {
                for(int y = 0; y < 3; y++)
                    if(board[x][y] == ' ')
                        return 3*x+y+1;
            }
        }
        //checking vertical columns
        for(int y = 0; y < 3; y++)
        {
            symbolCount = 0;
            spaceCount = 0;
            for(int x = 0; x < 3; x++)
            {
                if(board[x][y] == symbol)
                    symbolCount++;
                else if(board[x][y] == ' ')
                    spaceCount++;
            }
            
            if(symbolCount == 2 && spaceCount == 1)
            {
                for(int x = 0; x < 3; x++)
                    if(board[x][y] == ' ')
                        return 3*x+y+1;
            }
        }
        
        //checking diagonally
        symbolCount = 0;
        spaceCount = 0;
        for(int x = 0; x < 3; x++)
        {
            if(board[x][x] == symbol)
                symbolCount++;
            else if (board[x][x] == ' ')
                spaceCount++;
        }
        if(symbolCount == 2 && spaceCount == 1)
            for(int x = 0; x < 3; x++)
            {
                if(board[x][x] == ' ')
                    return 4*x+1;
            }
        
        symbolCount = 0;
        spaceCount = 0;
        for(int x = 0; x < 3; x++)
        {
            if(board[x][2-x] == symbol)
                symbolCount++;
            else if (board[x][2-x] == ' ')
                spaceCount++;
        }
        if(symbolCount == 2 && spaceCount == 1)
            for(int x = 0; x < 3; x++)
            {
                if(board[x][2-x] == ' ')
                    return 2*x + 3;
            }
            
        return 0;
    }
        
        
        
        
    
    /*
    public static int imminentWin(char[][] board, char symbol) {
        //check if there is an imminent win
        
        int symbolCount = 0;
        int spaceCount = 0;
        //checking horizontal rows
        for(int x = 0; x < 3; x++)
        {
            symbolCount = 0;
            spaceCount = 0;
            for(int y = 0; y < 3; y++)
            {
                if(board[x][y] == symbol)
                    symbolCount++;
                else if (board[x][y] == ' ')
                    spaceCount++;
            }
            
            if(symbolCount == 2 && spaceCount == 1)
            {
                for(int y = 0; y < 3; y++)
                {
                    if(board[x][y] == ' ')
                    {
                        return x*3+y+1;
                    }
                    
                }    
            }
            
        }

        //checking vertical columns
        for(int y = 0; y < 3; y++)
        {
            symbolCount = 0;
            spaceCount = 0;
            for(int x = 0; x < 3; x++)
            {
                if(board[x][y] == symbol)
                    symbolCount++;
                else if (board[x][y] == ' ')
                    spaceCount++;
            }
            
            if(symbolCount == 2 && spaceCount == 1)
            {
                for(int x = 0; x < 3; x++)
                {
                    if(board[x][y] == ' ')
                    {
                        return x*3+y+1;
                    }
                    
                }    
            }
        }
        
        //check diagonally top left to bottom right
        symbolCount = 0;
        spaceCount = 0;
        for(int x = 0; x < 3; x++)
        {
            if(board[x][x] == symbol)
                symbolCount++;
            else if (board[x][x] == ' ' )
                spaceCount++;
        }
        
        
        if(symbolCount == 2 && spaceCount == 1)
        {
            for(int x = 0; x < 3; x++)
                if(board[x][x] == ' ')
                    return 4*x+1;
        }
        
        //check diagonally bottom left to top right
        
        symbolCount = 0;
        spaceCount = 0;
        for(int x = 0; x< 3; x++)
        {
            if(board[x][2-x] == symbol)
                symbolCount++;
            else if (board[x][2-x] == ' ' )
                spaceCount++;
        }
        
        if(symbolCount == 2 && spaceCount == 1)
        {
            for(int x = 0; x < 3; x++)
                if(board[x][2-x] == ' ')
                    return 2*x+3;
        }
            
        
        return 0;
    }
    */
    public static boolean hasWon(char[][] board) {

        //checking for horizontal wins
        if(board[0][0] != ' ' && board[0][0] == board[0][1] && board[0][0] == board[0][2] || 
            board[1][0] != ' ' && board[1][0] == board[1][1] && board[1][0] == board[1][2] ||
            board[2][0] != ' ' && board[2][0] == board[2][1] && board[2][0] == board[2][2])
                return true;
        //checking for vertical wins
        if(board[0][0] != ' ' && board[0][0] == board[1][0] && board[0][0] == board[2][0] || 
            board[0][1] != ' ' && board[0][1] == board[1][1] && board[0][1] == board[2][1] ||
            board[0][2] != ' ' && board[0][2] == board[1][2] && board[0][2] == board[2][2])
                    return true;
        //checking for diagonal wins
        if(board[0][0] != ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2] || 
                board[0][2] != ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0])
            return true;
        return false;
    }
        
    
    public static void AIMove(char[][]board, char symbol) {
        
        int resultForO = imminentWin(board, 'O');
        int resultForX = imminentWin(board, 'X');
        if( resultForO != 0)
        {
             int x = (resultForO-1)/3;
             int y = (resultForO-1)%3;
             board[x][y] = symbol;
        }
        else if (resultForX != 0)
        {
             int x = (resultForX-1)/3;
             int y = (resultForX-1)%3;
             board[x][y] = symbol;
        }
        else
        {
            boolean symbolPlaced = true;
            
            do
            {
                symbolPlaced = true;
                int spot = (int)(Math.random()*9+1);
                int x = (spot-1)/3;
                int y = (spot-1)%3;
                if(board[x][y] == ' ')
                    board[x][y] = symbol;
                else
                    symbolPlaced = false;
            }while(!symbolPlaced);
            
        }
        
        
    }
    
    public static Scanner input = new Scanner(System.in);
    
    public static void main(String[] args) {

        int wins = 0, losses = 0;
        char playAgain = 'y';
        int moves = 0;
        char[][] board = new char[3][3];
        
        do
        {
            initialize(board);
            System.out.println("Wins: \t" + wins + "\tLosses: \t" +losses);
            display(board);
            moves = 0;
            
            while(!hasWon(board) && moves < 9 )
            {
                makeMove(board,'X');
                moves++;
                if(hasWon(board)) {
                    System.out.println("X has won!!!");
                    wins++;
                    break;
                }
                else if(moves < 9)
                {
                    AIMove(board,'O');
                    moves++;
                    if(hasWon(board)) {
                        System.out.println("O has won!!!");
                        losses++;
                        break;
                    }
                }
                display(board);
            }
            System.out.println("Would you like to play again (y/n)? ");
            playAgain = input.next().charAt(0);
        }while(playAgain == 'y');
        
    }
}