Factman - игра с двумя игроками

Я не уверен, что кто-то еще когда-либо слышал о Factman, или даже там, откуда это название, но мой учитель AP Computer Science называет этот проект Factman, так вот что я собираюсь делать.

Именование в сторону, игра проста. Игроки по очереди выбирают из списка номеров. Они получают число, добавленное к их счету, но другой игрок получает сумму факторов. Количество и все факторы удаляются из списка, и игроки должны выбирать из оставшихся номеров во всех последующих раундах. Когда список пуст, побеждает игрок с более высоким счетом.

package games;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.Box;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

class Factman_GUI extends JFrame {
    static JPanel panel;
    static JMenuBar menubar;
    static JCheckBoxMenuItem hideBoard;
    static JLabel p1ScoreLabel, p2ScoreLabel, turnIndicator, gameAreaLabel;
    static String userInput;
    static int userSelection = -1;
    static boolean newGameFlag = false;

    public Factman_GUI() {
        initGUI();
    }

    private void initGUI() {
        panel = new JPanel(new GridBagLayout());
        add(panel);

        // Generate the menu at the top of the window
        createMenu();

        //////////////////////////////////////////////////
        // First row, score labels
        // Score values will split all extra space evenly
        //
        GridBagConstraints c = new GridBagConstraints();
        JLabel p1Label = new JLabel("Player 1 Score:  ");
        c.anchor = GridBagConstraints.LINE_START;
        c.gridx = 0;
        c.gridy = 0;
        panel.add(p1Label, c);

        c = new GridBagConstraints();
        p1ScoreLabel = new JLabel("0");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.LINE_START;
        c.gridx = 1;
        c.gridy = 0;
        c.weightx = 0.5;
        panel.add(p1ScoreLabel, c);

        c = new GridBagConstraints();
        JLabel p2Label = new JLabel("Player 2 Score:  ");
        c.anchor = GridBagConstraints.LINE_START;
        c.gridx = 2;
        c.gridy = 0;
        panel.add(p2Label, c);

        c = new GridBagConstraints();
        p2ScoreLabel = new JLabel("0");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.LINE_START;
        c.gridx = 3;
        c.gridy = 0;
        c.weightx = 0.5;
        panel.add(p2ScoreLabel, c);

        //////////////////////////////////////////////////
        // Second row, main content area.
        // This spans all 4 columns and 2 rows
        //
        c = new GridBagConstraints();
        JPanel gameArea = new JPanel();
        gameArea.setLayout(new GridBagLayout());
        c.fill = GridBagConstraints.BOTH;
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 4;
        c.gridheight = 2;
        c.weighty = 1;
        panel.add(gameArea, c);

            c = new GridBagConstraints();
            gameAreaLabel = new JLabel("");
            c.anchor = GridBagConstraints.CENTER;
            c.fill = GridBagConstraints.BOTH;
            gameArea.add(gameAreaLabel, c);

        //////////////////////////////////////////////////
        // Third row, input area
        // This row contains another panel with its own layout
        // The first row indicates whose turn it is,
        // the second row takes user input. The text
        // field will take up all extra space
        //
        JPanel inputPanel = new JPanel();
        inputPanel.setLayout(new GridBagLayout());
        c = new GridBagConstraints();
        c.fill = GridBagConstraints.BOTH;
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 4;
        c.weightx = 1;
        panel.add(inputPanel, c);

            c = new GridBagConstraints();
            turnIndicator = new JLabel("It is Player 1's Turn");
            c.gridx = 0;
            c.gridy = 0;
            c.gridwidth = 4;
            inputPanel.add(turnIndicator, c);

            c = new GridBagConstraints();
            JLabel inputLabel = new JLabel("Enter your selection: ");
            c.fill = GridBagConstraints.BOTH;
            c.gridx = 0;
            c.gridy = 1;
            inputPanel.add(inputLabel, c);

            c = new GridBagConstraints();
            JTextField inputField = new JTextField();
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridx = 1;
            c.gridy = 1;
            c.gridwidth = 3;
            c.weightx = 1;
            inputField.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    userInput = inputField.getText();
                    try {
                        userSelection = Integer.parseInt(userInput);
                    } catch (NumberFormatException e) {
                        System.out.println("No number entered...");
                    }
                    System.out.println(userInput);
                    inputField.setText("");
                }
            });
            inputPanel.add(inputField, c);


        // Set basic window properties
        setTitle("Factman Game");
        setSize(600,200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenu() {
        menubar = new JMenuBar();

        // Create the file menu
        JMenu filem = new JMenu("File");
        filem.setMnemonic(KeyEvent.VK_F);

        JMenuItem newGame = new JMenuItem("New Game");
        newGame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
            ActionEvent.CTRL_MASK));
        newGame.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                int response = JOptionPane.showConfirmDialog(
                    panel,
                    "You are about to start a new game.\n"+
                    "Your current game will be lost.",
                    "Confirm New Game",
                    JOptionPane.OK_CANCEL_OPTION,
                    JOptionPane.WARNING_MESSAGE);
                if (response == 0) newGameFlag = true;
            }
        });

        JMenuItem quit = new JMenuItem("Exit");
        quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
            ActionEvent.CTRL_MASK));
        quit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                System.exit(0);
            }
        });

        filem.add(newGame);
        filem.addSeparator();
        filem.add(quit);

        // create the view menu
        JMenu viewm = new JMenu("View");
        viewm.setMnemonic(KeyEvent.VK_V);

        hideBoard = new JCheckBoxMenuItem("Hide Game Board");
        hideBoard.setState(false);        
        viewm.add(hideBoard);

        // Create the help menu
        JMenu helpm = new JMenu("Help");
        helpm.setMnemonic(KeyEvent.VK_H);

        JMenuItem gameInstructions = new JMenuItem("How to Play");
        gameInstructions.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                JOptionPane.showMessageDialog(
                    panel,
                    "<html>" +
                        "<p>Factman is a pretty simple game once you know the rules.<br>" +
                           "To play, each player will take turns selecting a number<br>" +
                           "from the list. The player will earn the number of points<br>" +
                           "equal to the number they selected. But be careful, if you<br>" +
                           "choose a number not in the list, you loose a turn!</p>" +
                        "<p></p>" +
                        "<p>When a player chooses a number, the other player will gain<br>" +
                           "the number of points for each of the factors in the list.<br>" +
                           "Any number that is used (selected or a factor) is removed<br>" +
                           "from the list.</p>" +
                        "<p></p>" +
                        "<p>The player with the highest score when the list is empty wins.</p>" +
                        "<p></p>" +
                        "<p>Good Luck!</p>" +
                    "</html>",
                    "How to Play",
                    JOptionPane.INFORMATION_MESSAGE);

            }
        });

        helpm.add(gameInstructions);        

        // Populate the menu bar
        menubar.add(filem);
        menubar.add(viewm);
        menubar.add(Box.createHorizontalGlue());
        menubar.add(helpm);

        // Set the menu bar in the panel
        setJMenuBar(menubar);
    }
}

public class Factman_Swing extends Factman_GUI {
    static ArrayList<Integer> gameBoard;
    static int upperBound, factorIndex, p1Score = 0, p2Score = 0;
    static boolean player1 = true;

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Factman_GUI factman = new Factman_GUI();
                factman.setVisible(true);
            }
        });

        playGame();
    }

    public static void playGame() {
        // set the flag false to prevent a new game when someone wins
        newGameFlag = false;
        // make sure the label text is black
        // gameAreaLabel.setForeground(Color.black);

        // create a popup window to get the upper bound
        upperBound = Integer.parseInt(JOptionPane.showInputDialog(
            panel, "Enter the upper bound for this game", null));
        System.out.println("Upper bound = " + upperBound);

        // generate the arraylist with the given upper limit
        gameBoard = createList(upperBound);
        System.out.println(gameBoard);

        // as long as there are numbers left in the list, keep looping the game
        while(!gameBoard.isEmpty()) {
            // if the new game option was selected, go back to main
            if (newGameFlag) return;

            // show the list in the GUI
            gameAreaLabel.setVisible(!hideBoard.getState());
            gameAreaLabel.setText(gameBoard.toString());

            // indicate whose turn it is in the GUI
            if(player1) turnIndicator.setText("It's Player 1's Turn");
            else        turnIndicator.setText("It's Player 2's Turn");

            // userSelection becomes non-zero when a
            // number is entered in the text field
            if (userSelection >= 0) {
                // save the input and set it back to zero
                // so the loop doesnt fire again
                int selection = userSelection;
                userSelection = -1;
                System.out.println("User selected " + selection);

                // wrap the selection in an Integer object for comparison with the list
                Integer number = new Integer(selection);
                // the player will loose his/her turn if an invalid number is entered
                if (!gameBoard.contains(number)) {
                    JOptionPane.showMessageDialog(
                        panel,
                        "The number you selected is not in the list.\nYou loose a turn",
                        "OOPS",
                        JOptionPane.ERROR_MESSAGE);
                    player1 = !player1;
                    continue;
                }

                // add the selection to the current player's score
                if (player1) p1Score += selection;
                else         p2Score += selection;

                // search for and remove the selection from the list
                removeInt(gameBoard, selection);

                // as long as there are factors, add them to the other
                // players score and remove them from the list
                do {
                    factorIndex = findFactor(gameBoard, selection);
                    if (factorIndex >= 0) {
                        int value = gameBoard.get(factorIndex).intValue();
                        if (player1) p2Score += value;
                        else         p1Score += value;
                        // remove the factor
                        removeInt(gameBoard, value);
                    }
                } while (factorIndex >= 0);    // loop until no factor is found

                // show the scores in the GUI
                p1ScoreLabel.setText(String.valueOf(p1Score));
                p2ScoreLabel.setText(String.valueOf(p2Score));

                // switch players
                player1 = !player1;
            }
        }

        // Show who won
        gameAreaLabel.setForeground(Color.blue);
        if (p1Score > p2Score)       gameAreaLabel.setText("PLAYER 1 WINS!!!!");
        else if (p1Score < p2Score)  gameAreaLabel.setText("PLAYER 2 WINS!!!!");
        else gameAreaLabel.setText("Somehow, you managed to tie.  Nice going.");
    }

    /**
     * Create a list of Integer objects from 1 to limit, inclusive.
     * @param limit the upper bound of the list
     * @return an ArrayList of Integer type 
     */
    public static ArrayList<Integer> createList(int limit) {
        ArrayList<Integer> temp = new ArrayList<Integer>();
        for (int i = 1; i <= limit; i ++) {
            temp.add(new Integer(i));
        }
        return temp;
    }

    /**
     * Search for the specified value in the list and remove the object
     * from the list. The remove method of the ArrayList class removes
     * the object and shifts all of the objects following it to the
     * left one index.
     * @param list  an ArrayList of Integers to search
     * @param value the value to remove from the list
     * @see java.util.ArrayList#remove
     */
    private static void removeInt(ArrayList<Integer> list, int value) {
        // loop through the list until the value of the object matches
        // the specified value, then remove it
        for (int i = 0; i < list.size(); i ++) {
            if (list.get(i).intValue() == value) {
                list.remove(i);
            }
        }
    }

    /**
     * Returns the index of the first factor of the specified number in
     * the specified ArrayList.  If no factor is found, -1 is returned.
     * @param list   an ArrayList of Integers to search
     * @param number the value to find factors of
     * @return the index of the first factor, or -1 if no factors exist
     */
    private static int findFactor(ArrayList<Integer> list, int number) {
        // loop through the list until the end or the specified number
        // this prevents index exceptions
        for (int i = 0; i < list.size() && i < number; i ++) {
            // check if the value divides evenly into the number
            if (number % list.get(i).intValue() == 0) {
                return i;
            }
        }
        // we only get here if no index was found
        return -1;
    }
}

Любые мысли, вопросы, предложения будут высоко оценены. Я довольно новичок в java, и это мое первое swing-приложение, поэтому не удивляйтесь любому фанк-коду.

11 голосов | спросил Eric Roch 16 FebruaryEurope/MoscowbMon, 16 Feb 2015 05:31:55 +0300000000amMon, 16 Feb 2015 05:31:55 +030015 2015, 05:31:55

2 ответа


7

Крупные методы

Ваши методы определенно слишком велики. Как правило, если метод не подходит на экране, становится трудно понять и поддерживать.

Попробуйте извлечь код в свои собственные методы, чтобы каждый метод делал только одно.

В качестве примера ваш метод playGame делает:

  • собрать предварительные настройки игры для текущей игры (верхняя граница)
  • управлять игровым контуром
  • управляет GUI (переключает видимость, отображает информацию о пользователе и т. д.)
  • управляет игровыми счетами
  • управляет логикой игры.
  • отображает информацию после игры (кто выиграл)

Это слишком много для одного метода. Извлечение кода в методы также уменьшит ваши комментарии в коде, если вы выберете хорошие имена методов.

OOP

Одна из причин, по которой ваши методы настолько велики, что у вас есть только два класса (с неясными обязанностями); Я бы добавил намного больше классов. Часто бывает проще сначала набросать их на листе бумаги, вот некоторые общие идеи, которые помогут вам начать:

  • UserInput: интерфейс и реализация класса, чтобы получить пользовательский ввод. Таким образом, вы можете позже легко обменять способ ввода.
  • PrintDebug: интерфейс и класс реализации для всех ваших инструкций system.out.print. Таким образом, будет очень легко впоследствии отключить это, зарегистрировать его в файле и т. Д.
  • Game: здесь вы можете поместить свою логику игры (и, возможно, игровой цикл, если вы не поместите это в свой класс). Это не будет содержать никакой информации о том, как реально отображать игру. Таким образом, вы всегда знаете, где искать изменение логики игры, и вы можете легко обменивать метод отображения, если хотите.
  • GUI: интерфейс и реализующий класс; это содержит отображение игры. Я бы, вероятно, добавил, например, меню в свой собственный GUI-класс.
  • Controller: этот класс объединяет все остальные классы.

Нейминг

  • Factman_Swing и Factman_GUI не очень хорошие имена , Они оба выражают похожие значения (gui), и кажется, что GUI фактически содержит больше элементов поворота, чем swing литий>
  • c, filem, viewm, а helpm - не очень хорошие имена.

Комментарии

  • Ваши комментарии JavaDoc замечательные.
  • , но ваши комментарии в коде немного, а иногда и на самом деле ухудшают читаемость. например, make sure the label text is black или // indicate whose turn it is in the GUI не сообщает читателю ничего, что код еще не сделал. Комментарии в коде должны документировать, почему вы что-то делаете, а не то, что вы делаете (хороший код, имена методов и комментарии JavaDoc делают это).

Юзабилити

  • , когда я начинаю новую игру, вместо нового списка отображается PLAYER X WINS!!!!!, а новая игра не запускается

Разное

  • ваши поля должны быть private (а не статические, см. ООП). Если они необходимы вне класса, добавьте геттеры.
  • всегда используют фигурные скобки, даже для однострочных операторов.
  • ваш отступ иногда выключается, что затрудняет чтение вашего кода.
  • Integer number = new Integer(selection); не требуется.
  • removeInt: вы можете просто использовать list.removeAll((Integer) value); или list.removeAll(new Integer(value)); вместо того, чтобы выполнять удаление самостоятельно.
ответил tim 16 FebruaryEurope/MoscowbMon, 16 Feb 2015 17:32:05 +0300000000pmMon, 16 Feb 2015 17:32:05 +030015 2015, 17:32:05
4

Используйте улучшенные для циклов для лучшей производительности:

Например, вместо

private static void removeInt(ArrayList<Integer> list, int value) {
        // loop through the list until the value of the object matches
        // the specified value, then remove it
        for (int i = 0; i < list.size(); i ++) {
            if (list.get(i).intValue() == value) {
                list.remove(i);
            }
        }
}

делать

private static void removeInt(ArrayList<Integer> list, int value) {
        // loop through the list until the value of the object matches
        // the specified value, then remove it
        for (Integer element:list) {
            if (element == value) {
                list.remove(element);
            }
        }
}

Также обратите внимание, что, поскольку Java 5 вам не нужно вызывать intValue(), так как это преобразование из Integer в int выполняется автоматически автообношением.

ответил barq 16 FebruaryEurope/MoscowbMon, 16 Feb 2015 10:35:42 +0300000000amMon, 16 Feb 2015 10:35:42 +030015 2015, 10:35:42

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132