Search code examples
javaswingjbuttontic-tac-toe

Hello I am creating a TicTacToe game for myself to understand Java better


however I am not sure where I am supposed to enter the whoWins() method. Do I enter this method in the actionperformed Method of the buttons or do i need to something different. Please help.

public class TTT extends JFrame implements ActionListener {

        private JButton buttons[] = new JButton[9];
        private JButton exitButton;
        public JLabel title;
        public JPanel titlePanel, panel;
        private int count = 0;
        int symbolCount = 0;
        private boolean win = false;

        public TTT() {

            title = new JLabel("Welcome to my Tic Tac Toe Game!");
            titlePanel = new JPanel();
            title.setFont(new Font(Font.SERIF, 0, 30));
            titlePanel.add(title);
            this.add(titlePanel, BorderLayout.NORTH);

            panel = new JPanel(new GridLayout(3, 3));
            for (int i = 0; i < buttons.length; i++) {
                buttons[i] = new JButton();
                panel.add(buttons[i]);
                buttons[i].setEnabled(true);
                buttons[i].addActionListener(this);
            }
            this.add(panel, BorderLayout.CENTER);

            JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
            exitButton = new JButton("Quit");
            panel1.add(exitButton);
            this.add(panel1, BorderLayout.SOUTH);
            exitButton.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(WIDTH);
                }
            });

        }

        public void whoWins() {
            //Determines who wins using for the horizontal rows.
            if (buttons[0].getText() == buttons[1].getText() && buttons[1].getText() == buttons[2].getText() && buttons[0].getText() != "") {
                win = true;
            } else if (buttons[3].getText() == buttons[4].getText() && buttons[4].getText() == buttons[5].getText() && buttons[3].getText() != "") {
                win = true;
            } else if (buttons[6].getText() == buttons[7].getText() && buttons[7].getText() == buttons[8].getText() && buttons[6].getText() != "") {
                win = true;
            } //Determines the verticles wins
            else if (buttons[0].getText() == buttons[3].getText() && buttons[3].getText() == buttons[6].getText() && buttons[0].getText() != "") {
                win = true;
            } else if (buttons[1].getText() == buttons[4].getText() && buttons[4].getText() == buttons[7].getText() && buttons[1].getText() != "") {
                win = true;
            } else if (buttons[2].getText() == buttons[5].getText() && buttons[5].getText() == buttons[8].getText() && buttons[2].getText() != "") {
                win = true;
            }
            // Diagnol Wins 
            else if (buttons[0].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[8].getText()&& buttons[0].getText()!= "") {
                win = true;
            }else if (buttons[2].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[6].getText()&& buttons[1].getText()!= "") {
                win = true;
            }else {
                win = false;
            }

            //who won
            if (win = true) {
                JOptionPane.showMessageDialog(null, "wins");
            }else if (count == 9 && win == false) {
                JOptionPane.showMessageDialog(null, "Tie game");
            }
        }

        public static void main(String[] args) {
            TTT ref1 = new TTT();
            ref1.setTitle("Tic Tac Toe");
            ref1.setVisible(true);
            ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            ref1.setSize(500, 500);
            ref1.setLocationRelativeTo(null);
    //        ref1.whoWins();

        }

        @Override
        public void actionPerformed(ActionEvent e) {
            count++;
            for (JButton button : buttons) {
                if (button == e.getSource()) {
                    if (symbolCount % 2 == 0) {
                        button.setText("X");
                        button.setEnabled(false);
                    } else {
                        button.setText("O");
                        button.setEnabled(false);
                    }
                }            
            }        
            if (count >= buttons.length) {
                JOptionPane.showMessageDialog(null, "End");
            }
            symbolCount++;
        }

    }

Solution

  • If you really want to do this right, then I suggest making some big changes, some M-V-C type changes:

    • First and foremost, separate out the logic of the game from the game GUI. This would mean that the code that determines who wins should not be in any code that contains GUI type code. This will be your "model"
    • Next you should never have GUI code implement listener interfaces, so try to get that out of the GUI and possibly have it go into its own class, the "Control" class.
    • Finally the GUI or "View" class will concern itself with displaying the model's state and getting input from the user and transmitting this input to the control.

    For example,...

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.GridLayout;
    import java.awt.Window;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.io.IOException;
    import java.util.EnumMap;
    import java.util.Map;
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import javax.swing.event.SwingPropertyChangeSupport;
    
    public class TicTacToeMain {
    
       private static void createAndShowGui() {
          TttView view = null;
          try {
             view = new TttView();
          } catch (IOException e) {
             e.printStackTrace();
             System.exit(-1);
          }
          TttModel model = new TttModel();
          new TttControl(model, view);
    
          JFrame frame = new JFrame("Tic Tac Toe");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.getContentPane().add(view.getMainPanel());
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    
    enum TttPiece {
       EMPTY, X, O
    }
    
    class TttView {
      // public static final String IMAGE = "/imgFolder/TicTacToe.png";
      public static final String PATH_TO_IMG_URL = "https://i.sstatic.net/mwfLB.png";
      private static final int GAP = 5;
      private JPanel mainPanel = new JPanel();
      private JPanel tttPanel = new JPanel();
      private Map<TttPiece, Icon> iconMap = new EnumMap<>(TttPiece.class);
      private JLabel[][] grid = new JLabel[TttModel.ROWS][TttModel.COLS];
      private TttControl control;
    
      public TttView() throws IOException {
          // BufferedImage img = ImageIO.read(getClass().getResourceAsStream(IMAGE));
          URL imgUrl = new URL(PATH_TO_IMG_URL);
          BufferedImage img = ImageIO.read(imgUrl);
          Icon[] imgIcons = splitImg(img);
          iconMap.put(TttPiece.X, imgIcons[0]);
          iconMap.put(TttPiece.O, imgIcons[1]);
          iconMap.put(TttPiece.EMPTY, createEmptyIcon(imgIcons[0]));
    
          tttPanel.setLayout(new GridLayout(grid.length, grid[0].length, GAP, GAP));
          tttPanel.setBackground(Color.black);
          MyMouseAdapter mouseAdapter = new MyMouseAdapter();
          for (int row = 0; row < grid.length; row++) {
             for (int col = 0; col < grid[row].length; col++) {
                grid[row][col] = new JLabel(iconMap.get(TttPiece.EMPTY));
                grid[row][col].setOpaque(true);
                grid[row][col].setBackground(Color.LIGHT_GRAY);
                grid[row][col].addMouseListener(mouseAdapter);
                tttPanel.add(grid[row][col]);
             }
          }
    
          JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
          btnPanel.add(new JButton(new ClearAction("Clear", KeyEvent.VK_C)));
          btnPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
    
          int blGap = 2;
          mainPanel.setLayout(new BorderLayout(blGap, blGap));
          mainPanel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap,
                blGap));
          mainPanel.add(tttPanel, BorderLayout.CENTER);
          mainPanel.add(btnPanel, BorderLayout.SOUTH);
       }
    
       public void setControl(TttControl control) {
          this.control = control;
       }
    
       public JComponent getMainPanel() {
          return mainPanel;
       }
    
       private Icon createEmptyIcon(Icon icon) {
          int width = icon.getIconWidth();
          int height = icon.getIconHeight();
          BufferedImage img = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_ARGB);
          return new ImageIcon(img);
       }
    
       private Icon[] splitImg(BufferedImage img) {
          int w = img.getWidth();
          int h = img.getHeight();
          int gap = 5;
          Icon[] icons = new ImageIcon[2];
          icons[0] = new ImageIcon(img.getSubimage(0, 0, w / 2 - gap, h / 2 - gap));
          icons[1] = new ImageIcon(img.getSubimage(w / 2 + gap, 0, w / 2 - gap, h
                / 2 - gap));
          return icons;
       }
    
       private class MyMouseAdapter extends MouseAdapter {
    
          @Override
          public void mousePressed(MouseEvent e) {
             if (control == null) {
                return;
             }
             for (int row = 0; row < grid.length; row++) {
                for (int col = 0; col < grid[row].length; col++) {
                   if (grid[row][col] == e.getSource()) {
                      control.gridPress(row, col);
                   }
                }
             }
          }
       }
    
       private class ClearAction extends AbstractAction {
    
          public ClearAction(String name, int mnemonic) {
             super(name);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent evt) {
             if (control != null) {
                control.clear();
             }
          }
    
       }
    
       private class ExitAction extends AbstractAction {
          public ExitAction(String name, int mnemonic) {
             super(name);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent evt) {
             if (control != null) {
                control.exit(evt);
             }
          }
       }
    
       public void setGridIcon(int row, int col, TttPiece tttPiece) {
          grid[row][col].setIcon(iconMap.get(tttPiece));
       }
    
    }
    
    class TttControl {
       private TttModel model;
       private TttView view;
    
       public TttControl(TttModel model, TttView view) {
          this.model = model;
          this.view = view;
          view.setControl(this);
    
          model.addPropertyChangeListener(new ModelListener());
       }
    
       public void exit(ActionEvent evt) {
          Window win = SwingUtilities
                .getWindowAncestor((Component) evt.getSource());
          win.dispose();
       }
    
       public void gridPress(int row, int col) {
          try {
             model.gridPress(row, col);
          } catch (TttException e) {
             // TODO: notify user
             // e.printStackTrace();
          }
       }
    
       public void clear() {
          model.clear();
       }
    
       private class ModelListener implements PropertyChangeListener {
          @Override
          public void propertyChange(PropertyChangeEvent evt) {
             if (TttModel.GRID_POSITION.equals(evt.getPropertyName())) {
                TttPiece[][] tttGrid = model.getTttGrid();
                for (int row = 0; row < tttGrid.length; row++) {
                   for (int col = 0; col < tttGrid[row].length; col++) {
                      view.setGridIcon(row, col, tttGrid[row][col]);
                   }
                }
             }
          }
       }
    
    }
    
    class TttModel {
       public static final int ROWS = 3;
       public static final int COLS = ROWS;
       public static final String GRID_POSITION = "grid position";
    
       private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
             this);
       private TttPiece[][] tttGrid = new TttPiece[ROWS][COLS];
       private TttPiece player = TttPiece.X;
       private boolean gameOver;
    
       public TttModel() {
          clear();
       }
    
       public void setGridPosition(int row, int col, TttPiece piece)
             throws TttException {
          if (gameOver) {
             return;
          }
          if (tttGrid[row][col] == TttPiece.EMPTY) {
             tttGrid[row][col] = piece;
             checkForWin(row, col, piece);
             nextPlayer();
             pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
          } else {
             String message = "Invalid setGridPosition for row: %d, col: %d, piece: %s. "
                   + "Spot already occupied by piece: %s";
             message = String.format(message, row, col, piece, tttGrid[row][col]);
             throw new TttException(message);
          }
       }
    
       public TttPiece[][] getTttGrid() {
          return tttGrid;
       }
    
       public void gridPress(int row, int col) throws TttException {
          setGridPosition(row, col, player);
       }
    
       public void nextPlayer() {
          player = player == TttPiece.X ? TttPiece.O : TttPiece.X;
       }
    
       private void checkForWin(int row, int col, TttPiece piece) {
          // TODO finish
    
       }
    
       public void clear() {
          for (int row = 0; row < tttGrid.length; row++) {
             for (int col = 0; col < tttGrid[row].length; col++) {
                tttGrid[row][col] = TttPiece.EMPTY;
             }
          }
          player = TttPiece.X;
          pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
       }
    
       public void addPropertyChangeListener(PropertyChangeListener listener) {
          pcSupport.addPropertyChangeListener(listener);
       }
    
       public void removePropertyChangeListener(PropertyChangeListener listener) {
          pcSupport.removePropertyChangeListener(listener);
       }
    
    }
    
    @SuppressWarnings("serial")
    class TttException extends Exception {
    
       public TttException() {
          super();
       }
    
       public TttException(String message) {
          super(message);
       }
    
    }
    

    Using for my images:

    enter image description here

    With GUI looking like:

    enter image description here