arithmetic expression Math.random in java - java

the purpose of this program is to let the user try to guess a number up to 20 randomly chosen by the computer. The user inputs their guess. The computer then tells the user if their guess is too high or too low. The user keeps inputting their guess until theu guess correctly. Then they are told how many guesses it took them. The problem is that I am not understanding whether the arithmetic expression in the program generates random numbers from 1 to 20 because when I am inputting numbers from 1 to 20, the pop-up says 'number is too big'.
package pkTopic6Exercise13;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Font;
public class Topic6Exercise13
{
private GuessingGame MyGuessingGame = new GuessingGame();
private Topic6Exercise13()
{//constructor
}
public static void main(String[] args)
{
Topic6Exercise13 myTopic6Exercise13 = new Topic6Exercise13();
myTopic6Exercise13.go();
}
private void go()
{
T6Ex13GUIin myT6Ex13GUIin = new T6Ex13GUIin();
}
private class GuessingGame
{
private int NumToGuess=0;
private int Guess=0;
private int NumGuesses=0;
private GuessingGame()
{//constructor
}
private void GenerateNum()
{
NumToGuess = 1+(int)(20*Math.random());
}
private String CheckNum()
{
NumGuesses = NumGuesses + 1;
if (Guess > NumToGuess)
{
JOptionPane.showMessageDialog(null, Guess + " is too BIG!");
return "NotGuessed";
}
else if (Guess < NumToGuess)
{
JOptionPane.showMessageDialog(null, Guess + " is too SMALL!");
return "NotGuessed";
}
else
{
JOptionPane.showMessageDialog(null, "Well done! " + Guess +" is correct, it took " + NumGuesses + " goes.");
return "Guessed";
}
}
}
private class T6Ex13GUIin extends JFrame
{
private JLabel lblGuess;
private JTextField txfGuess;
private JButton btnPickNumber;
private JButton btnQuit;
private T6Ex13GUIin()
{//constructor
Font fontDialog = new Font("Dialog", Font.BOLD,24);
this.setSize(1000,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(100,0);
this.setTitle("Guessing Game");
this.setLayout(null);
lblGuess = new JLabel("Type Guess:");
lblGuess.setFont(fontDialog);
lblGuess.setBounds(100,200,200,50);
lblGuess.setVisible(false);
this.add(lblGuess);
txfGuess = new JTextField("");
txfGuess.setBounds(300,200,100,50);
txfGuess.setFont(fontDialog);
txfGuess.setVisible(false);
ReturnListener MyReturnListener = new ReturnListener();
txfGuess.addKeyListener(MyReturnListener);
this.add(txfGuess);
ClickListener MyClickListener = new ClickListener();
btnPickNumber = new JButton("Pick Number");
btnPickNumber.setBounds(100,100,750,50);
btnPickNumber.setFont(fontDialog);
btnPickNumber.addActionListener(MyClickListener);
this.add(btnPickNumber);
btnQuit = new JButton("Quit");
btnQuit.setBounds(750,300,100,50);
btnQuit.setFont(fontDialog);
btnQuit.addActionListener(MyClickListener);
this.add(btnQuit);
this.setVisible(true);
}
private class ClickListener implements ActionListener
{
private ClickListener()
{//constructor
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == btnPickNumber)
{
MyGuessingGame.GenerateNum();
MyGuessingGame.NumGuesses=0;
btnPickNumber.setVisible(false);
lblGuess.setVisible(true);
txfGuess.setVisible(true);
txfGuess.setText("");
}
if (e.getSource() == btnQuit)
{
System.exit(0);
}
}
}
private class ReturnListener implements KeyListener
{
private ReturnListener()
{//constructor
}
public void keyPressed(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
if (e.getKeyChar() == '\n')
{
MyGuessingGame.Guess =
Integer.parseInt(txfGuess.getText());
if (MyGuessingGame.CheckNum().equals("Guessed"))
{
lblGuess.setVisible(false);
txfGuess.setVisible(false);
btnPickNumber.setVisible(true);
}
else
{
txfGuess.setText("");
}
}
}
}
}
}

Have you tried any testing? Like, debugging and seeing what value is getting set for NumToGuess? Or perhaps simply displaying the value being set? Then if you know what the random number is, you can test out your logic.
Based on your core logic, I ran this simple code below and didn't experience any problems.
public static void main(String[] args) {
int NumToGuess = 1+(int)(20*Math.random());
int myGuess = Integer.parseInt("10");
System.out.println("Value is: " + NumToGuess);
System.out.println("My Guess: " + myGuess);
if (myGuess > NumToGuess) {
System.out.println("Too Big");
}
else if (myGuess < NumToGuess) {
System.out.println("Too Small");
}
}

Math.rand() generates a random number between 0 and 1 exclusive. So by multiplying by 20 you get a value between 0 and 20 exclusive. By rounding down with the (int) cast it becomes between 0-19 inclusive and by adding one it becomes between 1-20 inclusive. So yes, your number is being generated correctly. However, you do add 1 again at the beginning of the checkNum() method so that could be a problem. Hope this helps.

Related

Trying to update a Java Swing JLabel text field to display new text once an IF condition is met

I'm working on a simple GUI project to get the foundations of Java Swing.
I created a Rock Paper Scissors game which you play against the computer which i implemented a GUI for
My text based GUI Form for Rock, Paper,Scissors
My problem is that once either my score or the computers score reach a value of 3, i want the text on the frame to change. I've tried to implement the code to check each time the variable increases in the button function but it still does not works, neither does implementing the function in the main, the game doesn't change any text or stop once the scores reach 3.
chooseRock.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cc = getCompChoice();
if (cc.equalsIgnoreCase("Paper")) {
compcount++;
if(compcount == 3){
winner.setText("Computer Wins");
}
compChoice.setText("Computers Choice: " + cc);
This code shows the GUI object and the listener for selecting "Rock", the code is the same for both paper and Scissors. Both compchoice and playchoice are declared with the other attributes at the top.
gameScreen(String title){
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(gameBoard);
this.pack();
chooseRock.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cc = getCompChoice();
if (cc.equalsIgnoreCase("Paper")) {
compcount++;
compChoice.setText("Computers Choice: " + cc);
compScore.setText("Computer Score: " + compcount);
} else if (cc.equalsIgnoreCase("Scissors")) {
playcount++;
compChoice.setText("Computers Choice: " + cc);
playerScore.setText("Your Score: " + playcount);
} else {
compChoice.setText("Computers Choice: " + cc + " Its a DRAW!");
}
}
});
This is a function I've written to check the scores and display the winner, the 'winner' text is displayed at the top of the panel and has a placeholder.
public void checkScore(){
if(playcount == 3 ){
winner.setText("GAME OVER - PLAYER WINS");
chooseRock.setEnabled(false);
chooseScissors.setEnabled(false);
choosePaper.setEnabled(false);
}else if(compcount == 3 ){
winner.setText("GAME OVER - COMPUTER WINS! BETTER LUCK NEXT TIME");
chooseRock.setEnabled(false);
chooseScissors.setEnabled(false);
choosePaper.setEnabled(false);
}
}
Is there any way to take the variable written inside the listener and use it to change the text field or is there some way conditions like this should be implemented?
You should call checkScore() within the ActionListeners actionPerformed method so that the score is calculated and acted upon with each button press.
Interesting aside:
One way to simplify your listeners is to create an enum, one that checks for win, something like:
public enum RPS {
ROCK("Rock"), PAPER("Paper"), SCISSORS("Scissors");
private String text;
private RPS(String text) {
this.text = text;
}
public String getText() {
return text;
}
#Override
public String toString() {
return text;
}
This way, your check for win can be as simple as adding a comparing method to the enum:
// returns 1 for win, -1 for loss, 0 for tie
public int compare(RPS other) {
int length = values().length;
int delta = (length + ordinal() - other.ordinal()) % length;
return delta != 2 ? delta : -1;
}
}
Each enum value has an ordinal() method that returns its order of declaration, 0 for ROCK, 1 for PAPER, and 2 for SCISSORS. The delta equation simply gets the difference between these ordinal values, adds 3 (the "size" of the enum) and checks the remainder of the calculation. If it is equal to 1, then that enum "wins" the battle, if 0, then its a tie and if 2, then this enum "loses". This can simplify your listeners.
For example, here I create a single listener class for all buttons:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RockPaperScissors extends JPanel {
public static final int MAX_SCORE = 3;
private static final int PANEL_WIDTH = 600;
private int myScore;
private int compScore;
private JLabel statusLabel = new JLabel(" ");
private JLabel myChoiceLabel = new JLabel();
private JLabel compChoiceLabel = new JLabel();
private JLabel myScoreLabel = new JLabel();
private JLabel compScoreLabel = new JLabel();
private List<Action> actionList = new ArrayList<>();
public RockPaperScissors() {
JPanel statusPanel = new JPanel();
statusPanel.setBorder(BorderFactory.createTitledBorder("Status"));
statusPanel.add(statusLabel);
JPanel scorePanel = new JPanel();
scorePanel.setBorder(BorderFactory.createTitledBorder("Score"));
scorePanel.add(new JLabel("My Score:"));
scorePanel.add(myScoreLabel);
scorePanel.add(Box.createHorizontalStrut(15));
scorePanel.add(new JLabel("Comp Score:"));
scorePanel.add(compScoreLabel);
JPanel selectionPanel = new JPanel();
selectionPanel.setBorder(BorderFactory.createTitledBorder("Selections"));
selectionPanel.add(new JLabel("My Choice:"));
selectionPanel.add(myChoiceLabel);
selectionPanel.add(Box.createHorizontalStrut(15));
selectionPanel.add(new JLabel("Comp Choice:"));
selectionPanel.add(compChoiceLabel);
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 3, 0));
for (RPS rps : RPS.values()) {
Action action = new ButtonAction(rps);
actionList.add(action);
JButton button = new JButton(action);
btnPanel.add(button);
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(statusPanel);
add(scorePanel);
add(selectionPanel);
add(btnPanel);
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int height = superSize.height;
int width = Math.max(superSize.width, PANEL_WIDTH);
return new Dimension(width, height);
}
private class ButtonAction extends AbstractAction {
private RPS rps;
public ButtonAction(RPS rps) {
super(rps.getText());
this.rps = rps;
}
#Override
public void actionPerformed(ActionEvent e) {
int randomValue = (int) (RPS.values().length * Math.random());
RPS compChoice = RPS.values()[randomValue];
myChoiceLabel.setText(rps.getText());
compChoiceLabel.setText(compChoice.getText());
if (rps.compare(compChoice) > 0) {
statusLabel.setText("I Win");
myScore++;
} else if (rps.compare(compChoice) < 0) {
statusLabel.setText("Computer Wins");
compScore++;
} else {
statusLabel.setText("Draw");
}
myScoreLabel.setText(String.valueOf(myScore));
compScoreLabel.setText(String.valueOf(compScore));
if (myScore >= MAX_SCORE) {
statusLabel.setText("I Win the Game");
} else if (compScore >= MAX_SCORE) {
statusLabel.setText("Computer Wins the Game");
}
if (myScore >= MAX_SCORE || compScore >= MAX_SCORE) {
for (Action action : actionList) {
action.setEnabled(false);
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
RockPaperScissors mainPanel = new RockPaperScissors();
JFrame frame = new JFrame("RockPaperScissors");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
enum RPS {
ROCK("Rock"), PAPER("Paper"), SCISSORS("Scissors");
private String text;
private RPS(String text) {
this.text = text;
}
public String getText() {
return text;
}
#Override
public String toString() {
return text;
}
public int compare(RPS other) {
int length = values().length;
int delta = (length + ordinal() - other.ordinal()) % length;
return delta != 2 ? delta : -1;
}
}

Lottery Program Ignores Function

I'm meant to write a program that lists one random number after the other, which it does (along with a beep). However, it ignores a fundamental function needed for the program to run correctly. The ask() function does what it implies, it asks the user to input an integer between the range (1000-9999) which is then compared to the winning number (random) to see if the user correctly guessed it and thus won. I've only recently started writing in Java so I'm not very sure if there's a basic mistake I'm making. Any help would be appreciated!
package edu.pupr.pega4;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Scanner;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class Pega4Driver {
public static void main(String[] args) {
Pega4 test = new Pega4(2000, true);
test.start();
JOptionPane.showMessageDialog(null, "Quit program?");
JOptionPane.showMessageDialog(null, "Perdiste!!!");
System.exit(0);
}
}
class Pega4 {
private int interval; //Time interval for new number to appear
private boolean beep; //BEEP
private int number; //The input number
private int tiradas = 1; //Counter
private int winNum; //The winning number
//Constructor
public Pega4(int interval, boolean beep) {
this.interval = interval;
this.beep = beep;
}
//Returns a random number within a specified range
public double getRandomIntegerBetweenRange(double min, double max){
double x = (int)(Math.random()*((max-min)+1))+min;
return x;
}
public void start() {
class Pega4Inner implements Asker, ActionListener {
Scanner input = new Scanner(System.in);
Date now = new Date();
#Override
public void ask() {
System.out.println("Entrar numero deseado: ");
number = input.nextInt();
//Input Validation
if (number < 1000 || number > 9999)
{
System.out.println("Entrada invalida. Entrar numero deseado: ");
number = input.nextInt();
}
System.out.println(now);
}
#Override
public void actionPerformed(ActionEvent e) {
winNum = (int) getRandomIntegerBetweenRange(1000, 9999);
System.out.println("Tirada #" + (tiradas++) + ": " + winNum);
if (beep)
Toolkit.getDefaultToolkit().beep();
if (winNum == number)
{
JOptionPane.showMessageDialog(null, "Ganaste!!!");
System.exit(0);
}
}
}
ActionListener listener = new Pega4Inner();
Timer timer = new Timer(interval, listener);
timer.start();
}
}
The Pega4Inner class implements an interface named Asker created by me. Its code is as follows:
package edu.pupr.pega4;
public interface Asker {
void ask();
}
You would need to actually call your ask() method from somewhere :)
I think a proper point to do that in your current code would be in the beginning of your actionPerformed() method in Pega4Inner :
public void actionPerformed(ActionEvent e) {
ask();
winNum = (int) getRandomIntegerBetweenRange(1000, 9999);
…
EDIT
Based on your requirement to call ask() only once, one way to do it is by taking this method out of your inner class and put it in your outer class, then call it explicitly in your driver class. So your Pega4 class could look like this :
class Pega4 {
private int interval; //Time interval for new number to appear
private boolean beep; //BEEP
private int number; //The input number
private int tiradas = 1; //Counter
private int winNum; //The winning number
//Constructor
Date now = new Date();
Scanner input = new Scanner(System.in);
public Pega4(int interval, boolean beep) {
this.interval = interval;
this.beep = beep;
}
//Returns a random number within a specified range
public double getRandomIntegerBetweenRange(double min, double max) {
double x = (int) (Math.random() * ((max - min) + 1)) + min;
return x;
}
public void ask() {
System.out.println("Entrar numero deseado: ");
number = input.nextInt();
//Input Validation
while (number < 1000 || number > 9999) { // not IF here
System.out.println("Entrada invalida. Entrar numero deseado: ");
number = input.nextInt();
}
System.out.println(now);
}
public void start() {
class Pega4Inner implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// ask();
winNum = (int) getRandomIntegerBetweenRange(1000, 9999);
System.out.println("Tirada #" + (tiradas++) + ": " + winNum);
if (beep) {
Toolkit.getDefaultToolkit().beep();
}
if (winNum == number) {
JOptionPane.showMessageDialog(null, "Ganaste!!!");
System.exit(0);
}
}
}
ActionListener listener = new Pega4Inner();
Timer timer = new Timer(interval, listener);
timer.start();
}
}
And then in your Pega4Driver class :
...
Pega4 test = new Pega4(2000, true);
test.ask();
test.start();
...

Event driven input vs turn based

I am trying to recreate console game with JTextArea as console/output and JTextField as user input. Since the GUI is event driven I do not understand how could I stop the code from executing, to wait for user input before proceeding with opponents turn. The only solution I can think of is While(userTurn) and userTurn would be changed to false upon actionlistener is there a better way?
My console solution
String getInput(String prompt){
String inputLine = null;
console.setTextConsole(prompt + " ");
try{
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
inputLine = is.readLine();
if(inputLine.length() == 0) return null;
}catch(IOException e){
console.setTextConsole("IOException "+e);
}
return inputLine;
}
I just called this getInput method and I proceeded with opponents turn.
What I want to accomplish is:
Opponents turn
Game waits for user
User types text into JtextField and presses enter
Game executes players command
Opponents turn again ..
I've written an example game so you can observe the difference. The computer and the user try to guess a random number between 0-2 inclusive. Who ever gets it right wins. If both get it right or both get it wrong its a draw.
EDIT: Updated GUI version
Here's the console program:
import java.util.Random;
import java.util.Scanner;
public class ConsoleGame {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
Random rand = new Random();
boolean playAgain = false;
int wins = 0, losses = 0, draw = 0;
do {
int num = rand.nextInt(3); // 0-2 inclusive
System.out.println("Guess the number [0-2]: ");
int guess = Integer.parseInt(console.nextLine());
int computerGuess = rand.nextInt(3);
System.out.println("You: " + guess + "\tComputer: " + computerGuess + "\tNumber: " + num);
if (guess == num && computerGuess == num || guess != num && computerGuess != num) {
draw++;
System.out.println("Draw!");
} else if (guess == num) {
wins++;
System.out.println("You win!");
} else if (computerGuess == num) {
losses++;
System.out.println("Computer wins :(");
}
System.out.println("Play again [y/n]? ");
playAgain = console.nextLine().startsWith("y");
} while (playAgain);
System.out.println("Wins: " + wins + "\nLosses: " + losses + "\nDraw: " + draw);
console.close();
}
}
Here's the GUI program:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class GUIGame extends JFrame {
private JPanel contentPane;
private JTextField textField;
private JTextArea textArea;
private boolean textReceived;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
GUIGame frame = new GUIGame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public GUIGame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
setContentPane(contentPane);
textField = new JTextField();
textField.addActionListener(new ActionListener() {
#Override
// user pressed 'enter' key,
public void actionPerformed(ActionEvent e) {
textReceived = true;
synchronized (textField) {
// notify game loop thread which is waiting on this event
textField.notifyAll();
}
}
});
contentPane.add(textField, BorderLayout.SOUTH);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
textArea = new JTextArea();
textArea.setFont(new Font("Consolas", Font.PLAIN, 12));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setForeground(Color.LIGHT_GRAY);
textArea.setBackground(Color.BLACK);
textArea.setEditable(false);
scrollPane.setViewportView(textArea);
// Start game loop in new thread since we block the thread when
// waiting for input and we don't want to block the UI thread
new Thread(new Runnable() {
#Override
public void run() {
playGame();
}
}).start();
}
private void playGame() {
Random rand = new Random();
boolean playAgain = false;
int wins = 0, losses = 0, draw = 0;
do {
int num = rand.nextInt(3); // 0-2 inclusive
textArea.append("Guess the number [0-2]: \n");
int guess = Integer.parseInt(requestInput());
int computerGuess = rand.nextInt(3);
textArea.append("You: " + guess + "\tComputer: " + computerGuess + "\tNumber: " + num + "\n");
if (guess == num && computerGuess == num || guess != num && computerGuess != num) {
draw++;
textArea.append("Draw!\n");
} else if (guess == num) {
wins++;
textArea.append("You win!\n");
} else if (computerGuess == num) {
losses++;
textArea.append("Computer wins :(\n");
}
textArea.append("Play again [y/n]? \n");
playAgain = requestInput().startsWith("y");
} while (playAgain);
textArea.append("Wins: " + wins + "\nLosses: " + losses + "\nDraw: " + draw + "\n");
}
private String requestInput() {
textField.setEnabled(true);
textField.requestFocus();
// wait on text field till UI thread signals a user input event
synchronized (textField) {
while (!textReceived) {
try {
textField.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
String input = textField.getText();
textField.setText("");
textField.setEnabled(false);
textReceived = false;
return input;
}
}
Well, I think this:
The ruler of the game is that who owns the turn. As long as the ruler make its move, the other must wait. How to implement this?
If the user owns the turn, he/she may enter text in the JTextField.
When he/she presses ENTER, the command must be validated. If it is OK, the turn must be transferred to the program, and meanwhile, the user shall not even be able to enter text in the JTextField. For example, disabling it:
private void switchTurnToTheProgram()
{
jTextField.setEnabled(false);
}
When the program finalizes its move, the turn must be transferred to the user again, and so, the jTextField must be enabled:
private void switchTurnToTheUser()
{
jTextField.setEnabled(true);
}
Last, you must determine in each case whose's first turn (to make the jTextField appear enabled or disabled).
The complete algorithm:
public void startGame(boolean userOwnsTheFirstTurn)
{
if (userOwnsTheFirstTurn)
{
switchTurnToTheUser();
}
else
{
switchTurnToTheProgram();
calculateNextMove();
switchTurnToTheUser();
}
}
public void userHasEnteredSomeCommand(String command)
{
// This must be called from the correspondant actionListener.
if (validateCommand())
{
switchTurnToTheProgram();
calculateNextMove();
switchTurnToTheUser();
}
else
{
... log an error to the user ...
}
}
To enhance the user's experience, maybe it will be useful to enable/disable the button along with the textField. In that case, you'll have to modify just the two methods switchTurnToTheProgram and switchTurnToTheUser.

How can i stop the program from skipping my check the second time around?

I am creating a program to take in sets of binary digits and convert them into hammingcodes (Effectively take in 8 digits, turn into 12, print out) but i am having trouble. Currently, i am using a JTextField for the user to enter their number, then they press a JButton to enter the data. I then do funky shit with that number to put it into a list and confirm that this is the last of the numbers they wish to enter. If they click a JButton called yes (New text in button, but same button) if goes on to do what i need. But if they click the other JButton called no, it goes back and repeats the same process. My problem is after clicking no once, the program stops allowing you to press no at the step to check if you want to add another list of numbers. IT appears to skip the check all together and assume they pressed yes as it does the rest of the working out thats done after all entry is finished.
My code is a tad messy due to messing with it for a few hours.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import javax.swing.*;
public class MainProgram extends JFrame
{
public MainProgram()
{
}
public static void main(String[] args)
{
MainProgram mp = new MainProgram();
mp.run();
}
private void run()
{
java.util.List<Integer> streamSplit = new ArrayList<>();
java.util.List<Integer> tempEight = new ArrayList<>();
java.util.List<Integer> finalStream = new ArrayList<>();
yes.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
checkYes = true;
}
});
no.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
checkNo = true;
}
});
init();
yesChange("Enter");
boolean confirm = false;
int aCheck = 0;
while (aCheck == 0)
{
confirm = false;
while (!confirm)
{
setTopText("<html>Please enter your next 8 bits. Do not enter more than 8 bits.<br> Press Enter when done</html>");
yesChange("Enter");
confirm = checkYes();
}
confirm = false;
setTopText("Digits Successfully added.");
int stream = checkInput();
do
{
streamSplit.add(stream % 10);
stream /= 10;
} while (stream != 0);
setYesNo();
setTopText("<html>Are you finished entering streams?</html>");
yesChange("YES");
noChange("NO");
aCheck = 2;
checkYes();
checkNo();
while (aCheck == 2)
{
if ( checkNo())
{
aCheck = 0;
System.out.println("CrapNo");
}
else if (checkYes())
{
aCheck = 1;
System.out.println("CrapYes");
}
}
}
int arrayLength = streamSplit.size();
int bufferLength = 8 - arrayLength % 8;
int numberOfStreams = 0;
if (bufferLength != 8)
{
numberOfStreams = arrayLength / 8 + 1;
} else
{
numberOfStreams = arrayLength / 8;
}
int tempStreams = numberOfStreams;
System.out.println(numberOfStreams + "<Streams Buffer>" + bufferLength);
while (bufferLength > 0 && bufferLength != 8)
{
streamSplit.add(0);
bufferLength--;
}
while (tempStreams > 0)
{
for (int i = 0; i < 8; i++)
{
tempEight.add(streamSplit.get(i));
}
if ((tempEight.get(0) + tempEight.get(1) + tempEight.get(3) + tempEight.get(4) + tempEight.get(6)) % 2 == 0)
{
tempEight.add(0, 0);
} else
{
tempEight.add(0, 1);
}
if ((tempEight.get(1) + tempEight.get(3) + tempEight.get(5) + tempEight.get(6) + tempEight.get(7)) % 2 == 0)
{
tempEight.add(1, 0);
} else
{
tempEight.add(1, 1);
}
if ((tempEight.get(3) + tempEight.get(4) + tempEight.get(5) + tempEight.get(8) + tempEight.get(9)) % 2 == 0)
{
tempEight.add(3, 0);
} else
{
tempEight.add(3, 1);
}
if ((tempEight.get(7) + tempEight.get(8) + tempEight.get(9) + tempEight.get(10)) % 2 == 0)
{
tempEight.add(7, 0);
} else
{
tempEight.add(7, 1);
}
tempStreams--;
for (int i = 0; i < 12; i++)
{
finalStream.add(tempEight.get(0));
tempEight.remove(0);
}
}
Collections.reverse(streamSplit);
System.out.print("Your original bit-stream was: ");
for (int i = 0; i < numberOfStreams * 2; i++)
{
for (int j = 0; j < 4; j++)
{
System.out.print(streamSplit.get(j + (i * 4)));
}
System.out.print(" ");
}
System.out.println();
System.out.print("Your new HammingCode bit-stream is: ");
for (int i = 0; i < numberOfStreams * 3; i++)
{
for (int j = 0; j < 4; j++)
{
System.out.print(finalStream.get(j + (i * 4)));
}
System.out.print(" ");
}
System.out.println();
}
public Boolean checkYes = false;
public Boolean checkNo = false;
private JFrame frame = new JFrame("Absolute Layout Example");
private JPanel contentPane = new JPanel();
private JLabel topText = new JLabel("Welcome to my Hamming Code Generator", JLabel.CENTER);
private JTextField inputText = new JTextField();
private JButton yes = new JButton("YES");
private JButton no = new JButton("NO");
public void init()
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane.setOpaque(true);
contentPane.setBackground(Color.WHITE);
contentPane.setLayout(null);
topText.setLocation(0, 0);
topText.setSize(400, 50);
topText.setBorder(BorderFactory.createLineBorder(Color.black));
inputText.setLocation(0,50);
inputText.setSize(400,75);
inputText.setBorder(BorderFactory.createLineBorder(Color.black));
yes.setSize(80, 40);
yes.setLocation(60, 135);
no.setSize(80, 40);
no.setLocation(260, 135);
contentPane.add(topText);
contentPane.add(inputText);
contentPane.add(yes);
contentPane.add(no);
frame.setContentPane(contentPane);
frame.setSize(400, 225);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void setTopText(String s)
{
topText.setText(s);
}
public void setYesNo()
{
checkYes = false;
checkNo = false;
}
public Boolean checkYes() {return checkYes;}
public Boolean checkNo() {return checkNo;}
public int checkInput()
{
String temp1 = inputText.getText();
int temp = Integer.parseInt(temp1);
return temp;
}
public void yesChange(String s)
{
yes.setText(s);
}
public void noChange(String s)
{
no.setText(s);
}
}
I find it tough to answer this question not fully knowing what your code is doing, especially the part where you "... do funky #### with that number..."
But I do know that you have significant issues with your program structure, especially within your lengthy run() method where you have numerous nested while (...) loops and do-while loops, code constructs that might seem at home within a linear processing console program but which seems out of place within an event-driven Swing GUI.
What I suggest that you do is try to use some state-dependent coding. For instance, you could give your class the boolean variables, enteringData and dataValidYet, to represent two key states: whether the user is now entering data into the JTextField, and whether that data has yet been validated yet. And then within your JButton ActionListeners, use if and if/else blocks to decide what to do on button push depending on the state of these boolean fields, and likely other key fields of the class.
For a code "skeleton" example, one that doesn't yet do anything, but hopefully will show you the structure I'm talking about:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class StateMachine extends JPanel {
private static final String INITIAL_TITLE = "Please enter your next 8 bits. "
+ "Do not enter more than 8 bits.\n"
+ "Press Enter when done";
private static final String ARE_YOU_FINISHED = "Are you finished entering streams?";
private static final String YES = "Yes";
private static final String ENTER = "Enter";
private static final String NO = "No";
private static int GAP = 8;
private static final int COLUMNS = 30;
// this is a JTextArea built to look like a JLabel
private JTextArea topTextArea = new JTextArea(2, COLUMNS);
private JTextField dataEntryField = new JTextField(COLUMNS);
private JButton yesEnterButton = new JButton(ENTER);
private JButton noButton = new JButton(NO);
private boolean enteringData = true;
private boolean dataValidYet = false;
public StateMachine() {
yesEnterButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
yesEnterButtonActionPerfromed(e);
}
});
noButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
noButtonActionPerfromed(e);
}
});
topTextArea.setWrapStyleWord(true);
topTextArea.setLineWrap(true);
topTextArea.setFocusable(false);
topTextArea.setEditable(false);
topTextArea.setOpaque(false);
topTextArea.setText(INITIAL_TITLE);
JPanel innerButtonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
innerButtonPanel.add(yesEnterButton);
innerButtonPanel.add(noButton);
JPanel outerButtonPanel = new JPanel();
outerButtonPanel.add(innerButtonPanel);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout(GAP, GAP));
add(topTextArea, BorderLayout.PAGE_START);
add(dataEntryField, BorderLayout.CENTER);
add(outerButtonPanel, BorderLayout.PAGE_END);
}
protected void noButtonActionPerfromed(ActionEvent e) {
// TODO depending on state of enteringData and dataValidYet booleans
// change text in buttons, do things with JTextField data
// set state of enteringData and dataValidYet booleans
if (enteringData) {
// a no press is meaningless if entering data
return;
}
// .... more
}
private void yesEnterButtonActionPerfromed(ActionEvent e) {
// TODO depending on state of enteringData and dataValidYet booleans
// change text in buttons, do things with JTextField data
// set state of enteringData and dataValidYet booleans
if (enteringData) {
topTextArea.setText(ARE_YOU_FINISHED);
yesEnterButton.setText(YES);
yesEnterButton.setActionCommand(YES);
enteringData = false;
return;
}
// .... more
}
private static void createAndShowGui() {
StateMachine mainPanel = new StateMachine();
JFrame frame = new JFrame("State Machine");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also, as a "side" recommendation, one unrelated to your main problem, understand that null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Note that if this were my program, I would use more indirection including creating separate classes to separate out the GUI portion of the program from the logic portion.

ActionListener Issue: Program to see if a number is prime or not? (Java GUI)

so my problem with this code is in the ActionListner I believe. When running the program I input a number and nothing happens. The only number that the program will run properly is when I input the number 2. I'm obviously doing something wrong in the for loop but I haven't been able to figure it out yet.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.text.*;
public class Prime implements ActionListener {
JFrame framePrime;
JPanel panelPrime;
JTextField primeTestField;
JLabel stringPrimelLabel, enterNumLabel, trueFalseLabel;
// Constructor
public Prime() {
// Create the frame and container.
framePrime = new JFrame("Prime or Not?");
panelPrime = new JPanel();
panelPrime.setLayout(new GridLayout(2, 2));
// Add the widgets.
addWidgets();
// Add the panel to the frame.
framePrime.getContentPane().add(panelPrime, BorderLayout.CENTER);
// Exit when the window is closed.
framePrime.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Show the converter.
framePrime.pack();
framePrime.setVisible(true);
}
// Create and add the widgets for converter.
private void addWidgets() {
// Create widgets.
primeTestField = new JTextField();
primeTestField.setHorizontalAlignment(JTextField.CENTER);
enterNumLabel = new JLabel("Enter a number: ",
SwingConstants.LEFT);
stringPrimelLabel = new JLabel("Is it Prime?: ",
SwingConstants.LEFT);
trueFalseLabel = new JLabel("Let's Find Out!",
SwingConstants.CENTER);
// Listen to events from Convert textfield.
primeTestField.addActionListener(this);
// Add widgets to container.
panelPrime.add(enterNumLabel);
panelPrime.add(primeTestField);
panelPrime.add(stringPrimelLabel);
panelPrime.add(trueFalseLabel);
panelPrime.setBackground(Color.red);
}
// Implementation of ActionListener interface.
public void actionPerformed(ActionEvent event) {
int n = Integer.parseInt(primeTestField.getText());
if (n == 2) {
trueFalseLabel.setText("Yes");
}
else {
for (int i = 2; 2*i < n; i++) {
if(n % i == 0){
trueFalseLabel.setText("No");
}
else {
trueFalseLabel.setText("Yes");
}
}
}
}
// main method
public static void main(String[] args) {
Prime converter = new Prime();
}
}
ActionListener for JTextField is triggered when you press enter in the text field.
Edit: If you want to do the prime check whenever the value is changed in the text field. As suggested by #MadProgrammer, you can add a DocumentListener to the document of the text field and implement the insertUpdate (called when you add a character) and removeUpdate (called when you remove a character) methods.
primeTestField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e)
check();
}
#Override
public void removeUpdate(DocumentEvent e) {
check();
}
#Override
public void changedUpdate(DocumentEvent e) {
}
});
(PS: I corrected and refactored your prime check logic into a method so that it is correct & reusable)
private void check() {
int n;
try {
System.out.println(primeTestField.getText());
n = Integer.parseInt(primeTestField.getText());
} catch (Exception ex) {
return;
}
if (n == 2) {
trueFalseLabel.setText("Yes");
} else {
boolean isPrime = true;
for (int i = 2; 2 * i < n; i++) {
if (n % i == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
trueFalseLabel.setText("Yes");
} else {
trueFalseLabel.setText("No");
}
}
}

Categories