Hello I am creating a TicTacToe game for myself to

2019-01-27 11:52发布

问题:

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++;
        }

    }

回答1:

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";
   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));
      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:

With GUI looking like:



回答2:

I am also interested in writing a Tic Tac Toe game, so I copied your code, and did a little modification, and it passed test, check following:

package eric.j2se.swing;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * <p>
 * Simple game of Tic Tac Toe.
 * </p>
 * 
 * @author eric
 * @date Apr 16, 2014 11:03:48 AM
 */
@SuppressWarnings("serial")
public class TicTacToe extends JFrame implements ActionListener {
    // 2 players
    public static final char playerX = 'X';
    public static final char playerO = 'O';
    // null player
    public static final char playerN = 'N';

    // the winer, init to null player
    private Character winner = playerN;
    // indicate whether game over
    private boolean gameOver = false;

    // count of button used,
    private int count = 0;

    private Character buttonPlayers[] = new Character[9];
    private JButton buttons[] = new JButton[9];
    private JButton exitButton;
    public JLabel title;
    public JPanel titlePanel, panel;

    public TicTacToe() {
        // init buttonPlayers
        for (int i = 0; i < 9; i++) {
            buttonPlayers[i] = playerN;
        }

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

        // init 9 button
        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);
        }

        // init exit button
        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() {
        // determine winner - horizontal rows
        if (!gameOver) {
            for (int i = 0; i < 3; i++) {
                if ((buttonPlayers[0 + i * 3] != playerN) && (buttonPlayers[0 + i * 3].equals(buttonPlayers[1 + i * 3]))
                        && buttonPlayers[1 + i * 3].equals(buttonPlayers[2 + i * 3])) {
                    winner = buttonPlayers[0 + i * 3];
                    gameOver = true;
                    break;
                }
            }
        }

        // determine winner - vertical rows
        if (!gameOver) {
            for (int i = 0; i < 3; i++) {
                if ((buttonPlayers[i + 0 * 3] != playerN) && (buttonPlayers[i + 0 * 3].equals(buttonPlayers[i + 1 * 3]))
                        && buttonPlayers[i + 1 * 3].equals(buttonPlayers[i + 2 * 3])) {
                    winner = buttonPlayers[i + 0 * 3];
                    gameOver = true;
                    break;
                }
            }
        }

        // determine winner - diagonal rows
        if (!gameOver) {
            int winButtonIndex = -1;

            if ((buttonPlayers[0] != playerN) && (buttonPlayers[0].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[8])) {
                winButtonIndex = 0;
            } else if ((buttonPlayers[2] != playerN) && (buttonPlayers[2].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[6])) {
                winButtonIndex = 2;
            }

            if (winButtonIndex >= 0) {
                winner = buttonPlayers[winButtonIndex];
                gameOver = true;
            }
        }

        // full
        if (count == 9) {
            gameOver = true;
        }

        if (gameOver) {
            String tip = "";
            switch (winner) {
            case playerO:
                tip = "Player O win!";
                break;
            case playerX:
                tip = "Player X win!";
                break;
            default:
                tip = "Draw game!";
                break;
            }

            JOptionPane.showMessageDialog(null, tip);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        for (int i = 0; i < buttons.length; i++) {
            JButton button = buttons[i];
            if (button == e.getSource()) {
                Character currentPlayer = (count % 2 == 1 ? playerX : playerO);
                button.setText(String.valueOf(currentPlayer));
                buttonPlayers[i] = currentPlayer;
                button.setEnabled(false);

                break;
            }
        }
        count++;
        whoWins();
    }

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

about when to call the win check:

check each time you click 1 of the 9 buttons,

about the flag:

I use 2 flag instead of 1 flag to indicate game over & winner, because in TTT game, draw game is very usual, after play several times, you always get draw game ...

a little suggestion to your code:

  • when compare string, use equals(), not ==,
  • define const values in variable, not write it in logic, e.g. 'O' 'X',
  • don't repeat code, try use logic control to make it short & easy to read & easy to maintain,