Search code examples
javaswinggettextjtextfieldjapplet

JTextField getText() is stuck after init()


This used to be homework but now it's personal as the term is over and I'm still working on learning Swing components. This program is my attempt to lift a procedural console TicTacToe implementation into an applet in the simplest (looking) way possible, eschewing the traditional button grid for a single JTextField and submit button.

It works fine through the first time, but after I reset the game with some logic in the init() function (this actually works, I was surprised), getText() returns the empty string down at line 155 (search on 'ARGH'). I'm basically taking shots in the dark at this point, so, if someone could have a look and critique, maybe point the way to the shortest route through this I'd really appreciate it!

    /** 
     * TTTapp.java - TicTacToe
     * Implements a simple console-based version of the classic
     * game Tic Tac Toe 
     * @author  Todd Howe
     * @version 1.0
     * @since 2012-08-22
     */
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import java.util.ArrayList;
    import java.util.*;
    /**
     * Plays a simple game of Tic Tac Toe.
     * 
     * A 3x3 char array is generated to accomodate a simple Tic Tac Toe
     * game. The player picks a position, the computer picks randomly 
     * and the results are tallied in the usual manner.
     */ 
    public class TTTapp extends JApplet implements ActionListener {
        static boolean checkWin=false;              // control variable to detect wins
        static boolean boardFull=false;             // control variable to detect ties
        static String response="";                      // user input
        static int gridPos;                         // (1-9) 1D rep of position on the TTT board
        static int x, y;                                // cartesian TTT board coordinates
        static char player;                         // X or O to indicate current player
        static char[][] board = new char[3][3];     // 2d TTT board matrix
        static int[][] magicsquare = { {8, 1, 6},       // sekrit weapon
                                        {3, 5, 7},
                                        {4, 9, 2} };

        Container con=getContentPane();
        Font monoFont = new Font("Monospaced", Font.BOLD, 12);
        JLabel gameBanner1=new JLabel("Welcome to Tic Tac Toe!");
        JLabel gameBanner2=new JLabel("Player is X, Computer is O");
        JLabel spacer1=new JLabel(" ");
        JLabel spacer2=new JLabel(" ");
        JLabel spacer3=new JLabel(" ");
        JLabel board1=new JLabel(" 1 | 2 | 3 ");
        JLabel board2=new JLabel("---|---|---");
        JLabel board3=new JLabel(" 4 | 5 | 6 ");
        JLabel board4=new JLabel("---|---|---");
        JLabel board5=new JLabel(" 7 | 8 | 9 ");
        JLabel announce=new JLabel("");
        JLabel prompt=new JLabel("\nPick an available space by entering the number (1-9): ");
        JTextField promptField=new JTextField("",4);
        JButton submitButton=new JButton("Submit");
        JButton restartButton=new JButton("RESTART GAME");
        BoxLayout flow=new BoxLayout(con, BoxLayout.Y_AXIS);    

        public void init() {
            // prep the application window
            if (TTTapp.checkWin==false) {
                con.setLayout(flow);
                board1.setFont(monoFont);
                board2.setFont(monoFont);
                board3.setFont(monoFont);
                board4.setFont(monoFont);
                board5.setFont(monoFont);

                gameBanner1.setAlignmentX(Component.CENTER_ALIGNMENT);
                gameBanner2.setAlignmentX(Component.CENTER_ALIGNMENT);
                board1.setAlignmentX(Component.CENTER_ALIGNMENT);
                board2.setAlignmentX(Component.CENTER_ALIGNMENT);
                board3.setAlignmentX(Component.CENTER_ALIGNMENT);
                board4.setAlignmentX(Component.CENTER_ALIGNMENT);
                board5.setAlignmentX(Component.CENTER_ALIGNMENT);
                announce.setAlignmentX(Component.CENTER_ALIGNMENT);
                prompt.setAlignmentX(Component.CENTER_ALIGNMENT);
                promptField.setAlignmentX(Component.CENTER_ALIGNMENT);
                submitButton.setAlignmentX(Component.CENTER_ALIGNMENT);

                con.add(gameBanner1);
                con.add(gameBanner2);
                con.add(spacer1);
                con.add(board1);
                con.add(board2);
                con.add(board3);
                con.add(board4);
                con.add(board5);
                con.add(spacer2);
                con.add(announce);
                con.add(prompt);
                con.add(promptField);
                con.add(submitButton);
                promptField.requestFocus();

                System.out.println("Real INIT");
                submitButton.addActionListener(this);
                promptField.addActionListener(this);
            }
            else {
                con.setLayout(flow);
                board1.setFont(monoFont);
                board2.setFont(monoFont);
                board3.setFont(monoFont);
                board4.setFont(monoFont);
                board5.setFont(monoFont);

                gameBanner1.setAlignmentX(Component.CENTER_ALIGNMENT);
                gameBanner2.setAlignmentX(Component.CENTER_ALIGNMENT);
                board1.setAlignmentX(Component.CENTER_ALIGNMENT);
                board2.setAlignmentX(Component.CENTER_ALIGNMENT);
                board3.setAlignmentX(Component.CENTER_ALIGNMENT);
                board4.setAlignmentX(Component.CENTER_ALIGNMENT);
                board5.setAlignmentX(Component.CENTER_ALIGNMENT);
                announce.setAlignmentX(Component.CENTER_ALIGNMENT);
                prompt.setAlignmentX(Component.CENTER_ALIGNMENT);
                promptField.setAlignmentX(Component.CENTER_ALIGNMENT);
                submitButton.setAlignmentX(Component.CENTER_ALIGNMENT);
                restartButton.setAlignmentX(Component.CENTER_ALIGNMENT);

                con.add(gameBanner1);
                con.add(gameBanner2);
                con.add(spacer1);
                con.add(board1);
                con.add(board2);
                con.add(board3);
                con.add(board4);
                con.add(board5);
                con.add(spacer2);
                con.add(announce);
                con.add(spacer3);
                con.add(restartButton);

                System.out.println("Else INIT");
                restartButton.addActionListener(this);
            }
        }
        public void actionPerformed(ActionEvent e) {
            String discard="";
            // MAIN GAME LOOP (CHANGED BOTH FORMER WHILE LOOPS TO IF TO ALLOW GETTEXT REFRESH)
            // game reset
            if (TTTapp.checkWin==true) {
                TTTapp.checkWin=false;
                TTTapp.boardFull=false;
                TTTapp.response="";
                TTTapp.board = new char[3][3];
                TTTapp.gridPos=(-1);
                announce.setText("");
                con.remove(announce);
                con.remove(restartButton);
                con.remove(spacer3);
                board1.setText(" 1 | 2 | 3 ");
                board2.setText("---|---|---");
                board3.setText(" 4 | 5 | 6 ");
                board4.setText("---|---|---");
                board5.setText(" 7 | 8 | 9 ");
                promptField.requestFocus();
                init();
                TTTapp.response=promptField.getText();
                promptField.setText("");
                // ### ARGH THIS DOESN'T READ promptField IN INIT() ################
            }
            if (TTTapp.boardFull==false && TTTapp.checkWin==false) {
                // ###############################################################
                // System.out.println("boardFull: "+boardFull+" checkWin: "+checkWin);
                displayBoard(TTTapp.board);
                // player's turn
                // System.out.println("Player's turn");
                TTTapp.player='X';
                TTTapp.gridPos=(-1);
                // WAS WHILE
                while (TTTapp.gridPos==(-1)) { // this was my last attempt to capture the bad response
                    if (TTTapp.gridPos==(-1)) {
                        TTTapp.response=promptField.getText();
                        promptField.setText("");
                        // ##################################################
                        System.out.println("Got here, response is "+response);
                        TTTapp.gridPos=validateResponse(TTTapp.response, TTTapp.board); 
                        // #######################################
                        System.out.println("GridPos is "+gridPos);
                        TTTapp.boardFull=playGridPos(TTTapp.gridPos, TTTapp.board, TTTapp.player);
                        // ########################################
                        System.out.println("boardFull: "+boardFull);
                        displayBoard(TTTapp.board);
                    }
                }
                // check for player win
                TTTapp.checkWin=scanBoard(TTTapp.board, TTTapp.magicsquare, TTTapp.player);
                if (TTTapp.checkWin==true) {
                    displayBoard(TTTapp.board);
                    con.remove(prompt);
                    con.remove(promptField);
                    con.remove(submitButton);
                    announce.setText("\nPLAYER WINS");
                }
                // computer's turn
                TTTapp.player='O';
                if (TTTapp.checkWin==false) {
                    if (TTTapp.boardFull==false) {
                        TTTapp.gridPos=computerPlays(TTTapp.board);
                        TTTapp.boardFull=playGridPos(TTTapp.gridPos, TTTapp.board, TTTapp.player);
                        displayBoard(TTTapp.board);
                    }
                    //check for computer win here
                    TTTapp.checkWin=scanBoard(TTTapp.board, TTTapp.magicsquare, TTTapp.player);
                    if (TTTapp.checkWin==true) {
                        displayBoard(TTTapp.board);
                        con.remove(prompt);
                        con.remove(promptField);
                        con.remove(submitButton);
                        announce.setText("\nCOMPUTER WINS");
                    }
                }
            }
            if (TTTapp.checkWin==false && TTTapp.boardFull==true) {
                displayBoard(TTTapp.board);
                con.remove(prompt);
                con.remove(promptField);
                con.remove(submitButton);
                announce.setText("\nTIE GAME");
            }
            if (TTTapp.checkWin==true) {
                init();
            }
            repaint();
        }
        /**
         * Display the TicTacToe board as a grid
         * @param board 2D char array representing game board
         */
        public void displayBoard(char[][] board) {
            int gridPos;    // (1-9) 1d rep of position on the board
            char[] cell=new char[9];    // array of parsed TTT board elements
            char readCell;              // single TTT element
            int line;                   // printout line number
            String[] boardDisplay = new String[5];  // array for 'console printing' to applet
            // System.out.println("");
            // stores each element of the displayBoard readout in cell[]
            for (int x=0; x<3; x++) {
                for (int y=0; y<3; y++) {
                    gridPos=((x*3)+y);
                    readCell=parseCell(board[x][y]);
                    if (readCell==' ') {
                        cell[gridPos]=(char)(gridPos+49);
                    }
                    else {
                        cell[(x*3)+y]=readCell;
                    }
                }
                // constructs tic tac toe grid display line by line
                line=x*2;
                boardDisplay[line]=(" "+cell[((x*3)+0)]+" | "+cell[((x*3)+1)]+" | "+cell[((x*3)+2)]);
                if(x<2) {
                    line+=1;
                    boardDisplay[line]=("---|---|---");
                }
            }
            board1.setText(boardDisplay[0]);
            board2.setText(boardDisplay[1]);
            board3.setText(boardDisplay[2]);
            board4.setText(boardDisplay[3]);
            board5.setText(boardDisplay[4]);
        }
        /**
         * Checks desired player board position against vacancies on TTT grid
         * @param response String of user response
         * @param board 2D char array representing game board
         */
        public int validateResponse(String response,char[][] board) {
            int checkPos=(-1);  // desired TTT board position
            ArrayList emptyCells=new ArrayList();   // array of available positions
            Integer somePos;    // candidate TTT board position
            int result=(-1);    // result returns position or -1 signal to try again
            boolean contains=false; // candidate cell matches desired position
            // populate emptyCells with (1-9) positions
            emptyCells=findEmptyCells(board);
            // checks whether there's any empty cells left
            if (emptyCells.size() > 0) {
                // checks whether the input is at least one char long
                if (response.length()>0) {
                    checkPos=(int)(response.charAt(0)-48);
                    int i=0;
                    while (i<emptyCells.size()) {
                        // #########################################################
                        // System.out.println("emptyCells("+i+"): "+emptyCells.get(i));
                        // checks whether requested cell is empty or not
                        somePos=(Integer)(emptyCells.get(i));
                        // ############################################################
                        // System.out.println("somePos: "+somePos+" checkPos: "+checkPos);
                        if ((somePos.intValue())!=checkPos) {
                            i++;
                        }
                        else {
                            if ((somePos.intValue())==checkPos) {
                                contains=true;
                                i=99;
                            }
                        }
                    }
                    // if requested cell is empty, validate request
                    if (contains==true) {
                        result=checkPos;
                    }
                    // otherwise send pick again signal
                    else {
                        // #################################################################
                        // System.out.println("Contains is "+contains+" checkPos is "+checkPos);
                        result=(-1);
                    }
                }
                // if no entry detected, send pick again signal
                else {
                    result=(-1);
                }
            }
            return(result);
        }
        /**
         * Further validates and places player marker on the board
         * @param gridPos Int desired position of marker on board
         * @param board 2D char array representing game board
         * @param player Char marker representing player
         */
        public boolean playGridPos(int gridPos, char[][] board, char player) {
            int x,y;    // cartesian TTT board coordinates
            ArrayList emptyCells=new ArrayList();   // array of available positions
            boolean boardFull=false;    // control variable to detect ties
            switch (gridPos) {
                // catch invalid entry signal
                case(-1):
                    announce.setText("\nPLEASE ENTER ONE OF THE VISIBLE NUMBERS.");
                    break;
                // place the player marker on the board
                default:
                    gridPos--;
                    x=gridPos/3;
                    y=gridPos-(x*3);
                    board[x][y]=player;
            }
            emptyCells=findEmptyCells(board);
            // check to see if the board is now full
            if (emptyCells.size()==0) {
                boardFull=true;
            }
            return(boardFull);
        }
        /**
         * Determines the computer's next move
         * @param board 2D char array representing game board
         */
        public int computerPlays(char[][] board) {
            int gridPos=(-1);   // (1-9) 1d rep of position on the board
            int temp;           // random board position variable
            String response=""; // user input
            Integer availPos;   // Integer rep of board position index
            ArrayList emptyCells=new ArrayList();   // array of available positions
            boolean vacant=false;   // control variable for a position's vacancy
            boolean checkWin=false; // control variable to detect a win
            char[][] tempBoard = new char[3][3];    // board to test positions for a win
            int[][] magicsquare = { {8, 1, 6},      // sekrit weapon
                                    {3, 5, 7},
                                    {4, 9, 2} };
            emptyCells=findEmptyCells(board);
            // check to see if we have an available win and pick that
            for (int i=0; i<emptyCells.size(); i++) {
                response=(""+emptyCells.get(i));
                temp=validateResponse(response, board);
                availPos=(Integer)temp;
                temp=availPos.intValue();
                // copy board to tempBoard
                for(int x=0; x<3; x++) {
                    for(int y=0; y<3; y++) {
                        tempBoard[x][y]=board[x][y];
                    }
                }
                // if there's two adjacent Os, find the win
                if (checkWin==false) {
                    checkWin=playGridPos(temp,tempBoard,'O');
                    checkWin=scanBoard(tempBoard,magicsquare,'O');
                    if (checkWin==true) {
                        gridPos=temp;
                    }
                }
            }
            // else pick a random square
            if (checkWin==false) {
                while (vacant==false) {
                    temp=(int)(Math.random()*(emptyCells.size()-1));
                    response=(""+emptyCells.get(temp));
                    gridPos=validateResponse(response, board);
                    if (gridPos!=(-2) && gridPos!=(-1)) {
                        availPos=(Integer)gridPos;
                        gridPos=availPos.intValue();
                        vacant=true;
                    }
                }
            }
            return(gridPos);
        }
        /**
         * Detect vacant elements in TicTacToe matrix
         * @param board 2D char array representing game board
         */
        public ArrayList findEmptyCells(char[][] board) {
            ArrayList emptyCells=new ArrayList(); // array of available positions
            char readCell;  // contents of a candidate cell
            Integer availPos;   // integer rep of board position index
            for (int x=0; x<3; x++) {
                for (int y=0; y<3; y++) {
                    availPos=Integer.valueOf((x*3)+y+1);
                    readCell=parseCell(board[x][y]);
                    if (readCell==' ') {
                        emptyCells.add(availPos);
                    }
                }                       
            }
            return(emptyCells);
        }
        /**
         * Scores the TTT board using a magic square to tally row/col/diag
         * @param board 2D char array representing game board
         * @param magicsquare 2D matrix to to help score TTT board
         * @param player Char marker representing player
         */
        public boolean scanBoard(char[][] board, int[][] magicsquare, char player) {
            char readCell;  // contents of a candidate cell
            int[][] keyScores=new int[3][3]; // matrix for magicsquare scoring
            boolean checkWin=false; // control variable to detect wins
            // mask magicsquare with player's occupied cells
            for (int x=0; x<3; x++) {
                for (int y=0; y<3; y++) {
                    readCell=parseCell(board[x][y]);
                    if (readCell==player) {
                        keyScores[x][y]=magicsquare[x][y];
                    }
                    else {
                        keyScores[x][y]=0;
                    }
                }                       
            }
            // check for a win
            // horizontals
            for (int x=0; x<3; x++) {
                if ((keyScores[x][0]+keyScores[x][1]+keyScores[x][2])==15)
                    checkWin=true;
            }
            //verticals 
            for (int y=0; y<3; y++) {
                if ((keyScores[0][y]+keyScores[1][y]+keyScores[2][y])==15)
                    checkWin=true;
            }
            //diagonals
            if ((keyScores[0][0]+keyScores[1][1]+keyScores[2][2])==15)
                    checkWin=true;
            if ((keyScores[0][2]+keyScores[1][1]+keyScores[2][0])==15)
                    checkWin=true;
            return(checkWin);
        }
        /**
         * Returns a processed representation of one TTT cell element
         * @param token Char contents of a single TTT cell
         */
        public char parseCell(char token) {
            char result=' ';    // holds processed contents of cell
            switch(token) {
            case('\u0000'):
                result=(' ');
                break;
            case('x'):
            case('X'):
                result=('X');
                break;
            case('o'):
            case('O'):
                result=('O');
                break;
            default:
                result=token;
            }
            return(result);
        }
    }

Solution

  • Your actionPerformed logic is wrong.

    First, you shouldn't dump all this, unrelated, content into a single actionPerformed. You should have one actionPerformed for each separate component (the text field, the buttons).

    If you can't then you should check who actually fired the event (either check the ActionEvent.getSource or ActionEvent.getActionCommand)

    NOW, I did rectify this by changing

    if (BadApplet.checkWin == true) {
        // Stuff here
    } 
    if (BadApplet.boardFull == false && BadApplet.checkWin == false) {
        // more stuff here
    }
    

    to

    if (BadApplet.checkWin == true) {
        // Stuff here
    }  else if (BadApplet.boardFull == false && BadApplet.checkWin == false) {
        // more stuff here
    }
    

    I'd highly recommend that you learn how to debug your source ;)