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

前端 未结 2 1698
旧巷少年郎
旧巷少年郎 2020-12-20 09:45

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 differ

相关标签:
2条回答
  • 2020-12-20 10:37

    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:

    enter image description here

    With GUI looking like:

    enter image description here

    0 讨论(0)
  • 2020-12-20 10:43

    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,
    0 讨论(0)
提交回复
热议问题