Chunky by FelipeFS
Chunky by FelipeFS
GPWiki.org
It is currently Thu Dec 18, 2014 1:25 pm

All times are UTC




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Fri Jul 18, 2014 2:01 am 
Rookie

Joined: Fri Jul 18, 2014 1:07 am
Posts: 3
Hi, this is my first game I've made in Swing. Can you tell me how my code is for my first project and what I should correct for the future when I get more in depth with Swing and other games in general?

It's a simple game. All you do is select a mode to guess the number. The higher the mode, the less guesses you get to guess a number between 1 and 30.

There is one problem I would like advice on. When selecting a mode in the combo box next the the start game button, you can only choose one option per game. Can you help me change it the code so that you can select any mode after already choosing one in the same game where it will take the latest selected mode as the mode for the rest of the game.

Thanks.

Here's the code:

GuessGame.java
Code:
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

import javax.swing.*;

public class GuessGame implements ActionListener {
   public JFrame frame;

   public JLabel input;
   public JLabel output;

   public JPanel mainPanel;
   public JPanel instructionPanel;
   public JPanel gamePanel;

   public JButton start;
   public JButton clear;
   public JButton exit;
   public JButton restart;

   public JComboBox<String> gameSelect;

   public static JTextField gameInput;

   public JTextArea instructionList;
   public static JTextArea gameOutput;

   public JScrollPane scroll;

   private final static int WIDTH = 270;
   private final static int HEIGHT = 240;
   private final static int SCALE = 3;

   public int numClicks = 0;
   public int numOfGuesses = -1;
   public int gameModeFetched = 0;
   public int gameMode = 0;
   public int correctNum = 0;
   public int userGuess = 0;

   public boolean startIsClicked = false;
   public boolean textEntered = false;
   public boolean running = true;
   public boolean gmIsSet = false;
   public boolean modeSelected = false;

   public String mode;

   public String[] modes;

   private final static String i0 = "***********************************************************************************************************************************************************";
   private final static String i1 = "Hello! Welcome to \"Guess the Number\".";
   private final static String i2 = "In this game, you must guess a number between 1 and 30 (Inclusive).";
   private final static String i3 = "Select your desired game mode (easy, normal, or hard) using the dropdown box.";
   private final static String i4 = "Be careful, you only get one chance per game to set it. After selecting your mode, click \"Start Game\".";
   private final static String i5 = "In easy mode, you get 20 guesses, in normal, 15 guesses, and in hard, 10 guesses.";
   private final static String i6 = "Please make sure that you have clicked the start button before entering a number.";
   private final static String i7 = "After typing your guess in the input box, press enter on your keyboard to check it.";
   private final static String i8 = "To relaunch the game, just press the \"Restart Game\" button.";
   private final static String i9 = "Made by: Kishan Patel";
   private final static String i10 = "Programmed in Java";
   private final static String i11 = "Graphics: Java Swing";
   private final static String newLine = "\n";

   public GuessGameMethods ggm;

   public Random r;

   public GuessGame() {
      ggm = new GuessGameMethods();

      r = new Random();

      correctNum = ggm.generateRandomNum(r);

      modes = new String[4];
      modes[0] = "";
      modes[1] = "Easy";
      modes[2] = "Normal";
      modes[3] = "Hard";

      frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("Guess the Number");
      frame.setSize(WIDTH * SCALE, HEIGHT * SCALE);
      frame.setLocationRelativeTo(null);
      frame.setResizable(false);

      input = new JLabel("Input here:");
      output = new JLabel("Output Console:");

      start = new JButton("Start Game");
      clear = new JButton("Clear Output Console");
      exit = new JButton("Exit Game");
      restart = new JButton("Restart Game");

      gameSelect = new JComboBox<String>();

      mainPanel = new JPanel();
      instructionPanel = new JPanel();
      gamePanel = new JPanel();

      mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

      instructionList = new JTextArea(13, 1);
      instructionList.setEditable(false);
      instructionList.setBackground(Color.WHITE);
      instructionList.setFont(new Font(Font.DIALOG, Font.BOLD, 14));
      instructionList.setBorder(BorderFactory.createLineBorder(Color.BLACK));
      instructionList.setPreferredSize(new Dimension(WIDTH * SCALE - 26, 100));

      // prints instructions to the instructionsList JTextArea
      instructionList.append(i0 + newLine);
      instructionList.append(i1 + newLine);
      instructionList.append(i2 + newLine);
      instructionList.append(i3 + newLine);
      instructionList.append(i4 + newLine);
      instructionList.append(i5 + newLine);
      instructionList.append(i6 + newLine);
      instructionList.append(i7 + newLine);
      instructionList.append(i8 + newLine);
      instructionList.append(i9 + newLine);
      instructionList.append(i10 + newLine);
      instructionList.append(i11 + newLine + i0);

      gameSelect.setPreferredSize(new Dimension(199, 36));
      gameSelect.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));
      gameSelect.addItem(modes[0]);
      gameSelect.addItem(modes[1]);
      gameSelect.addItem(modes[2]);
      gameSelect.addItem(modes[3]);
      gameSelect.addActionListener(this);

      start.addActionListener(this);
      start.setPreferredSize(new Dimension(199, 36));
      start.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

      exit.addActionListener(this);
      exit.setPreferredSize(new Dimension(199, 36));
      exit.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

      clear.addActionListener(this);
      clear.setPreferredSize(new Dimension(301, 36));
      clear.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

      restart.addActionListener(this);
      restart.setPreferredSize(new Dimension(301, 36));
      restart.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

      input.setFont(new Font(Font.DIALOG, Font.BOLD, 14));
      output.setFont(new Font(Font.DIALOG, Font.BOLD, 14));

      gameInput = new JTextField();
      gameInput.addActionListener(this);
      gameInput.setEditable(true);
      gameInput.setBackground(Color.WHITE);
      gameInput.setBorder(BorderFactory.createLineBorder(Color.BLACK));
      gameInput.setPreferredSize(new Dimension(WIDTH * SCALE - 30, 25));

      gameOutput = new JTextArea();
      gameOutput.setEditable(false);
      gameOutput.setBackground(Color.WHITE);
      gameOutput.setPreferredSize(new Dimension(WIDTH * SCALE - 30, 850));
      gameOutput.setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

      scroll = new JScrollPane(gameOutput, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      scroll.setPreferredSize(new Dimension(WIDTH * SCALE - 30, 250));
      scroll.setBorder(BorderFactory.createLineBorder(Color.BLACK));

      frame.getContentPane().add(mainPanel);

      mainPanel.add(instructionPanel);
      mainPanel.add(gamePanel);

      instructionPanel.add(instructionList);
      instructionPanel.add(gameSelect);
      instructionPanel.add(start);
      instructionPanel.add(exit);
      instructionPanel.add(clear);
      instructionPanel.add(restart);

      gamePanel.add(input);
      gamePanel.add(gameInput);
      gamePanel.add(output);
      gamePanel.add(scroll);

      frame.setVisible(true);
   }

   public static void main(String[] args) {
      new GuessGame();
   }

   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == gameSelect) {
         if (modeSelected == false) {
            if (gameSelect.getSelectedIndex() == 1) {
               gameMode = 1;
               mode = "easy";
               modeSelected = true;
            } else if (gameSelect.getSelectedIndex() == 2) {
               gameMode = 2;
               mode = "normal";
               modeSelected = true;
            } else if (gameSelect.getSelectedIndex() == 3) {
               gameMode = 3;
               mode = "hard";
               modeSelected = true;
            }
         }
      }

      if (e.getSource() == start && modeSelected) {
         numClicks += 1;
         if (numClicks == 1) {
            startIsClicked = true;
            gameOutput.append("You are now playing in " + mode + " mode" + newLine + "Enter your guess in the input box." + newLine);
         }
      }

      if (e.getSource() == gameInput && startIsClicked && ggm.containsOnlyNumbers(gameInput.getText())) {
         if (gameMode == 1) {
            userGuess = Integer.parseInt(gameInput.getText());
            if (numOfGuesses < 19) {
               if (userGuess == correctNum) {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Congratulations, you win!" + newLine);
                  gameOutput.append("To play again, just click \"Restart Game\"." + newLine + "Otherwise, you can just exit by clicking \"Exit Game\".");
                  gameInput.setEditable(false);
               } else {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Try again" + newLine);
                  numOfGuesses++;
               }
            } else {
               gameOutput.append("It seems you have run out of moves." + newLine + "Try again at another game!");
               gameInput.setEditable(false);
            }
         } else if (gameMode == 2) {
            userGuess = Integer.parseInt(gameInput.getText());
            if (numOfGuesses < 14) {
               if (userGuess == correctNum) {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Congratulations, you win!");
                  gameInput.setEditable(false);
               } else {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Try again" + newLine);
                  numOfGuesses++;
               }
            } else {
               gameOutput.append("It seems you have run out of moves." + newLine + "Try again at another game!");
               gameInput.setEditable(false);
            }
         } else if (gameMode == 3) {
            userGuess = Integer.parseInt(gameInput.getText());
            if (numOfGuesses < 9) {
               if (userGuess == correctNum) {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Congratulations, you win!");
                  gameInput.setEditable(false);
               } else {
                  gameOutput.append(Integer.toString(userGuess) + newLine);
                  gameOutput.append("Try again" + newLine);
                  numOfGuesses++;
               }
            } else {
               gameOutput.append("It seems you have run out of moves." + newLine + "Try again at another game!");
               gameInput.setEditable(false);
            }
         }
      }

      // clears the output console when the clear button is pressed
      if (e.getSource() == clear && startIsClicked) {
         gameOutput.setText("You are now playing in " + mode + " mode" + newLine + "Enter your guess in the input box." + newLine);
      }

      // clears current text in the input field
      if (e.getSource() == gameInput) {
         gameInput.setText("");
      }

      // exits the application when the exit button is pressed
      if (e.getSource() == exit) {
         System.exit(0);
      }

      if (e.getSource() == restart) {
         frame.dispose();
         new GuessGame();
      }

   }
}


GuessGameMethods.java
Code:
import java.util.Random;

public class GuessGameMethods {

   public boolean containsOnlyNumbers(String str) {
      // It can't contain only numbers if it's null or empty...
      if (str == null || str.length() == 0) return false;

      for (int i = 0; i < str.length(); i++) {
         // If we find a non-digit character we return false.
         if (!Character.isDigit(str.charAt(i))) return false;
      }

      return true;
   }

   public int generateRandomNum(Random r) {
      int randomNumber = 0;
      int[] array = new int[30];
      for (int i = 0; i < array.length; i++) {
         array[i] = i + 1;
      }
      int position = r.nextInt(array.length);
      randomNumber = array[position];

      return randomNumber;
   }
}


Top
 Profile  
 
PostPosted: Sun Jul 20, 2014 4:20 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3825
Location: South Africa
Code looks good - nice work!

Quote:
There is one problem I would like advice on. When selecting a mode in the combo box next the the start game button, you can only choose one option per game.

I don't have JDK installed on my box so can't run your code but I think it's coming down to setting modeSelected=false again after the game is complete. So after gameOutput.append("Try again" + newLine); try put a modeSelected = false.


Some random notes / nitpicking:

  • I like that you named the panels like mainPanel. I think you should do the same for the labels, frames and buttons. Makes the code easier to read without having to check the definition of "start" or "clear" for example.
  • I think you should have called i0..i11 something more descriptive like "instructionListLines". Also, whenever you find yourself repeating the same code over multiple lines - use a for loop rather. So you could define instructionListLines = new String[]{"line 1", "line 2", ... } and then when you add them to instructionList use a for loop to say instructionList.append(instructionListLines[i ] + newLine); Same goes for gameSelect.addItem(modes[i ]);
  • There is a standard java property for OS independant newline, you should use this as the value for newLine (newLine = System.getProperty("line.separator")). It might not matter for this but good habit in case you end up writing text files.
  • Looks like modes should be an enum and gameMode should be declared as that enum type.
  • GuessGameMethods should have static methods, it doesn't hold any state between method calls so there's no need to force the user to create an instance of the class. But I don't think it's really necessary to put those two methods in a separate class anyway, they don't seem like the kind of methods that will be re-used from multiple different classes.
  • generateRandomNum seems like a convoluted way of generating a number from 1 to 30. That int[] array should probably be a private static member variable to avoid regenerating it every time the method is called - that object has to get garbage collected every time the method ends but it never changes between calls. The method populates an array with ints from 1 to 30 and then chooses a random position and pulls that integer out - this could all be replaced by a call to Random.nextInt(30)+1.
  • the containsOnlyNumbers method could be replaced by a call to Integer.parseInt, wrapped in a try..catch for the NumberFormatException. Or maybe keep the containsOnlyNumbers but call Integer.parseInt(str.trim()) for robustness.
  • Honestly I'm not sure how proper swing programming should look but I think that actionPerformed method is too big. I would split this up into several methods for each handler. Like if (e.getSource() == gameSelect) {gameSelectHandler();}. Actually you should probably break this up by not going exit.addActionListener(this); for all objects. I see some code samples where they create an anonymous class and put the listener code there. Looks a bit clunky but it's more efficient and a bit clearer than cascading through a bunch of if's to find the correct handler code.
    Code:
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ...
            }
        });
  • Your main logic (in the big if e.getSource() == gameInput etc..) repeats the same logic 3 times, you should move this out to another method. Looks like the limit for numOfGuesses is the only thing that changes between the modes.

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Mon Jul 21, 2014 7:46 pm 
Rookie

Joined: Fri Jul 18, 2014 1:07 am
Posts: 3
Thank you so much on the positive feedback. I will definitely implement this into my existing code and future projects.


Top
 Profile  
 
PostPosted: Tue Jul 22, 2014 8:04 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3825
Location: South Africa
Cool man, hope you stick around the forums and keep us updated with your progress :)

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
cron

Powered by phpBB® Forum Software © phpBB Group