I am experiencing a weird behavior with Java objects. I have this ComponentPlane.class with two different versions. Difference is marked by ******.
First WORKING Version
package app.pathsom.som.output;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import app.pathsom.som.map.Lattice;
import app.pathsom.som.map.Node;
public class ComponentPlane extends JPanel{
private Lattice lattice;
private int componentNumber;
private double minValue;
private double maxValue;
private double origMinValue;
private double origMaxValue;
public ComponentPlane(Lattice lattice, int componentNumber){
this.lattice = new Lattice();
this.componentNumber = componentNumber;
initLattice(lattice);
initComponentPlane();
}
private void initLattice(Lattice lattice){
this.lattice.setLatticeHeight(lattice.getLatticeHeight());
this.lattice.setLatticeWidth(lattice.getLatticeWidth());
this.lattice.setNumberOfNodeElements(lattice.getNumberOfNodeElements());
this.lattice.initializeValues();
this.lattice.setNodeHeight(lattice.getNodeHeight());
this.lattice.setNodeWidth(lattice.getNodeWidth());
this.lattice.setTotalNumberOfNodes(lattice.getTotalNumberOfNodes());
for(int i = 0; i < lattice.getTotalNumberOfNodes(); i++){
******this.lattice.getLatticeNode()[i] = new Node(lattice.getLatticeNode()[i]);******
}
}
}
The only difference of the second NON-WORKING version is with this FUNCTION REPLACING the FUNCTION above
private void initLattice(Lattice lattice){
//same code here
for(int i = 0; i < lattice.getTotalNumberOfNodes(); i++){
******this.lattice.getLatticeNode()[i] = lattice.getLatticeNode()[i];******
}
}
I have also tried doing a third non-working version which is...
private void initLattice(Lattice lattice){
//same code here
******this.lattice.setLatticeNode(lattice.getLatticeNode());******
}
A constructor in the Node.class (WHICH is USED in the first WORKING version is this one...
public Node (Node node){
this.xPos = node.xPos;
this.yPos = node.yPos;
this.numOfElements = node.numOfElements;
this.cluster = -1;
this.nodeIndex = node.getNodeIndex();
for(int i = 0; i < this.numOfElements; i++){
this.addElement(node.getDoubleElementAt(i));
}
}
Lattice.class
public class Lattice {
private int latticeWidth;
private int latticeHeight;
private int numOfNodeElements;
private int nodeWidth;
private int nodeHeight;
private int totalNumOfNodes;
private Node[] latticeNodes;
private final int MAP_RADIUS = 225;
public Lattice(int latticeWidth, int latticeHeight, int numOfNodeElements){
this.latticeWidth = latticeWidth;
this.latticeHeight = latticeHeight;
this.numOfNodeElements = numOfNodeElements;
initializeLattice();
}
public Lattice(){
this(10, 10, 3);
}
public void initializeValues(){
totalNumOfNodes = this.latticeHeight * this.latticeWidth;
latticeNodes = new Node[totalNumOfNodes]; //specify the array of nodes
nodeWidth = (int) Math.floor(450/this.latticeWidth);
nodeHeight = (int) Math.floor(450/this.latticeHeight);
}
protected void initializeLattice(){
totalNumOfNodes = this.latticeHeight * this.latticeWidth;
latticeNodes = new Node[totalNumOfNodes];
nodeWidth = (int) Math.floor(450/this.latticeWidth);
nodeHeight = (int) Math.floor(450/this.latticeHeight);
//initialize colors
for(int i = 0; i <totalNumOfNodes; i++){
latticeNodes[i] = new Node(((i % this.latticeWidth) * nodeWidth) + nodeWidth / 2,
((i / this.latticeWidth) * nodeHeight ) + nodeHeight/2, numOfNodeElements, i);
latticeNodes[i].setNodeColor(new Color((int)(latticeNodes[i].getDoubleElementAt(0)
* 255), (int)(latticeNodes[i].getDoubleElementAt(1) * 255), (int) (latticeNodes[i].getDoubleElementAt(2) * 255)));
}
}
public int getLatticeHeight(){
return latticeHeight;
}
public void setLatticeHeight(int latticeHeight){
this.latticeHeight = latticeHeight;
}
public Node[] getLatticeNode(){
return latticeNodes;
}
public void setLatticeNode(Node[] latticeNodes){
this.latticeNodes = latticeNodes;
}
public int getLatticeWidth(){
return latticeWidth;
}
public void setLatticeWidth(int latticeWidth){
this.latticeWidth = latticeWidth;
}
public int getNodeHeight(){
return nodeHeight;
}
public int getNodeWidth(){
return nodeWidth;
}
public void setNodeHeight(int nodeHeight){
this.nodeHeight = nodeHeight;
}
public void setNodeWidth(int nodeWidth){
this.nodeWidth = nodeWidth;
}
public int getNumberOfNodeElements(){
return numOfNodeElements;
}
public void setNumberOfNodeElements(int numOfNodeElements){
this.numOfNodeElements = numOfNodeElements;
}
public int getTotalNumberOfNodes(){
return totalNumOfNodes;
}
public void setTotalNumberOfNodes(int totalNumberOfNodes){
this.totalNumOfNodes = totalNumberOfNodes;
}
}
A certain Visualization.class initiates all these actions and stores the ComponentPlane arrays. Here is the function
public void initComponentPlanes(){
componentPlanes = new ComponentPlane[somtrainer.getLattice().getNumberOfNodeElements()];
int size = somtrainer.getLattice().getNumberOfNodeElements();
for(int i = 0; i < size; i++){
System.out.println(i + ": " + inputData.getVariableLabels()[i] + " size : " + size);
componentPlanes[i] = new ComponentPlane(somtrainer.getLattice(), i);
componentPlanes[i].setBounds((240 - 225)/2, (280-240)/2, 225, 240);
componentPlanes[i].setOrigMaxMin(maxMin[i][0], maxMin[i][1]);
}
}
My problems are
The First one works fine. It creates HEATMAPS or COMPONENTPLANES for each component number (meaning they differ from each other) but I cannot use it as the line with ****** which references to the ("this.addElement....") in the Node.class constructor gives me OUTOFMEMORY error so it LAGS and FREEZES whenever I have many COMPONENTPLANES to do. (I am actually doing an ARRAY of COMPONENTPlane objects) so I decided to try the second and third option. I have already increased my heap size SO this is OUT of the question
If I use the second and third one, I end up with no LAGS even with large amount of ComponentPlanes (probably less memory taking up because of creating new Node objects or idk) but these creates wrong heatmaps. All heatmaps are the same. And the thing is, all heatmaps are like the last element of the ComponentPlanes array (e.g. if I have ten ComponentPlane objects, all heatmaps look exactly like the tenth Component Object)
All of the heatmaps are like this - the same as the last heatmap in the array:
Is there a way to make the second and third one work?
The obvious difference is that in the first one you're creating new nodes, and in the others you're reusing the old ones. The line
this.lattice.getLatticeNode()[i] = lattice.getLatticeNode()[i];
is setting one object equal to another. If, later, a property of lattice.getLatticeNode()[i] changes, that will also effect this.lattice.getLatticeNode()[i]. And that can cause hard-to-find bugs. In contrast, the line
this.lattice.getLatticeNode()[i] = new Node(lattice.getLatticeNode()[i]);
is creating a new object, distinct from the old one. But, of course, this means that you're using more memory, because now you have two objects instead of one.
There are little things you can do to reduce the amount of memory used. private final int MAP_RADIUS = 225; could be made static, so a new copy of the constant isn't created for each node.
Related
I have been trying to write JUnit tests to test a program but something seems to be wrong and I can't figure out what. The program works as intended, but the unittests behaves strangely when run together.
I want to create a new instance of the ParkingLotManager object for every test, and have tried to instansiate a new object in every test-method, as well as in the #BeforeEach. Still, when running the tests one by one, it all works fine, but when run together it all goes to hell.
Previously I couldn't get the #BeforeEach method to run, but that seems to have been a Maven compatibility issue. It seems to work now with printing stuff out at least.
I have been struggeling with this all day, and rewriting stuff a million times, so sorry if it's a bit messy.
Can someone tell me what I am doing wrong?
Other feedback on the code is also appreciated.
ParkingLotManager class that is to be tested:
package com.mycompany.graduatecase;
import java.util.*;
import com.mycompany.graduatecase.ParkingSpot;
import static com.mycompany.graduatecase.SpaceShipParking.calculateDuration;
import static com.mycompany.graduatecase.SpaceShipParking.calculatePrice;
import static com.mycompany.graduatecase.SpaceShipParking.input;
import java.time.LocalDateTime;
public class ParkingLotManager {
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
public ParkingLotManager(int levels, int parkingsPerLevel) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 15; j++) {
parkingLot.add(new ParkingSpot(i+1, j+1));
}
}
}
public void displayLot(){
for (int i = 0; i < parkingLot.size();i++)
{
System.out.println("Våning: " + parkingLot.get(i).level + " Number: " + parkingLot.get(i).number + " Is available: " + parkingLot.get(i).isAvailable);
}
}
public ParkingSpot getParkingSpot(int level, int number){
for (int i = 0; i < parkingLot.size();i++)
if (parkingLot.get(i).level == level)
if(parkingLot.get(i).number == number){
return parkingLot.get(i);
}
return null;
}
public ParkingSpot getAvailableParkingSpot(){
for (int i = 0; i < parkingLot.size();i++){
if (parkingLot.get(i).isAvailable){
return parkingLot.get(i);
}
}
return null;
}
/*
* Registers a designated parking spot on first available parking spot,
* starting on level 1, spot 1.
*/
public void registerParking(String regNo){
if (getAvailableParkingSpot() == null){
System.out.println("No available parkings right now, please come back later. ");
}else{
ParkingSpot parkingSpot = getAvailableParkingSpot();
System.out.println("\nPlease park on assigned parkingspot.");
System.out.println("Level: " + parkingSpot.level + " Number: " + parkingSpot.number);
parkingSpot.spotTaken();
parkingRecords.addRecord(regNo, parkingSpot);
}
}
/*
* Returns -1 when no found parking for regNo, otherwise returns duration for parking.
*/
public int registerPickup(String regNo){
ParkRecord parkingRecord = parkingRecords.findLatestParkingOnRegNo(regNo);
int durationParked = 0;
if ( parkingRecord == null){
System.out.println("Vi hittade inte din parkering. Försök igen.");
}else{
parkingRecord.setTo(LocalDateTime.now());
ParkingSpot spot = parkingRecord.getParkingSpot();
getParkingSpot(spot.level, spot.number).spotFreed();
durationParked = calculateDuration(parkingRecord.getFrom(), parkingRecord.getTo());
return durationParked;
}
return -1;
}
}
And here's the test class:
package com.mycompany.graduatecase;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;
public class ParkingLotManagerTest {
private ParkingLotManager parkingLot;
public ParkingLotManagerTest() {
}
#BeforeAll
public static void setUpClass() {
}
#AfterAll
public static void tearDownClass() {
}
#BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
#AfterEach
public void tearDown() {
}
/**
* Test of getParkingSpot method, of class ParkingLotManager.
*/
#Test
public void testGetParkingSpot() {
System.out.println("getParkingSpot");
int level = 1;
int number = 1;
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getParkingSpot(level, number);
// assertThat(actualObject)
// .usingRecursiveComparison()
// .isEqualTo(expectedObject);
assertEquals(expectedObject.level, actualObject.level);
assertEquals(expectedObject.number, actualObject.number);
}
#Test
public void testGetAvailableParkingSpot() {
System.out.println("getAvailableParkingSpot returns right object");
int level = 1;
int number = 1;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
#Test
public void testGetAvailableParkingSpot2() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings");
int level = 1;
int number = 4;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
#Test
public void testGetAvailableParkingSpot3() {
System.out.println("getAvailableParkingSpot returns right object after registering 3 parkings and removing 1");
int level = 1;
int number = 2;
//ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
ParkingSpot expectedObject = new ParkingSpot(level, number);
parkingLot.registerParking("123");
parkingLot.registerParking("234");
parkingLot.registerParking("456");
parkingLot.registerPickup("234");
ParkingSpot actualObject = parkingLot.getAvailableParkingSpot();
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
I agree with Robert's quick guess. I think he hit the nail on the head.
If your tests are running concurrently, they will have different ParkingLotManager objects that all share the same underlying data, which is clearly going to be a big concurrency problem. Even if they run serially, the data from the last test will remain so the future tests will end up NOT starting from "Empty".
So, if you know the tests run in order (and not all simultaneously), you can test this theory by adding a call in #AfterEach to a new function parkingLot.reset();
Implement the .reset() function in ParkingLotManager where .reset() clears the underlying (static) lists. That way, each time the previous test completes, the next one has a "fresh" list to work with. This will then make it "appear" as if you are getting a clean ParkingLotManager, instead of a new object with a handle to an old List.
private static ArrayList<ParkingSpot> parkingLot = new ArrayList<ParkingSpot>();
private static ParkingRecords parkingRecords = new ParkingRecords();
I would do what Robert said and try to take the static's out so it behaves likely more as you expected.
Remove:
private ParkingLotManager parkingLot;
...
#BeforeEach
public void setUp() {
parkingLot = new ParkingLotManager(3, 15);
}
and add local variable
ParkingLotManager parkingLot = new ParkingLotManager(3, 15);
on beginning of each test or equivalent of a constructor function (e.g getParkingLotManager3_15()) to not duplicate the code.
You should not have property that belong to test class, when you run tests parallel
I am writing a program which part is presented below:
public class Portal {
private String name;
private int[] positions; // positions of "ship"
private static int moves = 0; // moves made by player to sink a ship
public static int shot; // the value of position given by player
private int hits = 0; // number of hits
private int maxSize = 4; // max size of ship (the size will be randomized)
int first; // position of 1st ship block
int size; // real size of ship (randomized in setPortal method)
public void checkIfHit(){
for (int i : positions){
if (i == shot){
System.out.println("Hit confirmed");
hits++;
} else if (hits == positions.length){
System.out.println("Sunk");
} else {
System.out.println("Missed it");
}
}
moves++;
}
public void setPortal(){
size = 1 + (int)Math.random()*maxSize;
for (int i = 0; i < size - 1; i++){
if (i == 0){
positions[i]= 1 + (int)Math.random()*positions.length;
first = positions[i];
System.out.println(positions[i]);
continue;
}
positions[i]= first + 1;
System.out.println(positions[i]);
}
}
}
public class Main{
public static void main(String[] args){
// write your code here
Portal p1 = new Portal();
p1.setPortal();
}
}
code is split in two Java .class files.
The problem I'm dealing with is that using p1.setPortal(); doesn't show up text in IntelliJ console. The program works though and returns 0.
I don't have such problem in another program when I've put System.out.println in method other than main (also in separate class file).
What may be the cause of such issue?
It should properly throw an exception, because you forgot to initialize the integer array.
Have a look at this thread: Do we need to initialize an array in Java?
The Java's default value is null for an integer array. So your for wont even loop trough. The only thing that wonders me is why there is no exception..
I don't want to solve an equation and my question is not about Graphs and Trees Data Structures. I am trying to generate Data Points for graph from an equation given by user. I want efficient algorithm, easy to use and easy to maintain data structures. I have two solutions in mind
1: This is trivial and I have seen in many Applications.
String expr = "2*x+3*x";
Evaluator evaluator = new Evaluator();//I have this class
for (int i = start; i < end; i += step)
{
evaluator.setConstant("x", i);
double ans = evaluator.evaluate(expr);
}
This is very slow because each time every step is repeated like tokenzing, verifying, conversion to RPN, preparing stacks and queues and at last result calculation. The possible solution to this problem is somehow caching all stacks and queues but after that a comparison would be required between current expression and previous expression to use last stored state.
2: Currently I am developing second solution. The purpose of this is efficiency and would be used in Symbolic calculation in future.
So far my implementation
Variable.java
import java.text.DecimalFormat;
public class Variable
{
private final double pow;
private final double coefficient;
private final String symbol;
public Variable(String symbol)
{
this.symbol = symbol;
this.pow = 1.0;
this.coefficient = 1.0;
}
public Variable(String symbol, double coefficient, double pow)throws IllegalArgumentException
{
if (coefficient == 0.0)throw new IllegalArgumentException("trying to create variable with coefficient 0");
if (pow == 0.0)throw new IllegalArgumentException("trying to create variable with exponent 0");
this.symbol = symbol;
this.pow = pow;
this.coefficient = coefficient;
}
public final String getSymbol()
{
return this.symbol;
}
public final double getPow()
{
return this.pow;
}
public final double getCoefficient()
{
return this.coefficient;
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
DecimalFormat decimalFormat = new DecimalFormat("#.############");
if (coefficient != 1.0)builder.append(decimalFormat.format(this.coefficient));
builder.append(this.symbol);
if (this.pow != 1.0)builder.append("^").append(decimalFormat.format(this.pow));
return builder.toString();
}
/*
* Stub Method
* Generate some unique hash code
* such that chances of key collision
* become less and easy to identify
* variables with same power and same
* symbol*/
#Override
public int hashCode()
{
return 0;
}
}
Equation.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
public class Equation
{
private final ArrayList<Boolean> operations;
private final HashMap<String, Variable> variableHashMap;
private int typesOfVariables;
public Equation(Variable variable)
{
this.variableHashMap = new HashMap<>();
this.operations = new ArrayList<>();
this.typesOfVariables = 1;
this.variableHashMap.put(variable.getSymbol(), variable);
}
/*Stub Method*/
public void addVariable(Variable variable, boolean multiply)
{
/*
* Currently not covering many cases
* 1: Add two variables which have same name
* and same pow.
* 2: variable which are wrapped inside functions e.g sin(x)
* and many other.*/
if (multiply && variableHashMap.containsKey(variable.getSymbol()))
{
Variable var = variableHashMap.get(variable.getSymbol());
Variable newVar = new Variable(var.getSymbol(), var.getCoefficient() * variable.getCoefficient(), var.getPow() + variable.getPow());
/*
* Collision chances for variables with same name but
* with different powers*/
this.variableHashMap.replace(var.getSymbol(), newVar);
}
else
{
++this.typesOfVariables;
this.variableHashMap.put(variable.getSymbol(), variable);
}
this.operations.add(multiply);
}
/*Stub Method
*Value for every variable at any point will be different*/
public double solveFor(double x)
{
if (typesOfVariables > 1)throw new IllegalArgumentException("provide values for all variables");
Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator();
Variable var;
double ans = 0.0;
if (entryIterator.hasNext())
{
var = entryIterator.next().getValue();
ans = var.getCoefficient() * Math.pow(x, var.getPow());
}
for (int i = 0; entryIterator.hasNext(); i++)
{
var = entryIterator.next().getValue();
if (this.operations.get(i))ans *= var.getCoefficient() * Math.pow(x, var.getPow());
else ans += var.getCoefficient() * Math.pow(x, var.getPow());
}
return ans;
}
#Override
public String toString()
{
StringBuilder builder = new StringBuilder();
Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator();
if (entryIterator.hasNext())builder.append(entryIterator.next().getValue().toString());
Variable var;
for (int i = 0; entryIterator.hasNext(); i++)
{
var = entryIterator.next().getValue();
if (this.operations.get(i))builder.append("*").append(var.toString());
else builder.append(var.toString());
}
return builder.toString();
}
}
Main.java
class Main
{
public static void main(String[] args)
{
try
{
long t1 = System.nanoTime();
Variable variable = new Variable("x");
Variable variable1 = new Variable("x", -2.0, 1.0);
Variable variable2 = new Variable("x", 3.0, 4.0);
Equation equation = new Equation(variable);
equation.addVariable(variable1, true);//2x+x
equation.addVariable(variable2, true);
for (int i = 0; i < 1000000; i++)equation.solveFor(i);//Calculate Million Data Points
long t2 = System.nanoTime();
System.out.println((t2-t1)/1000/1000);
System.out.println(equation.toString());
}
catch (Exception e)
{
System.out.println("Error: " + e.getMessage());
}
}
}
Am I going in right direction?
Is there any commonly used Algorithm for this problem?
My main goal is efficiency, code cleanness and code maintainability.
Note: I am not native English speaker so please ignore any grammatical mistake.
Thanks.
I do not see any problem with your first code. Yes may be at every step your code "repeat like tokenzing, verifying, conversion to RPN, preparing stacks and queues and at last result calculation", but in the end all of this is just linear number of steps. So I fail to see how it can make it really slow.
One of the biggest screens I have seen was 2560x1440 pixels, which means that most of the time you would need less than 2500 points to draw your graph there.
If you point is code cleanness and code maintainability, then most probably a code consisting of 5 lines is better than the code consisting of 200.
I'm trying to display 550 data points with periodic peaks (the flat line is 61). The problem is, that androidplot isn't drawing all the points correctly! From my log:
ECG I values 61,61,62,63,62,61,61,61,61,67,71,68,61,53,61,61,61,61,61,61,61,61,62,63,64,64,64,63,62,61,61,61
I've got the rangeboundaries set to plot.setRangeBoundaries(0,100, BoundaryMode.AUTO);, but as you can see, the peaks never drop to the 53 data point. I can see this lower point sometimes, but it gets smoothed out a fraction of a second later (as you can see in the screenshot).
My line and point formatter is:
LineAndPointFormatter lapf = new LineAndPointFormatter(p.color, null, null, null);
lapf.getLinePaint().setStrokeJoin(Paint.Join.MITER);
lapf.getLinePaint().setStrokeWidth(1);
I've tried with the both Paint.Join.ROUND and Paint.Join.BEVEL and got the same effect. I've also used the debugger to check that 53 is being inserted into the series.
EDIT
After some debugging, it looks like my pulse loop thread is wrong:
while (keepRunning) {
for (PulseXYSeries j : series) {
for (int k = 0; k < j.plotStep; k++) {
int at = (j.position + k) % j.getSize();
if (j.pulsing) {
if (j.pulsePosition == j.pulseValues.size() - 1) {
j.pulsing = false;
j.pulsePosition = 0;
} else {
try {
int pulseVal = j.pulseValues.get(j.pulsePosition);
j.setY(pulseVal,at);
j.pulsePosition += 1;
} catch(IndexOutOfBoundsException e) {
j.pulsePosition = 0;
}
}
} else {
j.setY(j.pulseValues.get(0), at);
long currTime = SystemClock.elapsedRealtime();
if (currTime - j.getLastPulse() >= j.getPulseDelay()) {
j.pulsing = true;
j.setLastPulse(currTime);
}
}
j.remove(((at + j.eraserSize) % j.getSize()));
}
j.position = (j.position + 1) % j.getSize(); // fixed it by changing +1 to + j.plotStep
}
Thread.sleep(delay);
}
My custom series looks like:
private class PulseXYSeries implements XYSeries {
private List<Integer> pulseValues = new ArrayList<Integer>();
private int pulsePerMinute;
public int pulsePosition;
public int position;
private ArrayList<Integer> values;
private String title;
private long lastPulse;
public boolean pulsing = false;
public int eraserSize = 20;
public int plotStep = 3;
}
I'm pretty new to java and I'm trying to create a program that quizzes users on the difference between 2 random frequencies. Everything works except that when I try to get the difference of 2 frequencies the answer is always 0. How do I get it to display the actual difference? Here is the class I wrote to create the tones ans compute the difference:
public class Quiz{
private PitchPlay one = new PitchPlay();
private PitchPlay two = new PitchPlay();
private int frequencyOne;
private int frequencyTwo;
private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
public int run(){
frequencyOne = new Integer((int)(Math.random() * 5000 + 50));
frequencyTwo = new Integer((int)(Math.random() * 5000 + 50));
return this.dif;
}
public int freqDif(){
return this.dif;
}
public void playQuiz(){
one.play(one.note(frequencyOne, 2, 15));//note(frequency, duration, volume)
two.play(two.note(frequencyTwo, 2, 15));
}
}
And here is the class where the quiz class is used:
public class Action implements ActionListener{
Quiz one = new Quiz();
public void actionPerformed (ActionEvent e){
if(e.getSource() == playSoundButton)
{
if(answerResponse.getText().compareTo("Correct!") == 0 || answerResponse.getText().compareTo("Play and Listen...") == 0)
{
one.run();
one.playQuiz();
}
else
{
one.playQuiz();
}
}
if(e.getSource() == submitButton)
{
String responseText = new String(responseField.getText());
if(responseText !=null && !"".equals(responseText)){
try{
Integer responseNumber = Integer.parseInt(responseText);
if(responseNumber == one.freqDif())
{
answerResponse.setText("Correct!");
answerResponse.setVisible(true);
}
else
{
answerResponse.setText("Wrong Answer. The difference is " + one.freqDif() + " hertz.");
answerResponse.setVisible(true);
}
}catch(NumberFormatException f){
f.printStackTrace(System.out);
}
}
}
}
}
private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
This is calculated when the variable is created, not when you use the variable. You need to do the calculation after assigning the variables.
There are several issues with your code:
As others have mentioned, the line
private int dif = new Integer(Math.abs(frequencyTwo - frequencyOne));
creates a variable and assigns a value calculated from two other variables. The values of the other variables at the time of creation are used. You need to recalculate every time the values of those two variables changes. This does not happen automatically for you.
new Integer(...) creates an Integer object. When you subsequently assign this object to an int variable, the value is taken out of the object. This adds some unnecessary memory and run-time over head to your code. Instead, you should assign directly to your variables. For example,
frequencyOne = (int)(Math.random() * 5000 + 50);