JFrame never renders if program is only interacted with through doClick();

Viewed 26

I am writing an Othello game using Swing, here's the general code: (The snippet does not include the cases for game end/same player goes again, it's just the basic gameplay loop.)

View/Controller:

public class OthelloGUI extends JFrame {
    JSquare[][] board;
    final int BOARD_SIZE = 8;
    OthelloModel model;
    
    public OthelloGUI(OthelloModel m) {
        model = m;
        
        /* Window size, etc... */
        setLayout(new GridLayout(BOARD_SIZE, BOARD_SIZE));

        //add 8x8 buttons to GUI
        ActionListener ml = new MoveListener();
        board = new JSquare[BOARD_SIZE][BOARD_SIZE];

        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                getContentPane.add(board[i][j] = new JSquare(new Point(i, j)));
                board[i][j].addActionListener(ml);
            }
        }
        update();
    }

    void update() {

        //update GUI to reflect last move
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                //changes the JButton's text based on who owns it on the model's board
                board[i][j].setText(model.getOwner(i, j).view());
            }
        }
        
        //best place (I think) to have AI move is after the last move is processed
        if (model.getCurrentPlayerType() == PlayerType.AI) {

            //Computer player finds its next move, and clicks that button
            int[] bestMove = GreedyAI.findMove(model);
            board[bestMove[0]][bestMove[1]].doCLick();
        }
    }

    static class JSquare extends JButton {
        java.awt.Point p;
        JSquare (Point p) {this.p = p;}
    }

    class MoveListener implements ActionListener {
        
        @Override
        public void actionPerformed(ActionEvent e) {
        
            JSquare sq = (JSquare) e.getSource();

            //places the piece on the model's "board" and flips all applicable pieces
            int result = model.placeDisk(s.p, model.getCurrentColor());
            
            if (result == 0) {//move executes successfully
                update();
            }
            //otherwise... (illegal move, game end, same player again, etc...) 
        }
    }
}

enum Owner {
    NONE, BLACK, WHITE;

    public String view() {
        return this == BLACK ? "B" : this == WHITE ? "W" : ""
    }
}

This code executes fine if I start a Human v Human or Human v AI game, however, if I start an AI v AI game, the GUI never renders. I get the popup box for game setup, and the popup for the game end and who won, but the main ContentPane with the board never renders, so I don't see what moves the AI make.

Any ideas/suggestions?

1 Answers

The AI is automated. The human is .. not.

  • When the human is playing a human the code must wait for the human to make each turn. It must be event driven.
  • When the human plays the AI, the AI is automated but the code must still wait for events from the human.
  • But when the AI plays the AI the entire process is left to the code and this leads to the EDT being blocked.

Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See Concurrency in Swing for details and the fix.

Related