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(); final 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, "" + "

Factman is a pretty simple game once you know the rules.
" + "To play, each player will take turns selecting a number
" + "from the list. The player will earn the number of points
" + "equal to the number they selected. But be careful, if you
" + "choose a number not in the list, you loose a turn!

" + "

" + "

When a player chooses a number, the other player will gain
" + "the number of points for each of the factors in the list.
" + "Any number that is used (selected or a factor) is removed
" + "from the list.

" + "

" + "

The player with the highest score when the list is empty wins.

" + "

" + "

Good Luck!

" + "", "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 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_Swing factman = new Factman_Swing(); 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 createList(int limit) { ArrayList temp = new ArrayList(); 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 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 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; } }