I have an issue I need help with. I’m currently completing a university assignment to complete a TicTacToe game that requires the AI to be randomly selected from a smart or naive AI.
I have no problems with the NaiveAI when called from TicTacToeGUI, but am having issues with the Smart AI, firstly that the AI doesn’t take a move after I’ve moved, the buttons become disabled. I think this may be down to the
boolean valid = logic.move(this, pos);
line. When I have played around and got the SmartPlayer working, I can’t get the SmartAI to take the win.
My second problem is the actual randomisation of the AI. I’ve been playing around and staring at my screen for days now, and I’m still completely lost.
I looked through various questions on this site and others to find an answer to my problem, all in vain.
Apologies in advance for any issues with my code, I only began the module in September and I have no previous java experience.
This is what I have so far…
GameBoard Class
public class GameBoard { private ComputerPlayer[][] board; public GameBoard() { board = new ComputerPlayer[3][3]; } public ComputerPlayer getPos(int[] position) { if (position[0] < board.length && position[1] < board[position[0]].length){ return board[position[0]][position[1]]; } else { return null; } } private boolean setPos(ComputerPlayer player, int[] position) { if (position[0] < board.length && position[1] < board[position[0]].length){ board[position[0]][position[1]] = player; return true; } else { return false; } } public boolean move(ComputerPlayer player, int[] position) { if (getPos(position) == null){ return setPos(player, position); } else { return false; } } public GameBoard clone() { GameBoard clone = new GameBoard(); for (int x=0; x<3; x++){ for (int y=0; y<3; y++){ int[] pos = { x, y }; ComputerPlayer curr = getPos(pos); clone.move(curr, pos); } } return clone; } public boolean fullBoard() { boolean full = true; for (int x=0; x<3; x++){ for (int y=0; y<3; y++){ int[] pos = {x, y}; ComputerPlayer curr = getPos(pos); if(curr == null){ full=false; break; } } if (!full){ break; } } return full; } }
GameLogic Class
public class GameLogic { final private char X = 'X'; final private char O = 'O'; private ArrayList<ComputerPlayer> player; private GameBoard board; private ComputerPlayer current; public GameLogic() { player = new ArrayList<ComputerPlayer>(); } public void startGame() { GameBoard gameBoard = new GameBoard(); startGame(gameBoard); } public void startGame(GameBoard gameBoard) { board = gameBoard; current = player.get(0); current.startGame(gameBoard, this); getNextPlayer(current).startGame(gameBoard, this); promptMove(current); } public void endGame() { current = null; } public GameBoard getBoard() { return board; } public ComputerPlayer getLoser() { ComputerPlayer winner = getWinner(); ComputerPlayer loser = getNextPlayer(winner); return loser; } public ComputerPlayer getWinner() { for (int y=0; y<3; y++) { if ((board.getPos(new int[]{0, y}) == board.getPos(new int[]{1, y})) && (board.getPos(new int[]{1, y}) == board.getPos(new int[]{2, y}))) { return board.getPos(new int[]{0, y}); } } for (int x=0; x<3; x++) { if ((board.getPos(new int[]{x, 0})== board.getPos(new int[]{x, 1})) && (board.getPos(new int[]{x, 1}) == board.getPos(new int[]{x, 2}))) { return board.getPos(new int[]{x, 0}); } } if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{1, 1})) && (board.getPos(new int[]{1, 1}) == board.getPos(new int[]{2, 2}))) { return board.getPos(new int[]{0, 0}); } if ((board.getPos(new int[]{2, 0}) == board.getPos(new int[]{1, 1})) && (board.getPos(new int[]{1, 1}) == board.getPos(new int[]{0, 2}))) { return board.getPos(new int[]{2, 0}); } return null; } public char getLetter(ComputerPlayer player) { int index = getIndex(player); if (index == -1){ return ' '; } else if (index == 0){ return X; } else { return O; } } public boolean addPlayer(ComputerPlayer newPlayer) { if (!player.contains(newPlayer)){ player.add(newPlayer); return true; } else { return false; } } public boolean removePlayer(ComputerPlayer oldPlayer) { int index = player.indexOf(oldPlayer); if (index > -1){ player.remove(index); return true; } else { return false; } } public boolean move(ComputerPlayer player, int[] pos) { boolean valid = board.move(player, pos); ComputerPlayer winner = getWinner(); ComputerPlayer loser = getLoser(); if (winner != null) { winner.wonGame(board, this); loser.lostGame(board, this); endGame(); return valid; } else if (board.fullBoard()){ current.drawGame(board, this); getNextPlayer(current).drawGame(board, this); endGame(); return valid; } if (valid){ switchPlayer(); } promptMove(current); return valid; } private void switchPlayer() { current = getNextPlayer(current); } private void promptMove(ComputerPlayer player) { final GameLogic logic = this; Runnable myRunnable = new Runnable() { public void run() { current.takeTurn(board.clone(), logic); } }; new Thread(myRunnable).start(); } private int getIndex(ComputerPlayer players) { int index = player.indexOf(players); return index; } private int getNextPlayerIndex(ComputerPlayer players) { int index = getIndex(players); index++; if (index >= player.size()){ index = 0; } return index; } private ComputerPlayer getNextPlayer(ComputerPlayer players) { int nextIndex = getNextPlayerIndex(players); if (nextIndex > -1){ ComputerPlayer next = player.get(nextIndex); return next; } else { return null; } } }
TicTacToeGUI Class
import java.awt.Container; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; public class TicTacToeGUI extends ComputerPlayer implements ActionListener { public static void main(String[] args) { ComputerPlayer firstPlayer = new TicTacToeGUI(); ComputerPlayer secondPlayer = new RandomisePlayer(); GameLogic logic = new GameLogic(); logic.addPlayer(firstPlayer); logic.addPlayer(secondPlayer); logic.startGame(); } public JButton[][] buttons; GameLogic currentLogic; JLabel message; JFrame mainFrame = null; JButton myButton = null; private int wins; private int losses; private int draws; public TicTacToeGUI() { createAndShowGUI(); wins = 0; losses = 0; draws = 0; } private void createAndShowGUI() { JFrame frame = new JFrame("Tic-Tac-Toe"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container contentPane = frame.getContentPane(); contentPane.setLayout(new FlowLayout()); message = new JLabel(); contentPane.add(message); JButton restart = new JButton("New Game"); restart.addActionListener(this); restart.setActionCommand("restart"); contentPane.add(restart); GridLayout boardLayout = new GridLayout(3,3); JPanel panel = new JPanel(); panel.setLayout(boardLayout); addButtons(panel); contentPane.add(panel); frame.pack(); frame.setSize(500, 400); frame.setResizable(true); frame.setVisible(true); } private void addButtons(JPanel panel) { buttons = new JButton[3][3]; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { buttons[x][y] = new JButton(""); buttons[x][y].addActionListener(this); buttons[x][y].setActionCommand("move"); panel.add(buttons[x][y]); } } } private void disableButtons() { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { JButton button = buttons[x][y]; button.setEnabled(false); } } } private void enableButtons() { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { JButton button = buttons[x][y]; button.setEnabled(true); } } } private void displayBoard(GameBoard board, GameLogic logic) { for (int x=0; x<3; x++){ for (int y=0; y<3; y++){ int[] pos = {x,y}; ComputerPlayer curr = board.getPos(pos); JButton btn = buttons[x][y]; btn.setText("" + logic.getLetter(curr)); } } } public void startGame(GameBoard board, GameLogic logic) { currentLogic = logic; displayBoard(board, logic); disableButtons(); } private void displayMessage(String msg) { message.setText(msg); } public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); if (command == "move"){ for (int x=0; x<3; x++){ for (int y=0; y<3; y++){ int[] pos = {x,y}; JButton btn = buttons[x][y]; if (btn == event.getSource()){ disableButtons(); boolean valid = currentLogic.move(this, pos); displayBoard(currentLogic.getBoard(), currentLogic); return; } } } } else if (command == "restart") { try { currentLogic.startGame(); displayBoard(currentLogic.getBoard(), currentLogic); } catch (Exception e) { e.printStackTrace(); } } } public void takeTurn(GameBoard board, GameLogic logic) { displayBoard(board, logic); displayMessage("Make your move! You are '"+ logic.getLetter(this) +"'s.\n Won: "+wins+" Lost: "+losses+" Drawn: "+draws+"\n"); currentLogic = logic; enableButtons(); } public void lostGame(GameBoard board, GameLogic logic) { displayMessage("More like Tic-Tac-Doh! You lost."); displayBoard(board, logic); losses++; } public void wonGame(GameBoard board, GameLogic logic) { displayMessage("Tic-Tac-Woah! You won!"); displayBoard(board, logic); wins++; } public void drawGame(GameBoard board, GameLogic logic) { displayMessage("A hard fought draw."); displayBoard(board, logic); draws++; } }
Player interface
public interface Player { void takeTurn(GameBoard board, GameLogic logic); void lostGame(GameBoard board, GameLogic logic); void wonGame(GameBoard board, GameLogic logic); void drawGame(GameBoard board, GameLogic logic); void startGame(GameBoard board, GameLogic logic); void randomChoice(ComputerPlayer player);
}
Abstract Computer Class
public abstract class ComputerPlayer implements Player { public int x; public int y; public void printBoard(GameBoard board, GameLogic logic) { for (int y=0; y<3; y++) { for (int x=0; x<3; x++) { int[] pos = {x,y}; ComputerPlayer curr = board.getPos(pos); } } } public void randomPlayer(){ x = (int) (Math.random() * 300); y = (int) (Math.random() * 250); } public void randomChoice(ComputerPlayer player){ int smartNaiveChoice = (int)(1 + Math.random() * 2); if (smartNaiveChoice == 1){ new SmartPlayer(); } else if (smartNaiveChoice == 2){ new NaivePlayer(); } } public void startGame(GameBoard board, GameLogic logic){ printBoard(board, logic); } public void lostGame(GameBoard board, GameLogic logic) { printBoard(board, logic); } public void wonGame(GameBoard board, GameLogic logic) { printBoard(board, logic); } public void drawGame(GameBoard board, GameLogic logic) { printBoard(board, logic); } public void takeTurn(GameBoard board, GameLogic logic) { printBoard(board, logic); } }
Naive Player Class
public class NaivePlayer extends ComputerPlayer { private int randomPosPart(int min, int max) { return min + (int)(Math.random() * ((max - min) + 1)); } private int[] randomPos() { int[] pos = { randomPosPart(0,2), randomPosPart(0,2) }; return pos; } private int[] generateMovePos(GameBoard board, GameLogic logic) { return randomPos(); } public void takeTurn(GameBoard board, GameLogic logic) { int[] pos = generateMovePos(board, logic); boolean valid = logic.move(this, pos); } }
SmartPlayer Class
public class SmartPlayer extends ComputerPlayer { private int randomPosPart(int min, int max) { return min + (int)(Math.random() * ((max - min) + 1)); } private int[] randomPos() { int[] pos = { randomPosPart(0,2), randomPosPart(0,2) }; return pos; } public int[] generateMovePos(GameBoard board, GameLogic logic){ if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{1, 0}))){ int[] pos = {2, 0}; } else if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{2, 0}))){ int[] pos = {1, 0}; } else if ((board.getPos(new int[]{1, 0}) == board.getPos(new int[]{2, 0}))){ int[] pos = {0, 0}; } else if ((board.getPos(new int[]{0, 1}) == board.getPos(new int[]{1, 1}))){ int[] pos = {2, 1}; } else if ((board.getPos(new int[]{0, 1}) == board.getPos(new int[]{2, 1}))){ int[] pos = {1, 1}; } else if ((board.getPos(new int[]{1, 1}) == board.getPos(new int[]{2, 1}))){ int[] pos = {0, 1}; } else if ((board.getPos(new int[]{0, 2}) == board.getPos(new int[]{1, 2}))){ int[] pos = {2, 2}; } else if ((board.getPos(new int[]{1, 2}) == board.getPos(new int[]{2, 2}))){ int[] pos = {0, 2}; } else if ((board.getPos(new int[]{0, 2}) == board.getPos(new int[]{2, 2}))){ int[] pos = {1, 2}; } else if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{0, 1}))){ int[] pos = {0, 2}; } else if ((board.getPos(new int[]{0, 1}) == board.getPos(new int[]{0, 2}))){ int[] pos = {0, 0}; } else if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{0, 2}))){ int[] pos = {0, 1}; } else if ((board.getPos(new int[]{1, 1}) == board.getPos(new int[]{1, 2}))){ int[] pos = {1, 0}; } else if ((board.getPos(new int[]{1, 0}) == board.getPos(new int[]{1, 2}))){ int[] pos = {1, 1}; } else if ((board.getPos(new int[]{1, 0}) == board.getPos(new int[]{1, 1}))){ int[] pos = {1, 2}; } else if ((board.getPos(new int[]{2, 0}) == board.getPos(new int[]{2, 1}))){ int[] pos = {2, 2}; } else if ((board.getPos(new int[]{2, 1}) == board.getPos(new int[]{2, 2}))){ int[] pos = {2, 0}; } else if ((board.getPos(new int[]{2, 0}) == board.getPos(new int[]{2, 2}))){ int[] pos = {2, 1}; } else if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{1, 1}))){ int[] pos = {2, 2}; } else if ((board.getPos(new int[]{1, 1}) == board.getPos(new int[]{2, 2}))){ int[] pos = {0, 0}; } else if ((board.getPos(new int[]{0, 0}) == board.getPos(new int[]{2, 2}))){ int[] pos = {1, 1}; } else if ((board.getPos(new int[]{0, 2}) == board.getPos(new int[]{2, 0}))){ int[] pos = {1, 1}; } else if ((board.getPos(new int[]{1, 1}) == board.getPos(new int[]{2, 0}))){ int[] pos = {0, 2}; } else if((board.getPos(new int[]{1, 1}) == board.getPos(new int[]{0, 2}))){ int[] pos = {2, 0}; } else{ return randomPos(); } return null; } public void takeTurn(GameBoard board, GameLogic logic) { int[] pos = generateMovePos(board, logic); boolean valid = logic.move(this, pos); } }