This question already has answers here:
Generating Unique Random Numbers in Java
(21 answers)
Creating random numbers with no duplicates
(20 answers)
Closed 10 months ago.
In this code, when a button is pressed, it shows a random number. I don't want that number to repeat itself. I have it so that when a big button is pushed, a number generates 1-10. I want it so that IF that number is duplicated it runs the code again to find another number that works. I've been working on it for a while and tried a lot of things. Any tips/tricks would be great. Thank you.
class HiLow extends JFrame implements ActionListener{
int NumberGenerated;
JButton Push, High,Low, Bank;
JLabel Score;
int helpInt = 0;
int counterInt = 0;
ArrayList<Integer> numberList = new ArrayList<Integer>();
int size = numberList.size();
boolean hp = true;
HiLow(){
JFrame l = new JFrame();
// JOptionPane.showMessageDialog(l, "Press the 'Push' button\nThen look at the number rolled\nThere will be numbers from 1-10\nThen click higher or lower\nYou can bank your points using the bank button\nMost points after 5 spins wins\nGood luck!");
Push = new JButton("Push For Number");
High = new JButton("Higher");
Low = new JButton("Lower");
Bank = new JButton("Bank Points");
Score = new JLabel("");
add(Push);
add(High);
add(Low);
add(Bank);
add(Score);
Push.addActionListener(this);
High.addActionListener(this);
Low.addActionListener(this);
Bank.addActionListener(this);
Push.setBounds(150,150,200,200);
High.setBounds(10,420,100,50);
Low.setBounds(390,420,100,50);
Bank.setBounds(10,10,100,50);
Score.setBounds(205,100, 150,50);
High.setEnabled(false);
Low.setEnabled(false);
setLayout(null);
setSize(500, 500);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==Push){
helpInt++;
int max = 10;
int min = 1;
int range = max - min + 1;
// if(size >= 5) {
// High.setEnabled(false);
// Low.setEnabled(false);
// Push.setEnabled(false);
// }
do {
int NumberGenerated = (int)(Math.random() * range) + min;
if(numberList.contains(NumberGenerated)) {
High.setEnabled(false);
Low.setEnabled(false);
Push.setEnabled(true);
invalidate();
validate();
repaint();
}else {
String score = String.valueOf(NumberGenerated);
Score.setText("You Rolled: " + score);
numberList.add(NumberGenerated);
System.out.println(numberList);
hp=false;
}
}while(hp == true);
invalidate();
validate();
repaint();
if(helpInt == 1) {
High.setEnabled(true);
Low.setEnabled(true);
Push.setEnabled(false);
}
}
////////////////
if(e.getSource()==High){
helpInt--;
counterInt++;
if(helpInt == 0) {
High.setEnabled(false);
Low.setEnabled(false);
Push.setEnabled(true);
}
//if(size >= 5) {
// High.setEnabled(false);
// Low.setEnabled(false);
// Push.setEnabled(false);
//}
}
////////////////
if(e.getSource()==Low){
helpInt--;
counterInt++;
if(helpInt == 0) {
High.setEnabled(false);
Low.setEnabled(false);
Push.setEnabled(true);
}
//if(size >= 5) {
// High.setEnabled(false);
// Low.setEnabled(false);
// Push.setEnabled(false);
//}
}
////////////////
}
}
I am trying to get my Asteroids game in Java to have the ArrayList container be removed once it's off screen. I figured out how to stop having it print when off screen, but can see in my console the array continues to grow. Not sure where to go from here.
I think the way I can get them to be removed when off screen is by either using the remove or set feature with arrayLists. Visually everything is disappearing right, but in the console my ArrayList is still growing. I thought about setting a limit of how long it can be, but not sure if there is a better way than that.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Iterator;
public class AsteroidGame extends Frame {
private int FrameWidth = 500;
private int FrameHeight = 400;
static public void main(String[] args) {
AsteroidGame world = new AsteroidGame();
world.show();
world.run();
}
public AsteroidGame() {
setTitle("Asteroid Game0");
setSize(FrameWidth, FrameHeight);
addKeyListener(new keyDown());
addWindowListener(new CloseQuit());
}
public void run() {
while (true) {
movePieces();
repaint();
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
}
private ArrayList asteroids = new ArrayList();
private ArrayList rockets = new ArrayList();
private Station station = new Station(FrameWidth / 2, FrameHeight - 20);
public void paint(Graphics g) {
station.paint(g);
Iterator astIt = asteroids.iterator();
while (astIt.hasNext()) {
Asteroid rock = (Asteroid) astIt.next();
if (rock.y >= 400 || rock.x >= 500){
rock = null;
} else {
rock.paint(g);
}
}
Iterator rocIt = rockets.iterator();
while (rocIt.hasNext()) {
Rocket rock = (Rocket) rocIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.paint(g);
}
}
}
public void movePieces() {
if (Math.random() < 0.3) {
Asteroid newRock = new Asteroid(FrameWidth * Math.random(), 20, 10 * Math.random() - 5, 3 + 3 * Math.random());
if (newRock.y >= 500 || newRock.x >= 500){
asteroids.remove(0);
} else{
asteroids.add(newRock);
}
System.out.println(asteroids.size());
}
Iterator astIt = asteroids.iterator();
while (astIt.hasNext()) {
Asteroid rock = (Asteroid) astIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.move();
station.checkHit(rock);
}
}
Iterator rocIt = rockets.iterator();
while (rocIt.hasNext()) {
Rocket rock = (Rocket) rocIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.move(asteroids);
}
}
}
private class gameMover extends Thread {
public void run() {
while (true) {
movePieces();
repaint();
try {
sleep(100);
} catch (Exception e) {
}
}
}
}
Change:
rock = null;
to:
astIt.remove();
Assigning null to the variable that has been assigned the value of an element of a List does absolutely nothing to either the List or the element in it; it only affects the value that the variable holds.
As an aside, nice variable name choice of rock - it is appropraite for both types of object - either an abbreviation of "rocket" or a reasonable synonym for an astroid.
Change rock = null; to asteroids.remove(rock); or astIt.remove();
and it should be fine, also no need to set the variable to null as the garbage collector will take care of it for you.
EDIT
Actually asteroids.remove(rock); will throw an exception as said in the comments of this answer, so nevermind it and use the other.
Also I think when in movePieces() you create a new rock and you check if this new rock is outside the screen, I don't think removing the first asteroid in the ArrayList is correct as you will not add the new rock (which may be right if the rock can actually randomly spawn outside the screen) but you will also remove a maybe fine working asteroid from the ArrayList (and thus from the game and the screen).
So, personally I would change that part of code to:
if (Math.random() < 0.3) {
Asteroid newRock = new Asteroid(FrameWidth * Math.random(), 20, 10 * Math.random() - 5, 3 + 3 * Math.random());
if (!(newRock.y >= 500 || newRock.x >= 500)){
asteroids.add(newRock);
}
System.out.println(asteroids.size());
}
But tell me if this works for you.
I'm developing a simple game where all the images are randomized. I've noticed that some of the image are repeated although I have put the random code. I'm still new to Java. I hope that someone can help me solve my problem. Below is my coding.
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Random;
import javax.swing.*;
public class Task1 extends JFrame implements KeyListener,ActionListener {
JFrame frame = new JFrame("FYP");
JTextField textField = new JTextField();
JButton btnNext = new JButton("NEXT");
int sum=0;
int Error=0;int total_test = 0;
static String inputID;
static int index;
String[] imgFileHP = {"1.jpg","3.jpg","4.jpg","7.jpg","9.jpg","10.jpg","12.jpg","16.jpg","17.jpg","18.jpg"};
String[] imgNo = {"5","4","6","3","5","3","4","4","6","6"};
int randomNo;
Random rand = new Random();
public Task1(String inputID)
{
frame.setSize(2200,2500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
Task(inputID);
}
public void Task(String inputID)
{
JPanel panel = new JPanel();
JLabel labelUsername = new JLabel("");
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setBackground(Color.WHITE);
Collections.shuffle(Arrays.asList(imgFileHP));
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[count])));
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
}
textField.setText("");
textField.setColumns(10);
textField.addKeyListener(this);
btnNext.addActionListener(this);
panel.add(labelUsername);
panel.add(textField);
panel.add(btnNext);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent ae)
{
if(!textField.getText().equals("")){
total_test += 1;
if(isNumeric(textField.getText())){
//********************Correct Integer**********************
if(Integer.valueOf(imgNo[randomNo])==Integer.valueOf(textField.getText())){
//********************Correct Answer**********************
System.out.println("Correct");
sum+=1;
}else{
//********************Incorrect Answer**********************
System.out.println("Incorrect");
Error+=1;
}
refreshFrame();
}else{
//********************Incorrect Integer/Alphabet**********************
System.out.println("Invalid");
Error+=1;
refreshFrame();
}
}else{
System.out.println("Null Input");
}
//System.out.println(Integer.valueOf(imgNo[randomNo]));
}
public void refreshFrame(){
if(total_test>=10){
// add result page to see how many score
//Task2(sum, Error);
System.out.println("Correct: "+sum+" Incorrect: "+Error);
frame.dispose();
}else{
btnNext.removeActionListener(this);
frame.getContentPane().removeAll();
getContentPane().removeAll();
Task(inputID);
}
}
public static void main(String args[]) {
Task1 a = new Task1(inputID);
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static boolean isNumeric(String str)
{
try
{
Integer.valueOf(str);
}
catch(NumberFormatException nfe)
{
return false;
}
return true;
}
}
EDIT part (But some of the image is still repeating.)
Collections.shuffle(Arrays.asList(imgFileHP));
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
randomNo = index;
if(uniqueList.contains(index)){
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[index])));
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
Here is how Random works. Even though you have mentioned rand.nextInt(10);but everytime it gets called, there is not pre-defined rule in java that it has to generate unique numbers and not the duplicate the previously generated ones.
For Example:
when you call -
int index = rand.nextInt(10); // Index could be 2
index = rand.nextInt(10); // Now again the value could be 2 as well
So what you need to do is you have to add an extra piece of code to check the uniqueness every time random is called.
Since you want to generate numbers between 0 to 10. Try the following code, it might help you understand.
String[] imgFileHP = {"1.jpg","3.jpg","4.jpg","7.jpg","9.jpg","10.jpg","12.jpg","16.jpg","17.jpg","18.jpg"};
int upper = imgFileHP.length;
int lower = 0;
int r=0;
int index=0;
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
Another easier method is to use Collections.Shuffle as shown below:
Collections.shuffle(Arrays.asList(imgFileHP));
Example of Collection.shuffle().
Lets say you have an array String[] arr = {"abc","def","xyz","bla"}
when you do Collections.shuffle(Arrays.asList(arr));
then print array from index 0 to 3. Array might be shuffled something like this: {"def","bla","abc","xyz"}
**EDIT 2:**Solution based on your edit in main code:
for(int count=0;count<imgFileHP.length;count++){//first add the counters into List
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[index])));
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
The title is not my entire question. I know HOW to organize code, theoretically, but i would like some specific, USEFUL, pointers. Please read on before griping.
I'm a beginner to java and OOP (object oriented programming) and I would really like to learn how to better organize my code! Over the course of a month or two, I made a calculator program with little functions I thought of here and there with a few small jokes built into it. After looking at it a second time I realized that it is extremely poorly formatted and almost incomprehensible.If I may, I would like to ask some more experienced programmers to point me in the right direction on what I should do to fix it (for example, what things can I turn into objects, Where can I compartmentalize, etc).
Please note that this is my FIRST time posting on a forum like this so if i need to clarify something for you to help me, I've done something wrong, I'm asking for too much, please tell me so i can resolve it and i can get help. Please dont just mark this as invalid and file it away to oblivion (as often happens in stackoverflow). Also, before anyone asks, NO this is NOT homework, it is the product of my own crack at teaching myself java (probably why its not working too well).
Here is the source code:
// This is the original Calculator code without objects in a single class. not really efficient...
package randomClasses;
import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;
import javax.swing.*;
#SuppressWarnings("serial")
public class CalcClass
extends JFrame
implements ActionListener {
JPanel[] row = new JPanel[6];
JButton[] button = new JButton[21];
String[] buttonString = {"7", "8", "9", "+", "4", "5", "6", "-", "1", "2", "3", "*", ".", "/", "C", "v", "+/-", "=", "0", "Parabola", "x^y"};
int[] dimW = {300, 45, 100, 90, 180};
int[] dimH = {35, 40};
Dimension displayDimension = new Dimension(dimW[0], dimH[0]);
Dimension regularDimension = new Dimension(dimW[1], dimH[1]);
Dimension rColumnDimension = new Dimension(dimW[2], dimH[1]);
Dimension zeroButDimension = new Dimension(dimW[3], dimH[1]);
Dimension parabolaDimension = new Dimension(dimW[4], dimH[0]);
//formatting variables
int var = 0;
double x = 0;
String stor = "";
boolean initial = true;
//variables for Parabola function
int countEquals_parab = 0;
double Angle = 0;
double Vi = 0;
double Vx = 0;
double Vy = 0;
double T_max = 0;
double Y_displ = 0;
double X_displ = 0;
double h = 0;
double k = 0;
double a_parab = 0;
boolean parabComplete = true;
boolean parabola = false;
DecimalFormat df = new DecimalFormat("#######.#####");
//variables for addressing illegal typing issues
boolean typeNum = true;
boolean typeDot = true;
JFrame frame; //for parabolaInstructions
//original calculator variables
boolean[] function = new boolean[5];
double[] temporary = {0, 0}; //store on screen values
double result = 0; //store result
public JTextArea display = new JTextArea(1, 20);
Font font = new Font("Times new Roman", Font.BOLD, 14);
CalcClass() {
super("CalcClass");
setDesign();
setSize(380, 300);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
GridLayout grid = new GridLayout(6, 5);
setLayout(grid);
for(int i = 0; i < 5; i++) {
function[i] = false;
}
FlowLayout f1 = new FlowLayout(FlowLayout.CENTER);
FlowLayout f2 = new FlowLayout(FlowLayout.CENTER, 1, 1);
for(int i = 0; i < 6; i++) {
row[i] = new JPanel();
}
row[0].setLayout(f1);
for(int i = 1; i < 6; i++) {
row[i].setLayout(f2);
}
for(int i = 0; i < 21; i++) {
button[i] = new JButton();
button[i].setText(buttonString[i]);
button[i].setFont(font);
button[i].addActionListener(this);
}
display.setFont(font);
display.setEditable(false);
display.setPreferredSize(displayDimension);
for(int i = 0; i < 14; i++) {
button[i].setPreferredSize(regularDimension);
}
for(int i = 14; i < 18; i++) {
button[i].setPreferredSize(rColumnDimension);
}
button[18].setPreferredSize(zeroButDimension);
button[19].setPreferredSize(parabolaDimension);
button[20].setPreferredSize(rColumnDimension);
row[0].add(display);
add(row[0]);
for(int i = 0; i < 4; i++) {
row[1].add(button[i]);
}
row[1].add(button[14]);
add(row[1]);
for(int i = 4; i < 8; i++) {
row[2].add(button[i]);
}
row[2].add(button[15]);
add(row[2]);
for(int i = 8; i < 12; i++) {
row[3].add(button[i]);
}
row[3].add(button[16]);
add(row[3]);
row[4].add(button[18]);
for(int i = 12; i < 14; i++) {
row[4].add(button[i]);
}
row[4].add(button[17]);
add(row[4]);
row[5].add(button[19]);
row[5].add(button[20]);
add(row[5]);
setVisible(true);
}
public void getSqrt() {
stor = "";
initial = true;
try {
double value = Double.parseDouble(display.getText());
if(value == -100) {
format("John's Girlfriend");
} else {
value = Math.sqrt(Double.parseDouble(display.getText())); //create a value for variable, and use Maths square root to find the value
format(Double.toString(value)); //Sets display to new value
}
} catch(NumberFormatException e) {
}
typeDot = false;
typeNum = false;
}
public void getPosNeg() {
stor = "";
initial = true;
try {
double value = Double.parseDouble(display.getText()); //again creating a variable for current value
if(value != 0) { //if value is not equal to zero
value = (-1) * value; //multiplied by -1 to change the sign
format(Double.toString(value)); //Sets display to new value
} else {
}
} catch(NumberFormatException e) {
}
}
public void getResult() {
temporary[1] = Double.parseDouble(display.getText());
String temp0 = Double.toString(temporary[0]);
String temp1 = Double.toString(temporary[1]);
try {
if(temp0.contains("-")) {
String[] temp00 = temp0.split("-", 2);
temporary[0] = (Double.parseDouble(temp00[1]) * -1);
}
if(temp1.contains("-")) {
String[] temp11 = temp1.split("-", 2);
temporary[1] = (Double.parseDouble(temp11[1]) * -1);
}
} catch(ArrayIndexOutOfBoundsException e) {
}
try {
functions();
clear();
format(Double.toString(result));//display has a result
for(int i = 0; i < 5; i++) {
function[i] = false; //set all functions to false
}
} catch(NumberFormatException e) {
}
typeNum = false;
}
public void functions() {
if(function[2] == true) { //multiplication
result = temporary[0] * temporary[1];
} else if(function[3] == true) { //division
result = temporary[0] / temporary[1];
} else if(function[0] == true) { //addition
result = temporary[0] + temporary[1];
} else if(function[1] == true) { //subtraction;
result = temporary[0] - temporary[1];
} else if(function[4] == true) {
result = Math.pow(temporary[0], temporary[1]);
} else {
result = temporary[1];
}
}
double a_quadratic = 0;
double b = 0;
double c = 0;
double x1 = 0;
double x2 = 0;
double discr = 0;
int countEquals_quadratic = 0;
public void quadraticFormula() {
if(countEquals_parab == 0) {
a_quadratic = Double.parseDouble(display.getText());
clear();
display.setText("b = ");
}
if(countEquals_parab == 1) {
b = Double.parseDouble(display.getText());
display.setText("c = ");
}
if(countEquals_parab == 2) {
c = Double.parseDouble(display.getText());
discr = (Math.pow(b, 2) - 4 * a_quadratic * c); //stores the value of the discriminant
if(discr >= 0) {
x1 = (-b + Math.sqrt(b * b - 4 * a_quadratic * c)) / (2 * a_quadratic);
x2 = (-b - Math.sqrt(b * b - 4 * a_quadratic * c)) / (2 * a_quadratic);
}
}
}
public void parabolaButton() {
double G = 9.81;
if(countEquals_parab == 0) {
Vi = Double.parseDouble(display.getText());
clear();
display.setText("Angle of release: ");
}
if(countEquals_parab == 1) {
Angle = Double.parseDouble(display.getText());
if((Angle > 90.0) || (Angle < 0.0)) {
display.setText("Sorry, not a valid angle");
countEquals_parab = 3;
} else {
Angle = (Math.PI / 180.0) * Angle; //converting degrees into radians
Vx = Vi * Math.cos(Angle); //Calculating x component
Vy = Vi * Math.sin(Angle); //Calculating y component
//Finding time
T_max = Vy / G; //time to max height
//Calculating vertex coordinates
Y_displ = (Vy * Vy / (2 * G));
X_displ = Vx * T_max;
//finding a
a_parab = (-Y_displ) / (X_displ * X_displ);
display.setText("The equation of the parabola is \ny = " + df.format(a_parab) + "(x - " + df
.format(h) + ")^2 + " + df.format(k));
}
}
if(countEquals_parab == 2) {
display.setText("Time to get to max height = " + df.format(T_max));
}
if(countEquals_parab == 3) {
clearFunction();
countEquals_parab = -1;
parabola = false;
parabComplete = true;
}
countEquals_parab++;
}
public void var() {
var++;
if(var > 8) {
var = 1;
}
if(var == 1) {
format("x");
}
}
public final void setDesign() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch(Exception e) {
}
}
public void format(String get) {
//get stores the incoming values temporarily
//get is transferred to a new value for permanent storage
//print the permanent storage value
//new number is added, stored temporarily in get
//get is added to permanent storage
//print permanent storage value
double spaceFix = 0;
if(initial == true) {
stor = get;
initial = false;
} else if(initial == false) {
stor = stor + get;
}
spaceFix = stor.length() / 4;
int numberOfSpaces = 56 - stor.length() + (int) spaceFix;
String format = String.format("%" + numberOfSpaces + "s", stor);
display.setText(format);
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == button[0]) {
numberButtons("7");
}
if(ae.getSource() == button[1]) {
numberButtons("8");
}
if(ae.getSource() == button[2]) {
numberButtons("9");
}
if(ae.getSource() == button[3]) {
operatorButtons(0); //add function[0]
}
if(ae.getSource() == button[4]) {
numberButtons("4");
}
if(ae.getSource() == button[5]) {
numberButtons("5");
}
if(ae.getSource() == button[6]) {
numberButtons("6");
}
if(ae.getSource() == button[7]) {
operatorButtons(1); //subtract function[1]
}
if(ae.getSource() == button[8]) {
numberButtons("1");
}
if(ae.getSource() == button[9]) {
numberButtons("2");
}
if(ae.getSource() == button[10]) {
numberButtons("3");
}
if(ae.getSource() == button[11]) {
operatorButtons(2); //multiplication function[2]
}
if(ae.getSource() == button[12]) {
if(typeDot == false) {
} else {
numberButtons(".");
typeDot = false;
}
}
if(ae.getSource() == button[13]) {
operatorButtons(3); //divide function[3]
}
if(ae.getSource() == button[14]) {
clearFunction();
parabola = false;
parabComplete = true;
}
if(ae.getSource() == button[15]) {
getSqrt();
}
if(ae.getSource() == button[16]) {
getPosNeg();
}
if((ae.getSource() == button[17]) && display.getText().equals("")) {
} else if((ae.getSource() == button[17]) && (parabola == false)) {
getResult();
} else if((ae.getSource() == button[17]) && (parabola == true)) {
parabolaButton();
}
if(ae.getSource() == button[18]) {
numberButtons("0");
}
if(ae.getSource() == button[19]) {
clearFunction();
parabolaInstructions();
parabola = true;
parabComplete = false;
display.setText("Initial velocity: ");
}
if(ae.getSource() == button[20]) {
operatorButtons(4);//powerFunction();
}
}
public void parabolaInstructions() {
//Create the dialog.
final JDialog dialog = new JDialog(frame, "How to use the Parabola function");
//Add contents to it. It must have a close button,
//since some L&Fs (notably Java/Metal) don't provide one
//in the window decorations for dialogs.
JLabel label = new JLabel("<html><p align=center>" + "Step 1: Type in the initial velocity and press the \"=\" button<br>" + "Step 2: Type in the angle of Release (make sure that it is between 0 and 90)<br>" + "Step 3: Press the \"=\" button to scroll through the results<br>" + "Step 4: Profit");
label.setHorizontalAlignment(JLabel.CENTER);
Font font = label.getFont();
label.setFont(label.getFont().deriveFont(font.PLAIN, 14.0f));
JButton closeButton = new JButton("Ok");
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
dialog.dispose();
}
});
JPanel closePanel = new JPanel();
closePanel.setLayout(new BoxLayout(closePanel, BoxLayout.LINE_AXIS));
closePanel.add(Box.createHorizontalGlue());
closePanel.add(closeButton);
closePanel.setBorder(BorderFactory.
createEmptyBorder(0, 0, 5, 5));
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(label, BorderLayout.CENTER);
contentPane.add(closePanel, BorderLayout.PAGE_END);
contentPane.setOpaque(true);
dialog.setContentPane(contentPane);
//Show it.
dialog.setSize(new Dimension(400, 200));
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public void numberButtons(String i) {
if(typeNum == false) {
display.setText("");
format(i);
} else {
format(i);
}
typeNum = true;
}
public void operatorButtons(int funct) {
if(display.getText().equals("")) {
} else {
temporary[0] = Double.parseDouble(display.getText());
function[funct] = true;
clear();
}
}
public void clearFunction() {
clear();
try {
for(int i = 0; i < 5; i++) {
function[i] = false;
}
for(int i = 0; i < 2; i++) {
temporary[i] = 0;
}
} catch(NullPointerException e) {
}
//For parabola()
Vi = 0;
Vx = 0;
Vy = 0;
T_max = 0;
Y_displ = 0;
X_displ = 0;
h = 0;
k = 0;
a_parab = 0;
}
public void clear() {
display.setText("");
stor = "";
typeDot = true;
initial = true;
}
public static void main(String[] arguments) {
CalcClass c = new CalcClass();
}
}
Ok so now you've seen my mess... I sort-of know what I should do and YES I did some research but I feel it would be much easier to learn organization through example or a nice push than it would be from reading articles that tell you ultra-hypothetical or loosely-analogous examples of what objects are. Note: I tried using methods to organize and my class looks much better than what it did (I also made the whole thing an object to be called upon at the bottom which is pretty much useless).
If you use eclipse, try:
Window > Prefferences > Java > Editor > Save Actions
Check "perform the selected actions on save", "Additional Actions" and click "Configure".
Using eclipse's Save Actions can be really useful in real life coding, but you will probably learn some neat java tricks going through the Save Actions wizard.
Java is an Object Oriented language. You need to take advantage of that fact.
Use classes to separate your code into different logical / structural components. Learn how to use OOP. Follow SOLID design and use design patterns.
Another important thing is to know your language. Start by reading basic classes javadocs and relevant sections of the java spec. I would begin with deeply understanding the different types of java (class, interface, enum and inner / nested / anonymous types) and the different modifiers (private, public, protected, static, abstract, final, default).
Some other eclipse's short cuts:
CTRL-A, CTRL-I ("indentation") will fix your code indentation.
CTRL-SHIFT-O ("organize imports") will omit redundant imports.
You might consider taking a look at Code Complete, which deals with the issues that you're concerned with here, and otherwise is just a classic in our field that every serious developer should read.
In general, when you're organizing code you should do so with a few things in mind: readability and atomicity. These two factors apply to code on every level of an application, from variable naming, routines, methods, classes, packages, and so on.
Readability is a simple idea: can a human being read this code and understand it? To gauge the readability of the code all you have to do is read it! Do variable names help the reader understand what something is? Are routines and classes properly formatted and not needlessly complex? Have you removed all code that isn't being used? Is your code written in a logical progression?
Atomicity is the idea that everything should have one purpose. A function or method should (usually) do one thing and one thing only. A class should usually be a logical grouping of related methods and fields serving some type of unique purpose, and NOT a mish-mash of unrelated stuff. A package should also contain a set of related files. Same with a project, and so on.
The main benefit of atomicity is that once you get into more involved applications it's actually much easier to debug and isolate issues in your code because you know where stuff is. For instance: I have a database access error! Good thing I have a package that's specifically defined for my database access objects.
I know when I was just getting started in the field this was something that threw me off too. It might not be until you do a lot of coding within more significant apps that you really start to understand best practices and why people build stuff a certain way.
Thanks to everyone who contributed to my problem, I completely scrapped this garbage and made it 1000 times better. I knew from the beginning it was poorly made and I wanted to fix it, I just didn't know where to start. After reading all the advice that was given, watching a few tutorials and brushing up on some simple java concepts (modifiers, jswing, etc), I ended up making a new one that is in MVC format (Yay, order and efficiency). Now all my new variables are actually meaningful (Thanks #maaartinus for helping me realize that many of my variables were poorly named and made my whole program unnecessarily complicated). Also, I tried to work on SRP (Not 100% sure if I completely did it but with the program organized it will be easy to change things) and I plan on adding units later for good practice (Thank you, #Robert Snyder). This new GUI is ugly but that can always be changed later and since It is now in MVC format the job will be easier.
Here is what I did (not finished and far from perfect but a step in the right direction):
CalcGui.java
package com.Calculator;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class CalcGui extends JFrame {
private static final long serialVersionUID = 1L;
private String[] operatorsList = { "+", "-", "*", "/", "^" };
// Row 1
private JTextField firstNumber = new JTextField(10);
private JComboBox<String> operator = new JComboBox<>(operatorsList);
private JTextField secondNumber = new JTextField(10);
private JButton calculateButton = new JButton("Calculate");
private JTextField calcSolution = new JTextField(20);
// Row 2
private JLabel sqrtSymbol = new JLabel("√");
private JTextField sqrtNumber = new JTextField(10);
private JButton sqrtCalcButton = new JButton("Calculate");
private JTextField sqrtCalcSolution = new JTextField(20);
// Row 3
private JLabel quadraticLabel1 = new JLabel("A = ");
private JTextField quadraticFirstNumber = new JTextField(5);
private JLabel quadraticLabel2 = new JLabel("B = ");
private JTextField quadraticSecondNumber = new JTextField(5);
private JLabel quadraticLabel3 = new JLabel("C = ");
private JTextField quadraticThirdNumber = new JTextField(5);
private JButton quadraticCalcButton = new JButton("Calculate");
private JLabel quadraticTextBefore = new JLabel("x =");
private JTextField firstQuadraticCalcSolution = new JTextField(3);
private JLabel quadraticTextMiddle = new JLabel("and x =");
private JTextField secondQuadraticCalcSolution = new JTextField(3);
CalcGui() {
JPanel calcPanel = new JPanel(new BorderLayout());
FlowLayout Default = new FlowLayout(FlowLayout.LEFT);
JPanel row1 = new JPanel(Default);
JPanel row2 = new JPanel(Default);
JPanel row3 = new JPanel(Default);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(650, 150);
row1.add(firstNumber);
row1.add(operator);
row1.add(secondNumber);
row1.add(calculateButton);
row1.add(calcSolution);
row2.add(sqrtSymbol);
row2.add(sqrtNumber);
row2.add(sqrtCalcButton);
row2.add(sqrtCalcSolution);
row3.add(quadraticLabel1);
row3.add(quadraticFirstNumber);
row3.add(quadraticLabel2);
row3.add(quadraticSecondNumber);
row3.add(quadraticLabel3);
row3.add(quadraticThirdNumber);
row3.add(quadraticCalcButton);
row3.add(quadraticTextBefore);
row3.add(firstQuadraticCalcSolution);
row3.add(quadraticTextMiddle);
row3.add(secondQuadraticCalcSolution);
calcPanel.add(row1, BorderLayout.NORTH);
calcPanel.add(row2, BorderLayout.CENTER);
calcPanel.add(row3, BorderLayout.SOUTH);
this.add(calcPanel);
}
// basic calculations methods
public double getFirstNumber() {
return Double.parseDouble(firstNumber.getText());
}
public String getOperator() {
return (String) operator.getSelectedItem();
}
public double getSecondNumber() {
return Double.parseDouble(secondNumber.getText());
}
public void setCalcSolution(double solution) {
calcSolution.setText(Double.toString(solution));
}
void addCalculateListener(ActionListener listenForCalcButton) {
calculateButton.addActionListener(listenForCalcButton);
}
void displayErrorMessage(String errorMessage) {
JOptionPane.showMessageDialog(this, errorMessage);
}
// Square root function methods
public double getSqrtNumber() {
return Double.parseDouble(sqrtNumber.getText());
}
public void setSqrtCalcSolution(double solution) {
sqrtCalcSolution.setText(Double.toString(solution));
}
void addSqrtCalcListener(ActionListener listenForSqrtCalcButton) {
sqrtCalcButton.addActionListener(listenForSqrtCalcButton);
}
// Quadratic formula Methods
public double getQuadraticFirstNumber() {
return Double.parseDouble(quadraticFirstNumber.getText());
}
public double getQuadraticSecondNumber() {
return Double.parseDouble(quadraticSecondNumber.getText());
}
public double getQuadraticThirdNumber() {
return Double.parseDouble(quadraticThirdNumber.getText());
}
public void setFirstQuadraticCalcSolution(double solution) {
firstQuadraticCalcSolution.setText(Double.toString(solution));
}
public void setSecondQuadraticCalcSolution(double solution) {
secondQuadraticCalcSolution.setText(Double.toString(solution));
}
void addQuadraticCalcListener(ActionListener listenForQuadraticCalcButton) {
quadraticCalcButton.addActionListener(listenForQuadraticCalcButton);
}
}
CalcModel.java
package com.Calculator;
public class CalcModel {
private double calcValue;
public void calculate(double firstNumber, double secondNumber,
String operator) {
if (operator.equals("+")) {
calcValue = firstNumber + secondNumber;
}
if (operator.equals("-")) {
calcValue = firstNumber - secondNumber;
}
if (operator.equals("*")) {
calcValue = firstNumber * secondNumber;
}
if (operator.equals("/")) {
calcValue = firstNumber / secondNumber;
}
if (operator.equals("^")) {
calcValue = Math.pow(firstNumber, secondNumber);
}
}
public double getCalcValue() {
return calcValue;
}
}
SqrtCalcModel.java
package com.Calculator;
public class SqrtCalcModel {
private double sqrtCalcValue;
public void sqrt(double number) {
sqrtCalcValue = Math.sqrt(number);
}
public double getSqrtCalcValue() {
return sqrtCalcValue;
}
}
QuadraticCalcModel.java
package com.Calculator;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class QuadraticCalcModel {
private double firstQuadraticCalcValue;
private double secondQuadraticCalcValue;
public void quadraticFormula(double a, double b, double c) {
double discriminant = (b * b) - (4 * a * c);
if (discriminant >= 0) {
firstQuadraticCalcValue = (Math.sqrt((b * b) - (4 * a * c)) + (-b))
/ (2 * a);
secondQuadraticCalcValue = (Math.sqrt((b * b) - (4 * a * c)) - (-b))
/ (2 * a);
}
else {
JFrame parent = new JFrame();
JOptionPane.showMessageDialog(parent,
"This function has no real roots.");
}
}
public double getFirstQuadraticValue() {
return firstQuadraticCalcValue;
}
public double getSecondQuadraticValue() {
return secondQuadraticCalcValue;
}
}
CalculatorControler.java
package com.Calculator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CalculatorController {
private CalcGui theGui;
private CalcModel theCalcModel;
private SqrtCalcModel theSqrtCalcModel;
private QuadraticCalcModel theQuadraticCalcModel;
public CalculatorController(CalcGui theGui, CalcModel theCalcModel,
SqrtCalcModel theSqrtCalcModel,
QuadraticCalcModel theQuadraticCalcModel) {
this.theGui = theGui;
this.theCalcModel = theCalcModel;
this.theSqrtCalcModel = theSqrtCalcModel;
this.theQuadraticCalcModel = theQuadraticCalcModel;
this.theGui.addCalculateListener(new CalcListener());
this.theGui.addSqrtCalcListener(new SqrtCalcListener());
this.theGui.addQuadraticCalcListener(new QuadraticCalcListener());
}
class CalcListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
double firstNumber, secondNumber = 0;
String operator;
try {
firstNumber = theGui.getFirstNumber();
operator = theGui.getOperator();
secondNumber = theGui.getSecondNumber();
theCalcModel.calculate(firstNumber, secondNumber, operator);
theGui.setCalcSolution(theCalcModel.getCalcValue());
}
catch (NumberFormatException ex) {
System.out.println(ex);
theGui.displayErrorMessage("You Need to Enter 2 Numbers");
}
}
}
class SqrtCalcListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
double number = 0;
try {
number = theGui.getSqrtNumber();
theSqrtCalcModel.sqrt(number);
theGui.setSqrtCalcSolution(theSqrtCalcModel.getSqrtCalcValue());
}
catch (NumberFormatException ex) {
System.out.println(ex);
theGui.displayErrorMessage("You Need to enter a Number");
}
}
}
class QuadraticCalcListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
double a, b, c = 0;
try {
a = theGui.getQuadraticFirstNumber();
b = theGui.getQuadraticSecondNumber();
c = theGui.getQuadraticThirdNumber();
theQuadraticCalcModel.quadraticFormula(a, b, c);
theGui.setFirstQuadraticCalcSolution(theQuadraticCalcModel
.getFirstQuadraticValue());
theGui.setSecondQuadraticCalcSolution(theQuadraticCalcModel
.getSecondQuadraticValue());
}
catch (NumberFormatException ex) {
System.out.println(ex);
theGui.displayErrorMessage("You need to enter 3 numbers.");
}
}
}
}
MVCCalculator.java
package com.Calculator;
public class MVCCalculator {
public static void main(String[] args) {
CalcGui theGui = new CalcGui();
CalcModel theCalcModel = new CalcModel();
SqrtCalcModel theSqrtCalcModel = new SqrtCalcModel();
QuadraticCalcModel theQuadraticCalcModel = new QuadraticCalcModel();
new CalculatorController(theGui, theCalcModel, theSqrtCalcModel,
theQuadraticCalcModel);
theGui.setVisible(true);
}
}
Game class:
import java.util.Random;
public class Game {
public static void main(String args[]){
//----------Sets up GUI----------
GUI gameGUI = new GUI();
gameGUI.setVisible(true);
Player.setGUI(gameGUI);
//----------Sets initial number of marbles, computer player and human player----------
Random random = new Random();
int initialNum;
//loop makes sure initialNum of marbles is between 10 and 100
do{
initialNum = random.nextInt(100);
}while(initialNum < 10);
//*****gameGUI.manageMarbles(initialNum, true);
//end loop
Pile pile = new Pile(initialNum);
gameGUI.setPile(pile);
int compChoice = random.nextInt(2) + 1; //number index (1 or 2) representing SIMPLE_COMPUTER or SMART_COMPUTER
Player computer = new Player(Player.Type.values()[compChoice]);
Player humanPlayer = new Player(Player.Type.HUMAN);
//----------Game loop----------
//Randomly determine first player
Player currentPlayer;
int playerIndex = random.nextInt(2); //will be used to determine next player in the loop
if(playerIndex == 0){ currentPlayer = computer; }
else { currentPlayer = humanPlayer; }
//Loop
while(pile.getNumMarbles() != 0){
System.out.printf("%d marbles left.\n", pile.getNumMarbles());
int removed = currentPlayer.playTurn(pile.getNumMarbles());
pile.removeMarbles(removed);
//Determine next player
playerIndex = Math.abs(playerIndex - 1); //if playerIndex = 0, it becomes 1, and vice-versa
if(playerIndex == 0){ currentPlayer = computer; }
else { currentPlayer = humanPlayer; }
}
System.out.println(currentPlayer + " won");
}
}
Player class:
import java.util.Scanner;
import java.util.Random;
public class Player {
public enum Type{HUMAN, SIMPLE_COMPUTER, SMART_COMPUTER}
private Type type;
static private GUI gui;
public Player(Player.Type type){
this.type = type;
}
public Player.Type getType(){
return type;
}
public int playTurn(int pileSize){
Random random = new Random();
if(type == Type.HUMAN){
int marbles;
do{
marbles = gui.getMarblesToRemove();
}while(marbles < 0);
return marbles;
}
else if(type == Type.SIMPLE_COMPUTER){
if(pileSize == 1){
return 1;
}
else{
int remove = random.nextInt(pileSize/2) + 1;
if(remove == (pileSize/2) + 1){ remove -= 1; }
return remove;
}
}
else if(type == Type.SMART_COMPUTER){
if(pileSize == 1){
return 1;
}
else if(pileSize == 3 || pileSize == 7 || pileSize == 15 || pileSize== 31 || pileSize== 63 || pileSize <= 3){
int remove = random.nextInt(pileSize/2) + 1;
if(remove == (pileSize/2) + 1){ remove -= 1; }
return remove;
}
else{
for(int i=1; i<=pileSize/2; i++){
int size = pileSize - i;
if(size == 3 || size == 7 || size == 15 || size == 31 || size == 63){
return i;
}
}
}
}
return 0;
}
public String toString(){
return ""+type;
}
public static void setGUI(GUI guii){
gui = guii;
}
}
GUI class:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class GUI extends JFrame {
private JPanel panel;
private JButton removeButton; //button to remove marbles
private JTextField marblesAmount; //amount of marbles to remove
private static final int FIELD_WIDTH = 2;
private JLabel marblesLabel;
private JLabel errorLabel;
private Pile pile;
private int marblesToRemove;
private ClickListener listener;
static final private int WIDTH = 700, HEIGHT = 600;
public GUI(){
super.setTitle("test");
super.setSize(WIDTH, HEIGHT);
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
marblesLabel = new JLabel("How many marbles to remove?");
errorLabel = new JLabel("");
removeButton = new JButton("Remove");
listener = new ClickListener();
removeButton.addActionListener(listener);
marblesAmount = new JTextField(FIELD_WIDTH);
panel.add(removeButton);
panel.add(marblesLabel);
panel.add(marblesAmount);
panel.add(errorLabel);
super.add(panel);
marblesToRemove = 0;
}
public void setPile(Pile pile){
this.pile = pile;
}
private class ClickListener implements ActionListener{
public void actionPerformed(ActionEvent event){
marblesToRemove = Integer.parseInt(marblesAmount.getText());
}
}
public int getMarblesToRemove(){
return marblesToRemove;
}
}
Pile Class:
public class Pile {
private int initialNum;
private int currentNum;
public Pile(int initialNum){
setNumMarbles(initialNum);
currentNum = initialNum;
}
public int getNumMarbles(){
return currentNum;
}
public void removeMarbles(int numToRemove){
currentNum = currentNum - numToRemove;
}
public void setNumMarbles(int amount){
initialNum = amount;
}
public String toString(){
return "Number of marbles: " + currentNum;
}
}
What I am trying to do is to get the function playTurn(int pileSize) in the Player class to return the variable marbles(inside the if(type == Type.HUMAN) block ) only when it is not zero. The variable marblesToRemove from the gui class is assigned to marbles, by calling the function getMarblesToRemove().
marblesToRemove is initially set to 0 in the default constructor for the gui class, and that causes the functionplayTurn(int pileSize) to go in an infinite loop. But marblesToRemove is changed to another value that is input in a JTextField (marblesAmount) when a a button(removeButton) is pressed. But the the do while loop will still be an infinite loop and the function will return nothing, why? Can someone please help? Thanks.
This is probably because of at least two issues that I can see. The first is that you are modifying the variable in one thread, and reading it in the other. This should be done using either synchronization, or some other locking mechanism (Lock or AtomicInteger, etc.).
The second issue is that your reading-thread should not be doing a 'tight' loop. This is bad practices that sends one CPU to 100% usage. It should be done using some form of notification. Again, synchronization comes to mind.
Until you fix these two issues, you will always have unreliable results.
For what it's worth, in your particular case, if I were to make an educated guess, I would guess that there are two important copies of the marblesAmount (and there are alsways multiple copies). There's the copy thati's in the L1 and registers of one CPU that's doing a tight loop waiting for that register to change, and the other is in another core on your CPU setting it to a new value. Unless you use some synchronization, or somethin from the java.util.concurrent.* library you ave no way to tell one copy of the variable to refresh the other.
I got it to work finally. I just added a line of code "System.out.print("");" in the do-while loop in the Player class.
So now it looks like
do{
marbles = gui.getMarblesToRemove();
System.out.print("");
}while(marbles < 0);
I have no idea why that works, but it does lol. Now the function actually returns the value that I set in the JTextField if it is not zero.