Need Help with Computer Player Logic
I built a tic tac toe game in Java with a graphical interface that works great when two humans play. Now I want to add a computer player mode but I’m having trouble with the AI logic.
The Problem
The computer makes weird moves and doesn’t block the player from winning like it should. My plan was to make the computer pick random spots early in the game, then switch to defensive play to stop the human player from getting three in a row. But the computer picks completely wrong positions.
My Setup
I use a 2D button array and check getText() to see who owns each square. Human player is always “X” and computer is “O”. I made an AI class with methods to scan the board and choose moves.
Button Click Handler
public class ClickHandler implements ActionListener {
private ComputerPlayer cpu = new ComputerPlayer();
private int row, col;
public ClickHandler(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
if (btn.getText().equals("")) {
if (playerTurn) {
btn.setText("X");
playerTurn = false;
if (hasWinner(row, col)) {
JOptionPane.showMessageDialog(null, "You won!");
resetGame();
}
} else if (vsComputer) {
cpu.analyzeBoard();
cpu.makeMove();
} else {
btn.setText("O");
playerTurn = true;
if (hasWinner(row, col)) {
JOptionPane.showMessageDialog(null, "Player 2 wins!");
resetGame();
}
}
}
}
}
Computer Player Class
public class ComputerPlayer {
public void makeMove() {
if (!playerTurn) {
if (getBlockingMoves().isEmpty()) {
playerTurn = true;
int r = getRandomPosition();
int c = getRandomPosition();
gameButtons[r][c].setText(getSymbol());
hasWinner(r, c);
} else {
if (gameButtons[getBlockingMoves().get(0)][getBlockingMoves().get(1)].getText().equals("")) {
gameButtons[getBlockingMoves().get(0)][getBlockingMoves().get(1)].setText(getSymbol());
} else {
gameButtons[getBlockingMoves().get(0)][getBlockingMoves().get(1)].setText(getSymbol());
}
getBlockingMoves().clear();
playerTurn = true;
}
}
}
public int getRandomPosition() {
double rand = Math.random();
return rand > 0.66 ? 2 : rand > 0.33 ? 1 : 0;
}
public ArrayList<Integer> getBlockingMoves() {
ArrayList<Integer> moves = new ArrayList<>();
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
if (gameButtons[r][c].getText().equals("X")) {
if (r < 2 && c < 2) {
if (hasWinner(r+1, c+1)) {
moves.add(r+1);
moves.add(c+1);
} else if (hasWinner(r+1, c)) {
moves.add(r+1);
moves.add(c);
} else if (hasWinner(r, c+1)) {
moves.add(r);
moves.add(c+1);
}
} else if (r > 0 && c > 0) {
if (hasWinner(r-1, c-1)) {
moves.add(r-1);
moves.add(c-1);
} else if (hasWinner(r-1, c)) {
moves.add(r-1);
moves.add(c);
} else if (hasWinner(r, c-1)) {
moves.add(r);
moves.add(c-1);
}
}
}
}
}
return moves;
}
public String getSymbol() {
return "O";
}
}
Win Detection Method
public boolean hasWinner(int r, int c) {
if (gameButtons[0][c].getText().equals(gameButtons[1][c].getText()) &&
gameButtons[2][c].getText().equals(gameButtons[1][c].getText())) {
return true;
} else if (gameButtons[r][0].getText().equals(gameButtons[r][1].getText()) &&
gameButtons[r][2].getText().equals(gameButtons[r][0].getText())) {
return true;
} else if (r == c) {
return gameButtons[0][0].getText().equals(gameButtons[1][1].getText()) &&
gameButtons[0][0].getText().equals(gameButtons[2][2].getText());
} else if ((r == 0 && c == 2) || (r == 2 && c == 0) || r == c) {
return gameButtons[2][0].getText().equals(gameButtons[1][1].getText()) &&
gameButtons[2][0].getText().equals(gameButtons[0][2].getText());
}
return false;
}
Any ideas what I’m doing wrong with the blocking logic? The computer should pick spots that prevent the human from winning but it doesn’t work right.