-1

So I am having a few problems with this application. When I try to run it, I get a NullPointerException for the creation of a new player and also I am not sure how to best use a stack to keep track of the turns between the user and the computer which needs to be used to check for victories. here is the code

Game interface

package tictactoestack;

public interface Game {

    public enum Player {X, O}

    public Player getTurn();

    public Move getAutoMove();

    public Move getPlayerMove(int row, int col);

    public Character[][] getBoard();

    public boolean checkForVictory();

    public boolean isStalemated();

    public Player getPlayer();

    public void goBack();

    public Move redo();

}

Game Implementation

package tictactoestack;
import java.util.Stack;

import tictactoestack.Game.Player;

public class GameImpl implements Game {
    Character[][] newBoard = new Character[3][3];
    Player user = Player.X;
    Player computer = Player.O;

    Stack<Move> moves;

    Move prevMove = null;

    public GameImpl(Player x) {
        this.user = x;

    }

    @Override
    public Player getTurn() {
        Move m = new MoveImpl(moves.peek().getPlayer(), moves.peek().getCol(), moves.peek().getRow());
        if (m.getPlayer() == user && moves.peek().getPlayer() == Player.X)  {
            return user;
        }
        if (m.getPlayer() == computer) {
            return computer;
        }

        return null;
    }

    @Override
    public Move getAutoMove() {
        TicTacToeSolver auto = new SolverImpl();
        moves.push(auto.getMove(computer, newBoard)); 

        return auto.getMove(computer, newBoard);    
    }

    @Override
    public Move getPlayerMove(int row, int col) {
        Move playerMove = new MoveImpl(user, row, col);
        moves.push(playerMove);

        return playerMove;
    }

    @Override
    public Character[][] getBoard() {

        return newBoard;
    }

    @Override
    public boolean checkForVictory() {
/*      if(checkRowVictory(getBoard()) == true) 
            return true;
        else if(checkColVictory(getBoard()) == true)
            return true;
        else if(checkDiagVictory(getBoard()) == true) 
            return true;
        else 
            return false;
*/
        return false;
        }

    @Override
    public boolean isStalemated() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Player getPlayer() {
        if(moves.peek().getPlayer() == Player.X) 
            return user;
        else if(moves.peek().getPlayer() == Player.O) 
            return computer; 
        else
            return null;

    }

    @Override
    public void goBack() {
        prevMove = moves.pop();

    }

    @Override
    public Move redo() {
        moves.push(prevMove);

        return new MoveImpl(getTurn(), prevMove.getRow(), prevMove.getCol()); 
    }

}

Move Interface

package tictactoestack;

import tictactoestack.Game.Player;

public interface Move {

    public int getRow();

    public int getCol();

    public Player getPlayer();

}

Move Implementation

package tictactoestack;

import tictactoestack.Game.Player;

public class MoveImpl implements Move {
    int row;
    int col;
    Player turn;

    public MoveImpl(Player turnIn, int rowIn, int colIn) {
        turn = turnIn;
        row = rowIn;
        col = colIn;

    }

    @Override
    public int getRow() {

        return row;
    }

    @Override
    public int getCol() {

        return col;
    }

    @Override
    public Player getPlayer() {
        if (turn == Player.X) {
            return Player.X;
        } else {
            return Player.O;
        }
    }
}

TicTacToeGUI.java

package tictactoestack;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EmptyStackException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.Border;

import tictactoestack.Game.Player;

public class TicTacToeGUI {
    private JFrame frame;
    private JPanel startPanel;
    private JButton oStartButton;
    private JButton xStartButton;
    private JButton backButton;
    private JButton redoButton;
    private JPanel boardPanel;
    private JLabel[][] labels;
    private Game game;

    private void setUpGUI() {
        game = new GameImpl(Player.X);
        labels = new JLabel[3][3];
        frame = new JFrame();
        frame.setLayout(new BorderLayout());
        startPanel = new JPanel();
        boardPanel = new JPanel(new GridLayout(3, 3));
        setUpStartPanel();
        setUpLabels();

        frame.add(startPanel, BorderLayout.NORTH);
        frame.add(boardPanel, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private void setUpLabels() {
        for (int row = 0; row < 3; row++)
            for (int col = 0; col < 3; col++) {
                JLabel l = new JLabel();
                labels[row][col] = l;
                setUpLabel(l, row, col);
                boardPanel.add(l);
            }
    }

    private void setUpLabel(final JLabel l, final int row, final int col) {
        l.setPreferredSize(new Dimension(85,85));
        setLabelBorder(l, row, col);
        l.setFont(new Font(null, 0, 40));
        l.setHorizontalAlignment(0);

        l.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                if (game.getBoard()[row][col] == ' '
                        && game.getPlayer() == game.getTurn()
                        && !game.checkForVictory()) {
                    playerMove(l, row, col);
                }
            }

            @Override
            public void mouseEntered(MouseEvent arg0) {
            }

            @Override
            public void mouseExited(MouseEvent arg0) {
            }

            @Override
            public void mousePressed(MouseEvent arg0) {
            }

            @Override
            public void mouseReleased(MouseEvent arg0) {
            }
        });
    }

    private void setLabelBorder(JLabel l, int row, int col) {
        Border blackline = BorderFactory.createLineBorder(Color.black);
        if (row == 1) {
            if (col == 1)
                l.setBorder(BorderFactory
                        .createMatteBorder(1, 1, 1, 1, Color.black));           else
                l.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0,
                        Color.black));
        } else if (col == 1) {
            l.setBorder(BorderFactory
                    .createMatteBorder(0, 1, 0, 1, Color.black));
        }
    }

    private void updateLabels() {
        Character[][] board = game.getBoard();

        for (int row = 0; row < 3; row++)
            for (int col = 0; col < 3; col++) {
                labels[row][col].setText(String.valueOf(board[row][col]));
            }
    }

    private void setUpStartPanel() {
        setUpOButton();
        setUpXButton();
        setUpBackButton();
        setUpRedoButton();
        startPanel.add(oStartButton);
        startPanel.add(xStartButton);
        startPanel.add(backButton);
        startPanel.add(redoButton);
    }

    private void setUpOButton() {
        oStartButton = new JButton("Play O");
        oStartButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                game = new GameImpl(Player.O);
                updateLabels();
            }
        });
    }

    private void setUpXButton() {
        xStartButton = new JButton("Play X");
        xStartButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                game = new GameImpl(Player.X);
                updateLabels();
            }
        });

    }

    private void setUpBackButton(){
        backButton = new JButton("Back");
        backButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    game.goBack();
                } catch (EmptyStackException e) {
                    JOptionPane.showMessageDialog(null, "Can't go back");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                updateLabels();
            }
        });}

        private void setUpRedoButton(){
            redoButton = new JButton("Redo");
            redoButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    try {
                        game.redo();
                    } catch (EmptyStackException e) {
                        JOptionPane.showMessageDialog(null, "Can't Redo");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    updateLabels();
                }
            });

    }

    public void play() {
        while (true) {
            if (game.getTurn() != game.getPlayer() && !game.checkForVictory()
                    && !game.isStalemated())
                getAutoMove();
            else
                try {
                    Thread.sleep(400);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }

    public void executeMove(Move m) {
        updateLabels();
        if (game.checkForVictory()) {
            char victorChar;
            if (game.getTurn() == Player.X)
                victorChar = 'O';
            else
                victorChar = 'X';
            JOptionPane.showMessageDialog(null, victorChar + " wins!");
        }
    }

    private void playerMove(JLabel l, int row, int col) {
        Character[][] board = game.getBoard();
        if (board[row][col] == ' ') {
            Move m = game.getPlayerMove(row, col);
            executeMove(m);
        }
    }

    private void getAutoMove() {
        Move m = game.getAutoMove();
        executeMove(m);
    }

    public static void main(String[] args) {
        TicTacToeGUI gui = new TicTacToeGUI();
        gui.setUpGUI();
        gui.play();
    }
}

most of it is still a work in progress since I cannot fully test it but my most important question is why am I getting the nullpointerexception when I try to initiate the Game.Player variable for the user

heres the stacktrace associated with the error

Exception in thread "main" java.lang.NullPointerException at tictactoestack.GameImpl.getTurn(GameImpl.java:26) which is this line

if (m.getPlayer() == computer && (moves.peek().getPlayer() == Player.O)) {

at tictactoestack.TicTacToeGUI.play(TicTacToeGUI.java:189)

if (game.getTurn() != game.getPlayer() && !game.checkForVictory()

at tictactoestack.TicTacToeGUI.main(TicTacToeGUI.java:229)

gui.play();
Moshe Katz
  • 15,992
  • 7
  • 69
  • 116
Juan Battini
  • 115
  • 3
  • 14
  • 1
    If you've done even a little searching on solving a NullPointerException (NPE), you'll know that the most important bit of information that we need is the exception's associated stacktrace and some identification of the line that causes it, something that the stacktrace will tell you, and unfortunately neither of which you've posted here with your question. Please fix this so that we can help you. – Hovercraft Full Of Eels Apr 30 '15 at 03:10
  • Where is the `if (m.getPlayer() == computer && (moves.peek().getPlayer() == Player.O)) {` line in the posted code above? – Hovercraft Full Of Eels Apr 30 '15 at 03:24
  • In fact the GameImpl class doesn't even have a `moves` variable. Sorry, but I'm really confused. Are you sure that the posted code is the code that is throwing the exception? Note though that you never assign `turns` a viable object. – Hovercraft Full Of Eels Apr 30 '15 at 03:27
  • My bad I went back and changed the datatype of the stack to Move instead of integer and I renamed it moves, I'll update the code – Juan Battini Apr 30 '15 at 03:28

1 Answers1

0

Your moves variable is null -- fix this.

i.e., you have:

Stack<Move> moves;

but where do you have

Stack<Move> moves = ?????;

Where do you assign anything to this variable? So if it remains null and you try to use it: NPE!

More importantly, you need to learn the general concepts of how to debug a NPE (NullPointerException). You should critically read your exception's stacktrace to find the line of code at fault, the line that throws the exception, and then inspect that line carefully, find out which variable is null, and then trace back into your code to see why. You will run into these again and again, trust me.


Also, as per the Stack API, better to use a Deque and an ArrayDeque. For example:

Deque<Move> moves = new ArrayDeque<Move>();
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373