I plan in JavaFX a new Game 'Number-Shape-System'. Basically its a little memory game where pictures are associated with numbers. So '2'='Swan', '5'='Hand(Fingers)' and so on. So the player see the exercise 'Swan + Fingers = ?'.
What I want is all possible mathematically operations following rules:
/*
* Generate all possible mathematical operations to the console with the numbers
* 0-12, where every result is (>= 0 && <= 12).
* - Mathematical operations are '+', '-', '*' and '/'.
* - The rule 'dot before line' shouldn't be used, instead the operations will
* be executed from left to right.
* - Every among result must be between (>= 0 && <= 12) and a whole number.
* - Only different numbers are allowed for the operations (an operation have
* 2 numbers). For example 2+3 is allowed, 3*3 not.
*
* A solution with recursive methods would be preferred. I want the output for
* the length 2-10.
*
* Example output with different length:
* - Length 3: 2+3(=5)*2(=10)
* - Length 5: 2+3(=5)*2(=10)+2(=12)/4(=3)
*/
I have prepared a example implementation, but I don't know how to convert it to a recursive functionality.
import java.util.ArrayList;
import java.util.List;
public class Generator {
private static final List<Double> numbers = new ArrayList<>();
private static final List<String> operations = new ArrayList<>();
static {
numbers.add(0.0);
numbers.add(1.0);
numbers.add(2.0);
numbers.add(3.0);
numbers.add(4.0);
numbers.add(5.0);
numbers.add(6.0);
numbers.add(7.0);
numbers.add(8.0);
numbers.add(9.0);
numbers.add(10.0);
numbers.add(11.0);
numbers.add(12.0);
operations.add("+");
operations.add("-");
operations.add("*");
operations.add("/");
}
private int lineCounter = 0;
public Generator() {
this.init();
}
private void init() {
}
public void generate() {
// Length 2 ###########################################################
boolean okay = false;
int lineCounter = 0;
StringBuilder sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation : operations) {
if (first == second) {
continue;
}
if (operation.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result = perform(first, operation, second);
okay = this.check(result, operation);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation, second, result);
System.out.println(sbDouble.toString());
}
}
}
}
System.out.println("Compute with length 2: " + lineCounter + " lines");
// Length 2 ###########################################################
// Length 3 ###########################################################
okay = false;
lineCounter = 0;
sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation1 : operations) {
if (first == second) {
continue;
}
if (operation1.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result1 = perform(first, operation1, second);
okay = this.check(result1, operation1);
if (okay) {
for (Double third : numbers) {
for (String operation2 : operations) {
if (second == third) {
continue;
}
if (operation2.equals("/") && third == 0.0) {
continue;
}
double result2 = perform(result1, operation2, third);
okay = this.check(result2, operation2);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation1, second, result1);
this.computeResultAsString(sbDouble, operation2, third, result2);
System.out.println(sbDouble.toString());
}
}
}
}
}
}
}
System.out.println("Compute with length 3: " + lineCounter + " lines");
// Length 3 ###########################################################
// Length 4 ###########################################################
okay = false;
lineCounter = 0;
sbDouble = new StringBuilder();
for (Double first : numbers) {
for (Double second : numbers) {
for (String operation1 : operations) {
if (first == second) {
continue;
}
if (operation1.equals("/") && (first == 0.0 || second == 0.0)) {
continue;
}
double result1 = perform(first, operation1, second);
okay = this.check(result1, operation1);
if (okay) {
for (Double third : numbers) {
for (String operation2 : operations) {
if (second == third) {
continue;
}
if (operation2.equals("/") && third == 0.0) {
continue;
}
double result2 = perform(result1, operation2, third);
okay = this.check(result2, operation2);
if (okay) {
for (Double forth : numbers) {
for (String operation3 : operations) {
if (third == forth) {
continue;
}
if (operation3.equals("/") && forth == 0.0) {
continue;
}
double result3 = perform(result2, operation3, forth);
okay = this.check(result3, operation3);
if (okay) {
++lineCounter;
sbDouble = new StringBuilder();
this.computeResultAsString(sbDouble, first, operation1, second, result1);
this.computeResultAsString(sbDouble, operation2, third, result2);
this.computeResultAsString(sbDouble, operation3, forth, result3);
System.out.println(sbDouble.toString());
}
}
}
}
}
}
}
}
}
}
System.out.println("Compute with length 4: " + lineCounter + " lines");
// Length 4 ###########################################################
}
private boolean check(double result, String operation) {
switch (operation) {
case "+":
case "-":
case "*": {
if (result > 0 && result <= 12) {
return true;
}
break;
}
case "/": {
if (
(Math.floor(result) == result)
&& (result >= 0 && result <= 12)
) {
return true;
}
break;
}
}
return false;
}
private double perform(double first, String operation, double second) {
double result = 0.0;
switch (operation) {
case "+": { result = first + second; break; }
case "-": { result = first - second; break; }
case "*": { result = first * second; break; }
case "/": { result = first / second; break; }
}
return result;
}
private void computeResultAsString(StringBuilder sbDouble, String operation, double second, double result) {
sbDouble.append(operation);
sbDouble.append(second);
sbDouble.append("(=");
sbDouble.append(result);
sbDouble.append(")");
}
private void computeResultAsString(StringBuilder sbDouble, double first, String operation, double second, double result) {
sbDouble.append(first);
sbDouble.append(operation);
sbDouble.append(second);
sbDouble.append("(=");
sbDouble.append(result);
sbDouble.append(")");
}
public static void main(String[] args) {
final Generator generator = new Generator();
generator.generate();
}
}
As you can see in your own code, for each increase in "length", you have to nest another block of the same code. With a dynamic length value, you can't do that.
Therefore, you move the block of code into a method, and pass in a parameter of how many more times it has to "nest", i.e. a remainingLength. Then the method can call itself with a decreasing value of remainingLength, until you get to 0.
Here is an example, using an enum for the operator.
public static void generate(int length) {
if (length <= 0)
throw new IllegalArgumentException();
StringBuilder expr = new StringBuilder();
for (int number = 0; number <= 12; number++) {
expr.append(number);
generate(expr, number, length - 1);
expr.setLength(0);
}
}
private static void generate(StringBuilder expr, int exprTotal, int remainingLength) {
if (remainingLength == 0) {
System.out.println(expr);
return;
}
final int exprLength = expr.length();
for (int number = 0; number <= 12; number++) {
if (number != exprTotal) {
for (Operator oper : Operator.values()) {
int total = oper.method.applyAsInt(exprTotal, number);
if (total >= 0 && total <= 12) {
expr.append(oper.symbol).append(number)
.append("(=").append(total).append(")");
generate(expr, total, remainingLength - 1);
expr.setLength(exprLength);
}
}
}
}
}
private enum Operator {
PLUS ('+', Math::addExact),
MINUS ('-', Math::subtractExact),
MULTIPLY('*', Math::multiplyExact),
DIVIDE ('/', Operator::divide);
final char symbol;
final IntBinaryOperator method;
private Operator(char symbol, IntBinaryOperator method) {
this.symbol = symbol;
this.method = method;
}
private static int divide(int left, int right) {
if (right == 0 || left % right != 0)
return -1/*No exact integer value*/;
return left / right;
}
}
Be aware that the number of permutations grow fast:
1: 13
2: 253
3: 5,206
4: 113,298
5: 2,583,682
6: 61,064,003
7: 1,480,508,933
Related
We define balanced number as number which has the same number of even and odd dividers e.g (2 and 6 are balanced numbers). I tried to do task for polish SPOJ however I always exceed time.
The task is to find the smallest balance number bigger than given on input.
There is example input:
2 (amount of data set)
1
2
and output should be:
2
6
This is my code:
import java.math.BigDecimal;
import java.util.Scanner;
public class Main {
private static final BigDecimal TWO = new BigDecimal("2");
public static void main(String[] args) throws java.lang.Exception {
Scanner in = new Scanner(System.in);
int numberOfAttempts = in.nextInt();
for (int i = 0; i < numberOfAttempts; i++) {
BigDecimal fromNumber = in.nextBigDecimal();
findBalancedNumber(fromNumber);
}
}
private static boolean isEven(BigDecimal number){
if(number.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) != 0){
return false;
}
return true;
}
private static void findBalancedNumber(BigDecimal fromNumber) {
BigDecimal potentialBalancedNumber = fromNumber.add(BigDecimal.ONE);
while (true) {
int evenDivider = 0;
int oddDivider = 1; //to not start from 1 as divisor, it's always odd and divide potentialBalancedNumber so can start checking divisors from 2
if (isEven(potentialBalancedNumber)) {
evenDivider = 1;
} else {
oddDivider++;
}
for (BigDecimal divider = TWO; (divider.compareTo(potentialBalancedNumber.divide(TWO)) == -1 || divider.compareTo(potentialBalancedNumber.divide(TWO)) == 0); divider = divider.add(BigDecimal.ONE)) {
boolean isDivisor = potentialBalancedNumber.remainder(divider).compareTo(BigDecimal.ZERO) == 0;
if(isDivisor){
boolean isEven = divider.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) == 0;
boolean isOdd = divider.remainder(new BigDecimal("2")).compareTo(BigDecimal.ZERO) != 0;
if (isDivisor && isEven) {
evenDivider++;
} else if (isDivisor && isOdd) {
oddDivider++;
}
}
}
if (oddDivider == evenDivider) { //found balanced number
System.out.println(potentialBalancedNumber);
break;
}
potentialBalancedNumber = potentialBalancedNumber.add(BigDecimal.ONE);
}
}
}
It seems to work fine but is too slow. Can you please help to find way to optimize it, am I missing something?
As #MarkDickinson suggested, answer is:
private static void findBalancedNumberOptimized(BigDecimal fromNumber) { //2,6,10,14,18,22,26...
if(fromNumber.compareTo(BigDecimal.ONE) == 0){
System.out.println(2);
}
else {
BigDecimal result = fromNumber.divide(new BigDecimal("4")).setScale(0, RoundingMode.HALF_UP).add(BigDecimal.ONE);
result = (TWO.multiply(result).subtract(BigDecimal.ONE)).multiply(TWO); //2(2n-1)
System.out.println(result);
}
}
and it's finally green, thanks Mark!
I planned to develop an equation solver from basic and able to do basic mathematics operations using below code. I have used a token stack structure which will used to store the deliminator and number token. Though this implementation is too basic, I want to improve it on later version. I just need some helps the way I use the data structure to store the token as a set of stacks. Please kindly suggest any mistake ?
import java.util.ArrayList;
import java.util.Stack;
class TokenStack<N, D> {
private Stack<N> numberStack;
private Stack<D> delimStack;
public TokenStack() {
numberStack = new Stack<N>();
delimStack = new Stack<D>();
}
public void pushN(N num) {
numberStack.push(num);
}
public N popN() {
return numberStack.pop();
}
public void pushD(D delim) {
delimStack.push(delim);
}
public D popD() {
return delimStack.pop();
}
public boolean isEmptyN() {
return numberStack.isEmpty();
}
public boolean isEmptyD() {
return delimStack.isEmpty();
}
}
public class GeneralST {
private static final char SPACE_DELIM = ' ';
private static final char ADD_DELIM = '+';
private static final char SUB_DELIM = '-';
private static final char MUL_DELIM = '*';
private static final char DIV_DELIM = '/';
protected static final char EQU_DELIM = '=';
private TokenStack<String, Character> tokens = new TokenStack<String, Character>();
protected ArrayList<Character> acceptedDelims = new ArrayList<Character>();
protected ArrayList<Character> mathsDelims = new ArrayList<Character>();
protected double result;
public double getResult() {
return result;
}
protected void setupDelims() {
acceptedDelims.add(SPACE_DELIM);
mathsDelims.add(ADD_DELIM);
mathsDelims.add(SUB_DELIM);
mathsDelims.add(MUL_DELIM);
mathsDelims.add(DIV_DELIM);
acceptedDelims.addAll(mathsDelims);
}
private void tokenize(String str) {
String reverse = "";
for (int i = str.length() - 1; i >= 0; i--) {
char charAt = str.charAt(i);
if (i > 1) {
char charPre = str.charAt(i - 1);
if (acceptedDelims.indexOf(charAt) == -1 && (charPre == '-' || charPre == '+')) {
reverse = reverse + charPre + charAt;
i--;
} else {
reverse = reverse + charAt;
}
} else {
reverse = reverse + charAt;
}
}
int i = 0;
while (reverse.length() > 2) {
char charAt = reverse.charAt(i);
char chartNext = reverse.charAt(i + 1);
if (acceptedDelims.indexOf(charAt) != -1 && acceptedDelims.indexOf(chartNext) != -1) {
String previous = reverse.substring(0, i);
if (!previous.equals("") && !previous.equals(" ")) {
tokens.pushN(previous);
}
if (mathsDelims.indexOf(charAt) != -1) {
tokens.pushD(charAt);
}
reverse = reverse.substring(i + 1);
i = i - previous.length() - 1;
}
i++;
}
if (!reverse.equals("")) {
tokens.pushN(reverse);
}
}
private double equate() {
double val = 0;
int step = 1;
int side = 1;
while (!tokens.isEmptyN() && !tokens.isEmptyD()) {
char delim = tokens.popD();
double val1 = Double.valueOf(tokens.popN());
double val2 = side * Double.valueOf(tokens.popN());
switch (delim) {
case ADD_DELIM:
val = val1 + val2;
break;
case SUB_DELIM:
val = val1 - val2;
break;
case MUL_DELIM:
val = val1 * val2;
break;
case DIV_DELIM:
try {
val = val1 / val2;
break;
} catch (Exception exception) {
exception.printStackTrace();
break;
}
case EQU_DELIM:
val = val1 - val2;
side = -1;
delim = '-';
}
String outString = "Step %d : %s %c %s = %f";
String printString = String.format(outString, step, val1, delim, val2, val);
step++;
System.out.println(printString);
tokens.pushN(String.valueOf(val));
}
return val;
}
public GeneralST(String str) {
System.out.println("--------------------------------------");
System.out.println("[EXP] : " + str);
setupDelims();
tokenize(str);
result = equate();
System.out.println("--------------------------------------");
}
public void PrintResult() {
System.out.println("Result = " + result);
}
}
class EquateST extends GeneralST {
public EquateST(String str) {
super(str);
}
#Override
protected void setupDelims() {
mathsDelims.add(EQU_DELIM);
super.setupDelims();
}
public void PrintResult() {
if (result == 0) {
System.out.println("Result = True");
} else {
System.out.println("Result = False");
}
}
}
class Main {
public static void main(String[] args) {
String[] equations = {"6 + 2 + -4 * 4 - 5", "6 + 2 - 4 * 4 = -5", "6 + -2 - 4 = 4 - 5"};
calculate(equations);
}
private static void calculate(String... equations)
{
for (String equation : equations) {
if (equation.contains("=")) {
EquateST equateST = new EquateST(equation);
equateST.PrintResult();
} else {
GeneralST generalST = new GeneralST(equation);
generalST.PrintResult();
}
}
}
}
Sample Results
--------------------------------------
[EXP] : 6 + 2 + -4 * 4 - 5
Step 1 : 6.0 + 2.0 = 8.000000
Step 2 : 8.0 + -4.0 = 4.000000
Step 3 : 4.0 * 4.0 = 16.000000
Step 4 : 16.0 - 5.0 = 11.000000
--------------------------------------
Result = 11.0
--------------------------------------
[EXP] : 6 + 2 - 4 * 4 = -5
Step 1 : 6.0 + 2.0 = 8.000000
Step 2 : 8.0 - 4.0 = 4.000000
Step 3 : 4.0 * 4.0 = 16.000000
Step 4 : 16.0 - -5.0 = 21.000000
--------------------------------------
Result = False
--------------------------------------
[EXP] : 6 + -2 - 4 = 4 - 5
Step 1 : 6.0 + -2.0 = 4.000000
Step 2 : 4.0 - 4.0 = 0.000000
Step 3 : 0.0 - 4.0 = -4.000000
Step 4 : -4.0 - -5.0 = 1.000000
--------------------------------------
Result = False
Your problem is "arithmetic evaluation".
It was mentioned in many book "Algorithm".
Best and simple way to solve it : using stack and "postfix notation".
You can find a lot of article with your favorite programming languages.
Hello I'm new to java can anyone help me?
This code convert
2000 to 2k and 1000000 1m etc
private static final NavigableMap<Long, String> suffixes = new TreeMap<>();
static {
suffixes.put(1_000L, "k");
suffixes.put(1_000_000L, "M");
suffixes.put(1_000_000_000L, "G");
suffixes.put(1_000_000_000_000L, "T");
suffixes.put(1_000_000_000_000_000L, "P");
suffixes.put(1_000_000_000_000_000_000L, "E");
}
public String format(long value) {
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
if (value < 0) return "-" + format(-value);
if (value < 1000) return Long.toString(value); //deal with easy case
Map.Entry<Long, String> e = suffixes.floorEntry(value);
Long divideBy = e.getKey();
String suffix = e.getValue();
long truncated = value / (divideBy / 10); //the number part of the output times 10
boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}
I need a code which reverse the conversion for example
2k to 2000 and 1m to 1000000
I got the solution just by storing the values in an ArrayList before converting and it worked osum. Thanks for the help everyone :)
I have posted a solution. Need proper input as proper validations are not included. Let me know if it fits your need. also you can add/modify the switch cases according to your need.
public class Test {
public static void main(String[] args) {
String values[] = {
"27",
"999",
"1.0 k",
"110.6 k",
"29.0 G",
"5m",
"5m30",
"2.7k",
"2k7",
"2k17",
"9.2 E",
"9.2EE"
};
Test test = new Test();
test.printValues(values);
}
private void printValues(String[] values) {
for (String value : values) {
if (isProperNumber(value)) {
printValue(value);
} else {
System.out.println("Not a proper number");
}
System.out.println("===================");
}
}
private void printValue(String value) {
String lastAlphabet = value.replaceAll("[^a-zA-Z]*$", "")
.replaceAll(".(?!$)", "");
long multiplier = 1L;
switch (lastAlphabet.toLowerCase()) {
case "k":
multiplier = 1_000L;
break;
case "m":
multiplier = 1_000_000L;
break;
case "g":
multiplier = 1_000_000_000L;
break;
case "t":
multiplier = 1_000_000_000_000L;
break;
case "p":
multiplier = 1_000_000_000_000_000L;
break;
case "e":
multiplier = 1_000_000_000_000_000_000L;
break;
default:
break;
}
String[] values = value.split(lastAlphabet);
if (multiplier == 1) {
System.out.println("" + values[0]);
} else {
double valueMultiplier = Double.parseDouble(values[0]);
double valueAdder;
try {
valueAdder = Double.parseDouble(values[1]);
} catch (ArrayIndexOutOfBoundsException ex) {
valueAdder = 0.0d;
}
double total = (valueMultiplier * multiplier) + valueAdder;
System.out.printf("%.0f\n", total);
}
}
private boolean isProperNumber(String value) {
value = value.replaceAll("\\s+", "");
String count = value.replaceAll("[.0-9]+", "");
return count.length() < 2;
}
}
no need to worry, just use simple JS Trick with Round figure up to 2 decimal places.
function somefunction(count){
if (count >= 1000) {
return Math.round((count/1000) * 10)/10+'k';
} else {
return count;
}
}
if you want put more functionalities, just put more else if with devide 1000 with more million or billion, just 2 or 3 more else if makes your code better.
private static final String dp(String value) {
if (value.contains("k") || value.contains("K")){
value.replace("k", "000");
value.replace("K", "000");
} else if (value.contains("m") || value.contains("M")){
value.replace("m", "000000");
value.replace("M", "000000");
} else if (value.contains("g") || value.contains("G")){
value.replace("g", "000000000");
value.replace("G", "000000000");
} ......
return value;
}
Below are the 2 methods which I am using to generate a random number from a range of numbers.This is part of a small maths quiz. The number of questions can go upto 50 questions. The only clause is the numbers should be non repeated i.e 5x6 if is present in the list I cant have 6x5 in the list.
The problem that I am facing is the below code throws stackoverflow error.I have tried to run it in a separate thread but I am unable to get it working.
The for loop used inside the first method is the one I use to check if the number is already present.
public QuestionsV1 generateQuestionsArray(int level, int range) {
generateRandomNumbers(level, range);
for (QuestionsV1 questions : questionsList) {
if (questionsList != null && ((first_number == questions.getFirst_number() && second_number == questions.getSecond_number())
|| (first_number == questions.getSecond_number() &&
second_number == questions.getFirst_number()))) {
generateQuestionsArray(level, range);
break;
}
}
Log.d("ArrayList---", first_number + " " + second_number);
QuestionsV1 questions = new QuestionsV1();
questions.setFirst_number(first_number);
questions.setSecond_number(second_number);
questions.setOperator("x");
questions.setCorrect_answer(first_number * second_number);
return questions;
}
public void generateRandomNumbers(int level, int range) {
Random rand1 = new Random();
Random rand2 = new Random();
if (range == 0) {
first_number = rand1.nextInt(3 - 1 + 1) + 1;
} else if (range == 1) {
first_number = rand1.nextInt(6 - 4 + 1) + 4;
} else if (range == 2) {
first_number = rand1.nextInt(10 - 7 + 1) + 7;
}
switch (level) {
case 1:
second_number = rand2.nextInt(6 - 2 + 1) + 2;
break;
case 2:
second_number = rand2.nextInt(12 - 7 + 1) + 7;
break;
case 3:
second_number = rand2.nextInt(20 - 13 + 1) + 13;
break;
}
below is the error which I am getting.
Fatal Exception: java.lang.StackOverflowError: stack size 2MB
at java.util.concurrent.atomic.AtomicLong.<init>(AtomicLong.java:61)
at java.util.Random.<init>(Random.java:137)
at java.util.Random.<init>(Random.java:105)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:80)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbers(Multiply.java:106)
at com.leapscale.scimat.t4e.Builders.Multiply.generateQuestionsArray(Multiply.java:39)
at com.leapscale.scimat.t4e.Builders.Multiply.generateRandomNumbersHard(Multiply.java:74)
at com.leapscale.scimat.t4e.Builders.Multiply.calculateNoOfQuestionsForLevels(Multiply.java:141)
at com.leapscale.scimat.t4e.Builders.Multiply.getList(Multiply.java:146)
at com.leapscale.scimat.t4e.Levels.Levels_Fragment$QuestionBuilder$1.run(Levels_Fragment.java:185)
at java.lang.Thread.run(Thread.java:761)
Instead of using recursive call use a while loop to keep generating until a non-duplicate value is created. Something similar to this:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class App {
private static final int QUESTION_COUNT = 25;
private static final int RANGE = 10;
private static final Random RAND = new Random();
public static void main(String[] args) {
App app = new App();
app.generateAndDisplayQuestions();
}
private void generateAndDisplayQuestions() {
List<QuestionV1> questions = new ArrayList<>();
for (int q = 0; q < QUESTION_COUNT; q++) {
while(true) {
QuestionV1 question = getNextRandomQuestion();
if (!questions.contains(question)) {
questions.add(question);
break;
}
System.out.println("found a duplicate - trying again...");
}
System.out.println("Question " + (q + 1) + ": first = " + questions.get(q).getFirst() + " : second = " + questions.get(q).getSecond());
}
}
private QuestionV1 getNextRandomQuestion() {
return new QuestionV1(RAND.nextInt(RANGE), RAND.nextInt(RANGE));
}
private class QuestionV1 {
private int first;
private int second;
public QuestionV1(int first, int second) {
this.first = first;
this.second = second;
}
#Override
public boolean equals(Object o) {
QuestionV1 other = (QuestionV1)o;
return (this.first == other.first && this.second == other.second) || (this.first == other.second && this.second == other.first);
}
#Override
public int hashCode() {
return first * 31 + second;
}
public int getFirst() {
return first;
}
public int getSecond() {
return second;
}
}
}
Not that if RANGE is low and QUESTION_COUNTis high, then this will cause an infinite loop since all possible combinations will be used.
This portion of my program seems to be giving me a problem:
public static double[] getBonusAmt(boolean[] bonusEligibility, int[] numYrsFlown, double[] bonusAmt) {
bonusAmt = new double[bonusEligibility.length];
double bonus = 0;
for (boolean b : bonusEligibility) {
for (int i : numYrsFlown) {
if (i >= 9 && b == true) {
bonus = 2410.00;
}
else if (i < 9 && i >= 6 && b == true) {
bonus = 1206.00;
}
else if (i < 6 && i >= 2 && b == true) {
bonus = 515.00;
}
else if (i < 2 && b == true) {
bonus = 0.00;
}
}
}
return bonusAmt;
}
Input/Output:
Name: [joe, james]
Years flown: [2, 2]
Miles flown: [45, 43]
Average miles between pilots: 44
Bonus eligibility: [true, false]
Bonus amount: [0.00, 0.00]
Joe should be earning a bonus because his miles flown is greater than the average, but his amount is zero. The expected bonus amount for Joe should be 515.00 because one, he is eligible for a bonus and two, has only flown for 2 years.
Can anyone see why the bonus amount is always zero even if I enter another person that has flown more than the average?
Your method assigns values to the bonus variable but returns a bonusAmt variable, which is never assigned, so its values remain 0.0.
Your nested loops don't make much sense. It looks like you need a single regular for loop, assuming that the i'th index of bonusEligibility array corresponds with the i'th index of the numYrsFlown array.
public static double[] getBonusAmt(boolean[] bonusEligibility, int[] numYrsFlown) {
double[] bonusAmt = new double[bonusEligibility.length];
for (int i = 0; i < bonusEligibility.length; i++) {
if (numYrsFlown[i] >= 9 && bonusEligibility[i]) {
bonus = 2410.00;
}
else if (numYrsFlown[i] < 9 && numYrsFlown[i] >= 6 && bonusEligibility[i]) {
bonusAmt[i] = 1206.00;
}
else if (numYrsFlown[i] < 6 && numYrsFlown[i] >= 2 && bonusEligibility[i]) {
bonusAmt[i] = 515.00;
}
else if (numYrsFlown[i] < 2 && bonusEligibility[i]) {
bonusAmt[i] = 0.00;
}
}
return bonusAmt;
}
BTW, there's no point in passing the bonusAmt array as an argument to the method, since the method assigns to it a reference to a new array.
You forgot to set bonusAmt to the selected bonus value.
Here is a more object oriented way to do what you want. No need to accept this answer as Eran's solution explains your error perfectly ... This is just another way of doing it ...
public class MainApp {
public static void main(String[] args) {
AirMilesCustomer[] customers = new AirMilesCustomer[] {
new AirMilesCustomer("John", true, 2),
new AirMilesCustomer("Jane", true, 5),
new AirMilesCustomer("Sally", true, 7),
new AirMilesCustomer("Bill", false, 10),
new AirMilesCustomer("Stacy", true, 15)
};
for(AirMilesCustomer customer : customers) {
System.out.println(customer);
}
}
}
class AirMilesCustomer {
private String _name;
private boolean _bonusEligibility;
private int _numYrsFlown;
public AirMilesCustomer(String name, boolean bonusEligibility, int numYrsFlown) {
_name = name;
_bonusEligibility = bonusEligibility;
_numYrsFlown = numYrsFlown;
}
public String getName() {
return _name;
}
public boolean isBonusEligibility() {
return _bonusEligibility;
}
public int getNumYrsFlown() {
return _numYrsFlown;
}
public double getBonusAmount() {
double bonus = 0.00;
if (_numYrsFlown >= 9 && _bonusEligibility) {
bonus = 2410.00;
}
else if (_numYrsFlown < 9 && _numYrsFlown >= 6 && _bonusEligibility) {
bonus = 1206.00;
}
else if (_numYrsFlown < 6 && _numYrsFlown >= 2 && _bonusEligibility) {
bonus = 515.00;
}
else if (_numYrsFlown < 2 && _bonusEligibility) {
bonus = 0.00;
}
return bonus;
}
public String toString() {
return "[" + _name + "][" + _numYrsFlown + "][" + _bonusEligibility + "][" + getBonusAmount() + "]";
}
}