Optimizing an algorithm [compile ready code] - java

Problem from game perspective (Poker)
The player has 2 green chips (5 points) and 1 blue (10 points). This totals 20 points. Now the player want to buy a ingame icon that costs 16 points. The player has enough money to buy the item. So the player pays 16 points, but what points will he give to the shop to pay correctly.
Now I've written a working example with all of the work done.
Code
Program.java
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
// Setting up test environment
Player player = new Player("Borrie", new int[]{0,0,0,0, 230});
int itemCost = 16626;
// Pay for item
System.out.printf("First we check if the player can pay with it's current ChipSet");
if (!player.canPayWithChipSet(player.getChips(), 5)) {
if (player.exchangeChips(5)) {
System.out.printf("\n\nThe players ChipSet:" + Arrays.toString(player.getChips().chips));
System.out.printf("\nThe players ChipSet has been succesfully exchanged.");
} else {
System.out.printf("\n\nThe players ChipSet:" + Arrays.toString(player.getChips().chips));
System.out.printf("\nThe players ChipSet was not able to be exchanged.\n");
}
} else {
System.out.printf("\n\nThe player can pay exact with it's original ChipSet. No need to exchange.");
}
}
}
Player.java
import java.util.ArrayList;
import java.util.Arrays;
public class Player {
private String name;
private ChipSet chips;
private int points = 0;
public Player(String name, int[] chips) {
this.name = name;
this.chips = new ChipSet(chips);
this.points = this.chips.getSum();
}
public boolean exchangeChips(int cost) {
ChipSet newChipSet = exchangePlayerChipSet(this.chips.getChips(), cost);
if (newChipSet == null) {
return false;
}
this.chips = newChipSet;
return true;
}
public ChipSet exchangePlayerChipSet(int[] originalChipValues, int cost) {
ChipSet newChipSet = null;
// Create possible combinations to compare
ArrayList<ChipSet> chipSetCombos = createCombinations(this.chips.getChips());
// Filter the chipset based on if it's able to pay without changing chips
System.out.printf("\n\n---- Filter which of these combinations are able to be payed with without changing chips ----");
ArrayList<ChipSet> filteredCombos = filterCombinations(chipSetCombos, cost);
// Compare the filtered chipsets to determine which one has changed the least
if (!filteredCombos.isEmpty()) {
newChipSet = compareChipSets(originalChipValues, filteredCombos);
}
return newChipSet;
}
private ArrayList<ChipSet> createCombinations(int[] array) {
ArrayList<ChipSet> combos = new ArrayList<>();
int[] startCombo = array;
System.out.printf("Player has " + getTotalPoints(startCombo) + " points in chips.");
System.out.printf("\nPlayer has these chips (WHITE,RED,GREEN,BLUE,BLACK): " + Arrays.toString(startCombo));
while (startCombo[4] != 0) {
startCombo = lowerBlack(startCombo);
if (getTotalPoints(startCombo) == points) {
combos.add(new ChipSet(startCombo));
}
}
while (startCombo[3] != 0) {
startCombo = lowerBlue(startCombo);
if (getTotalPoints(startCombo) == points) {
combos.add(new ChipSet(startCombo));
}
}
while (startCombo[2] != 0) {
startCombo = lowerGreen(startCombo);
if (getTotalPoints(startCombo) == points) {
combos.add(new ChipSet(startCombo));
}
}
while (startCombo[1] != 0) {
startCombo = lowerRed(startCombo);
if (getTotalPoints(startCombo) == points) {
combos.add(new ChipSet(startCombo));
}
}
System.out.printf("\n\n---- Creating variations on the players chips ----");
System.out.printf("\nVariation (all worth " + getTotalPoints(startCombo) + " points):\n");
int counter = 1;
for (ChipSet a : combos) {
System.out.printf("\nCombo " + counter + ": " + Arrays.toString(a.getChips()));
counter++;
}
return combos;
}
private ArrayList<ChipSet> filterCombinations(ArrayList<ChipSet> combinations, int cost) {
ArrayList<ChipSet> filteredChipSet = new ArrayList<>();
combinations.stream().filter((cs) -> (canPayWithChipSet(cs, cost))).forEach((cs) -> {
filteredChipSet.add(cs);
});
return filteredChipSet;
}
// This method has be worked out
public boolean canPayWithChipSet(ChipSet cs, int cost) {
ChipSet csOrig = new ChipSet(cs.chips);
ChipSet csCopy = new ChipSet(cs.chips);
int counterWhite = 0, counterRed = 0, counterGreen = 0, counterBlue = 0, counterBlack = 0;
while (20 <= cost && cost > 0 && csOrig.getChips()[4] != 0) {
csOrig.getChips()[4] -= 1;
cost -= 20;
counterBlack++;
}
while (10 <= cost && cost > 0 && csOrig.getChips()[3] != 0) {
csOrig.getChips()[3] -= 1;
cost -= 10;
counterBlue++;
}
while (5 <= cost && cost > 0 && csOrig.getChips()[2] != 0) {
csOrig.getChips()[2] -= 1;
cost -= 5;
counterGreen++;
}
while (2 <= cost && cost > 0 && csOrig.getChips()[1] != 0) {
csOrig.getChips()[1] -= 1;
cost -= 2;
counterRed++;
}
while (1 <= cost && cost > 0 && csOrig.getChips()[0] != 0) {
csOrig.getChips()[0] -= 1;
cost -= 1;
counterWhite++;
}
if (cost == 0){
System.out.printf("\nCombo: %s can pay exact. With %d white, %d red, %d green, %d blue an %d black chips", Arrays.toString(csCopy.chips),counterWhite,counterRed,counterGreen,counterBlue,counterBlack);
return true;
} else {
System.out.printf("\nCombo: %s cannot pay exact.\n\n\n", Arrays.toString(csCopy.chips));
return false;
}
}
private ChipSet compareChipSets(int[] originalChipValues, ArrayList<ChipSet> chipSetCombos) {
ChipSet newChipSet;
int[] chipSetWaardes = originalChipValues; // originele chipset aantal van kleur
int[] chipSetCombosDifferenceValues = new int[chipSetCombos.size()];
int counter = 1;
System.out.printf("\n\n---- Calculate differences between players stack and it's variations ----");
for (ChipSet cs : chipSetCombos) {
int amountWhite = cs.getChips()[0];
int amountRed = cs.getChips()[1];
int amountGreen = cs.getChips()[2];
int amountBlue = cs.getChips()[3];
int amountBlack = cs.getChips()[4];
int differenceWhite = Math.abs(chipSetWaardes[0] - amountWhite);
int differenceRed = Math.abs(chipSetWaardes[1] - amountRed);
int differenceGreen = Math.abs(chipSetWaardes[2] - amountGreen);
int differenceBlue = Math.abs(chipSetWaardes[3] - amountBlue);
int differenceBlack = Math.abs(chipSetWaardes[4] - amountBlack);
int totalDifference = differenceWhite + differenceRed + differenceGreen + differenceBlue + differenceBlack;
chipSetCombosDifferenceValues[counter - 1] = totalDifference;
System.out.printf("\nCombo " + counter + ": " + Arrays.toString(cs.getChips()) + " = " + totalDifference);
counter++;
}
newChipSet = chipSetCombos.get(smallestValueOfArrayIndex(chipSetCombosDifferenceValues));
System.out.printf("\n\nThe least different ChipSet is: " + Arrays.toString(newChipSet.getChips()) + " ");
return newChipSet;
}
private int smallestValueOfArrayIndex(int[] array) {
int currentValue = array[0];
int smallestIndex = 0;
for (int j = 1; j < array.length; j++) {
if (array[j] < currentValue) {
currentValue = array[j];
smallestIndex = j;
}
}
return smallestIndex;
}
private int[] lowerBlack(int[] array) {
return new int[]{array[0], array[1], array[2], array[3] + 2, array[4] - 1};
}
private int[] lowerBlue(int[] array) {
return new int[]{array[0], array[1], array[2] + 2, array[3] - 1, array[4]};
}
private int[] lowerGreen(int[] array) {
return new int[]{array[0] + 1, array[1] + 2, array[2] - 1, array[3], array[4]};
}
private int[] lowerRed(int[] array) {
return new int[]{array[0] + 2, array[1] - 1, array[2], array[3], array[4]};
}
private int getTotalPoints(int[] array) {
return ((array[0] * 1) + (array[1] * 2) + (array[2] * 5) + (array[3] * 10) + (array[4] * 20));
}
public String getName() {
return this.name;
}
public int getPoints() {
return this.points;
}
public ChipSet getChips() {
return chips;
}
}
ChipSet.java
public class ChipSet {
public static final int WHITE_VALUE = 1;
public static final int RED_VALUE = 2;
public static final int GREEN_VALUE = 5;
public static final int BLUE_VALUE = 10;
public static final int BLACK_VALUE = 20;
public static final int[] VALUES = new int[]{WHITE_VALUE, RED_VALUE, GREEN_VALUE, BLUE_VALUE, BLACK_VALUE};
protected int[] chips;
public ChipSet(int[] chips) {
if (chips == null || chips.length != 5) {
throw new IllegalArgumentException("ChipSets should contain exactly 5 integers!");
}
// store a copy of passed array
this.chips = new int[5];
for (int i = 0; i < this.chips.length; i++) {
this.chips[i] = chips[i];
}
}
public int getSum() {
return chips[0] * WHITE_VALUE
+ chips[1] * RED_VALUE
+ chips[2] * GREEN_VALUE
+ chips[3] * BLUE_VALUE
+ chips[4] * BLACK_VALUE;
}
public int[] getChips() {
return this.chips;
}
}
Some explanation:
Create combinations
We create some submethods the trade a chip in for it's lower chip. So
for example black = 2 blues. Then we create 5 loops in order. The
first ones checks if there are still black chips, if so reduce 1 black
add 2 blues. Save this new combination in a list if the sum of the
chips in the new ChipSet equals the original ChipSets value. Loop
continues until there are no blacks anymore. Then it check if there
are blues and repeats the same process until there are no reds
anymore. Now we have list with all possible variations of X value in
chips.
Filter combinations
You filter the ChipSets based on
if you can pay X points with them without exchanging. We loop over all
possible combinations of ChipSets created in the previous part. If you
can pay with the ChipSet without exchanging add it to the filteredList
of ChipSets. The result is a filered list with only valid ChipSets.
Calculate difference
For each ChipSet we count the number of chips of all colors in a
ChipSet and substract the original chipset number of chips with it.
You take the absolute value of that and make a sum of all those
differences of the original and the combos colors. Now we have a
number that represents the difference from the original. Now all we
have to do is compare all the ChipSets ´difference number´. The one
with the least difference we use to assign to the player.
So what it basically does is: It checks first if the current ChipSet can be used to pay and returns a boolean just like you asked. If it can it doesn't do anything, otherwise it goes through the 3 sub-algorithms and defines the best ChipSet (one to able to use to pay and least different one) and changes the players ChipSet the it
So now what is my question, how would I start to optimize this? I ask this because when there are bigger inputs the algorithm easily uses a few seconds.

Profile the application a few times to see which methods take the most time with accuracy. For example:
Try to optimize those methods which you know are the bottlenecks and reprofile until your bottlenecks are out.

Let me tell you how to find the problem(s). Here's what to do:
Get it running and hit "pause". Display the call stack. Click on each level, and it will show you a line of code where some method/function A calls some B, and the reason why is evident from the context. Put all those reasons together, and you understand completely why that point in time was being spent. Now ask yourself "Is there any way to avoid doing this, at least some of the time?" Now, don't act on that right away. Take a few more pauses and study each one the same way.
Now, if you saw such a thing you could avoid doing, and you saw it on more than just one sample, then you should fix it, and you will see a substantial speedup, guaranteed. Now comes the good news: If you do it all again, you will see that you've exposed something else, that can also give you a speedup. This continues until it stops, and then your code is about as nearly optimal as you can make it. Regarding the picture you posted, I've explained many many times why that does not work.
If you do this, you can find anything profilers can find, and plenty that they can't.
The reason is very simple - it comes down to describing things.
What is inclusive time percent of a function? It is the fraction of call stack samples containing that function.
What is self time percent of a function? It is the fraction of call stack samples containing that function at the end.
What is inclusive time percent of a line of code (as opposed to a function)? It is the fraction of call stack samples containing that line of code.
If you look at a call graph, what is the time percent of a link in the graph between functions A and B? It is the fraction of call stack samples in which A is directly calling B.
What is CPU time? It is the time you get if you ignore any samples taken during I/O, sleep, or any other such blocking?
So, if you are examining stack samples yourself, you can locate anything a profiler can locate, just by looking.
You can also locate things that the profiler cannot, such as:
Seeing that a large fraction of time is spent allocating memory for objects that a short time later are simply deleted.
Seeing that a function is being called multiple times with the same arguments, only because the programmer was too lazy to declare a variable to remember the prior result.
Seeing in a 20-level stack sample that a seemingly innocuous function was being called at the 10th level, that the programmer never imagined would be doing file I/O at the 20th level for some obscure reason that its writer couldn't rule out, but you know is not necessary.
Seeing that there are a dozen different functions all doing the same thing but they are different functions because their owner classes have been templated.
Seeing that there is a frequent pattern of function P calling something but then calling R, where P is called from lots of different places, and R calls down to lots of different places.
You can easily see any of these things, and more, just by examining the samples yourself.
Now, the average number of samples it takes to see them depends on how big they are.
If something takes 50% of time, the average number of samples needed to see it twice is 2/0.5 = 4 samples, so if you take 10 samples you are sure to see it.
Suppose there was another thing taking 25% of time.
Now after fixing the first problem and cutting the time in half, the second one takes 50%, not 25%, so it, too, is easy to find.
This is how fixing one speedup exposes the next one.
But as soon as you fail to find a speedup that's really there, the whole process stops, because you stop exposing the ones that are initially small but become really important when the bigger ones are removed.
Profilers give you precise measurements, but what are they measurements of?
(Actually, that precision is fake. All those measurements have standard errors, which you are not shown.)
What are they measurements of? Only very simple stuff, actually.
There's no way they can recognize the kind of stuff you can recognize, since you know the code.
I have had academic profiler fans insist to me that any problem you can find, you can find with a profiler, but that is not a theorem.
There is no justification for it at all, theoretical or practical.
There are plenty of problems that can escape from profilers.
It's a case of "out of sight - out of mind".
"Gee, I ran the profiler on my code, but I couldn't see any bottlenecks, so I guess there aren't any."
If you're serious about performance, you've got to do better than that.

Related

How to write a java program that computes the value of e^x

I'm trying to figure out how to answer this question for my Java class, using only while loops:
Write an application that computes the value of mathematical constant e^x by using the following formula. Allow the user to enter the number of terms to calculate. e^x = 1 + (x/1!) + (x^2/2!) + (x^3/3!) + ...
I can't figure out how I would do this without also asking the user for a value for x? Below is the code that I created for calculating x with the number of terms and just the number 1 for the exponent of each fraction. Any help is appreciated
import java.util.Scanner;
public class FactorialB {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int counter = 0;
float answer = 0;
System.out.print("Enter number of terms: ");
int n = scanner.nextInt();
while (counter < n) {
double factorial = 1;
int factCounter = counter;
while (factCounter > 1) {
factorial = factCounter * factorial;
factCounter--;
}
answer += 1 / factorial;
counter++;
}
System.out.printf("e = %f%n", answer);
}
}
Firstly the question you seem to be asking:
There is no way to make a program that will give e for a specific number unless you ask the user for that number.
However it might be that they just want you to make a method that provides the solution (if it were called) independently of user input. (because the code to get user input isn't very interesting, what is interesting is how you reach the result).
An alternative way to provide x and n are for instance passing them as commandline arguments. (args[] in your main would be a way to provide them)
I would create a separate method that receives x and n that covers the main calculation:
e^x = 1 + (x/1!) + (x^2/2!) + (x^3/3!) + ...
And separate methods that cover 'calculating a single term (x^1/1!), (x^2/2!), etc' and 'factorialize(n)'
public void calculatePartialE_term(int x, int n) {
if (n == 0) {
return 1; // this will allow you to use a while loop, covers the n = 0 case
} else {
// removed the implementation, but basically do
// x^n/n! here for whatever value of n this term is calculating.
}
}
public int calcualteNFactorial(int n) {
// assert n >= 1
// use a while loop to calculate n factorial
}
the benefit of doing this in a separate methods is that you can prove / verify the working of calculatePartialE_term or calcualteNFactorial independently of one another.
now you can simply write a while loop based on x and n to do something like
public int calculateE_to_x(int x, int n) {
int current = 0;
int sum = 0;
while (current <= n) {
sum += calculatePartialE_term(x, current);
}
}
I wouldn't expect your teacher to expect you to show code that handles user input but even if that is the case it will be easier for them to verify your work if the actual work (of calculating) is done in a separate method.

Belt Collision Time Calculation

Mr. Dis and Mr. Aster are mechanical engineers at Fiasco Iron Works.
They were assigned to design roadways for automated trolleys to carry
the iron ores across the smelting plants. They were supposed to make
two circular roadways for the automated trolleys. However, by mistake
Mr Dis and Mr Aster made the circular roadways tangential to each
other (i.e. the two circular paths touch each other at a point).
Every morning at 0800 hrs the trolleys start at the point of tangency
and move clockwise in their respective tracks. It is quite obvious
that at some point the trolleys would collide at the point from where
they started. In a desperate attempt to save the trolleys and the
damage caused to the operations of the plant, the Chief Engineer of
the plant has requested you to write a program that will sound a
hooter 10 seconds before the collision such that the foreman can stop
the trolleys in order to avoid the collision. Write a program to
find out the time lapsed (in seconds) before the hooter should go off.
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int greater,smaller;
int result = 0;
if(perimeter1 > perimeter2) {
greater = perimeter1;
smaller = perimeter2;
} else {
greater = perimeter2;
smaller = perimeter1;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result/speed1-10;
}
Here, I am trying to calculate the distance before collision which is basically am LCM operation and then division by speed. But this is failing for some of the cases.Please help me understand why.
The belt having greater perimeter is considered for calculating the distance it covers before collision. So the speed can not be chosen arbitrarily, it should be of the belt having greater perimeter.
Changes
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int greater,smaller;
int speed, result = 0;
if(perimeter1 > perimeter2) {
greater = perimeter1;
smaller = perimeter2;
speed = speed1;
} else {
greater = perimeter2;
smaller = perimeter1;
speed = speed2;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result/speed-10;
}
Another alternative approach, calculate the LCM of time taken by both belts which would be the time of collision.
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int timeForTrolley1 = perimeter1/speed1,timeForTrolley2 = perimeter2/speed2;
int greater,smaller;
int result = 0;
if(timeForTrolley1 > timeForTrolley2) {
greater = timeForTrolley1;
smaller = timeForTrolley2;
} else {
greater = timeForTrolley2;
smaller = timeForTrolley1;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result-10;
}

Possible uneven distribution in Java's Random class or bad implementation?

I'm tinkering around with a cellular automaton and my movement detection function is acting really strangely. I'm 80% sure it's my implementation but I have no idea where the issue is. Could someone take a look and enlighten me since I've spent the better part of 7H trying to get it to work and it won't:
private int[] cellularSearch(short xPos, short yPos)
{
// the center position is our current position; the others are potentially free positions
byte[][] positions = new byte[][]{{0,0,0},{0,1,0},{0,0,0}};
int[] result = new int[2];
byte strike=0;
int dice0=0, dice1=0;
while(strike<9)
{
dice0 = r.nextInt(3)-1;
result[0] = xPos + dice0;
if((result[0] >= 0)
&& (result[0] < img.getWidth()))
{
dice1 = r.nextInt(3)-1;
result[1] = yPos + dice1;
if((result[1] >= 0)
&& (result[1] < img.getHeight()))
{
if((positions[dice1+1][dice0+1] != 1)) // if this isn't our own cell and wasn't tried before
{
if(img.getRGB(result[0], result[1]) == Color.white.getRGB()) // if the new cell is free
{
return result;
}
}
positions[dice1+1][dice0+1]=1; // we need to use +1 to create a correlation between the linkage in the matrix and the actual positions around our cell
strike++;
}
}
}
}
The code works and it correctly identifies when a pixel is white and returns the position for it. My problem is the distribution of the results. Given that I'm using Random both for the row and the column, I was expecting a near equal distribution over all possible locations, but what happens is that this code seems to prefer the cell right above the coordinates being fed in (it hits it ~3x as much as the other ones) and the one right below the coordinates (it hits it ~2x as much as the others).
When I start my program and all my pixels slowly move towards the top of the window on EVERY run (vs true randomness with my old lengthy code which was 3x as long), so there's gotta be an error in there somewhere. Could someone please lend a hand?
Thank you in advance!
EDIT: Thank you everyone for the effort! Sorry for the non-compiling code but I extracted the main purpose of the function while cutting out a ton of commented code (my other approaches to implementing this function). Locally the code has the return statement and it runs. I'll slowly go through all your answers in the next few hours (gonna have dinner soon).
EDIT2: I tried what #DodgyCodeException and #tevemadar suggested and made a list with all the 8 positions, then shuffle them each time I enter the function, and then iterate through them, trying each one in part. Still the position exactly above and below the current cell are selected most. I'm baffled. This is my old super-spaghetti code that I've written for this function and it worked perfectly with no errors, equal distribution, and (oddly enough) it's the most efficient implementation that I've tried out of everything mentioned here. After I'm done with lunch and filing some paperwork I'll thoroughly study it (it's been ~ 2 years since I wrote it) to see why it works so well. If anyone still has ideas, I'm fully open.
boolean allRan=false;
int lastDice=0, anteLastDice=0, dice = r.nextInt(3)+1;
//the initial dice usage is for selecting the row on which we'll operate:
//dice = 1 or 3 -> we operate above or under our current cell; dice = 2 -> we operate on the same row
while(!allRan)
{
if((dice==1) || (dice==3))
{
int i= r.nextInt(3);
if(((xPos-1+i) < img.getWidth())
&& ((xPos-1+i) >= 0))
{
if(((yPos-1) >= 0)
&& (img.getRGB(xPos-1+i, yPos-1) == Color.white.getRGB())
&& (dice==1))
{
result[0] = xPos-1+i;
result[1] = yPos-1;
above++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
else if(((yPos+1) < img.getHeight())
&& (img.getRGB(xPos-1+i, yPos+1) == Color.white.getRGB())
&& (dice==3))
{
result[0] = xPos-1+i;
result[1] = yPos+1;
below++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
}
// if this section is reached, it means that: the initial dice roll didn't find a free cell, or the position was out of bounds, or the dice rolled 2
// in this section we do a dice reroll (while remembering and avoiding our previous values) so that we cover all dice rolls
if(dice==1)
{
if(lastDice==0)
{
lastDice=dice;
dice += r.nextInt(2)+1; // we incrmeent randomly towards 2 or 3.
}
else
{
if(lastDice==2)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=3;
}
else
{
allRan=true;
}
}
else if(lastDice==3)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=2;
}
else
{
allRan=true;
}
}
}
}
else // dice is 3
{
if(lastDice==0)
{
lastDice=dice;
dice -= r.nextInt(2)+1; // we decrement randomly towards 2 or 1.
}
else
{
if(lastDice==2)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=1;
}
else
{
allRan=true;
}
}
else if(lastDice==1)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice=2;
}
else
{
allRan=true;
}
}
}
}
}
if(dice==2)
{
int i=0;
i += r.nextInt(2)==0?-1:1;
if(((xPos+i) < img.getWidth())
&& ((xPos+i) >= 0)
&& (img.getRGB(xPos+i, yPos) == Color.white.getRGB()))
{
result[0] = xPos+i;
result[1] = yPos;
leveled++;
endTime = (int) System.currentTimeMillis();
section4Runtime += (double) (endTime - startTime) / 1000;
return result;
}
// same as above: a dice reroll (with constrictions)
if(lastDice==0)
{
lastDice=dice;
dice+= r.nextInt(2)==0?-1:1; // randomly chose if you decrement by 1 or increment by 1
}
else
{
if(lastDice==1)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice =3;
}
else
{
allRan=true;
}
}
else if(lastDice==3)
{
if(anteLastDice==0)
{
anteLastDice= lastDice;
lastDice=dice;
dice =1;
}
else
{
allRan=true;
}
}
}
}
}
return result;
After much thought, I eventually figured it out. All the ideas that we all had were violating a fundamental "rule" of the first implementation that I was using: the first implementation was trying a random position on one of the 3 lines, then moving on to the next lines (without coming back to try the other positions on that line). Example: if the algo selected the line above, it would randomly try the top-left corner to see if it's free; if it wasn't then it would try the same line as the current cell and the line below (again, just with 1 of their possible positions) without coming back. All our ideas were iterating through all possibilities around the cell, which meant that it was inevitable to have the top and bottom line have more hits than the middle (since top and bottom have 3 possible points each while middle has only 2). Also, when there were holes in the field, the cells most likely to fill it up were the ones that were moving diagonally (which in the end is up or down) or those directly moving up or down, since those moving sideways only had the options left/ right. The only mystery that will remain unsolved is why (using our proposed implementations) the model would generally use the point exactly above our current cell. I have no idea why it loves going straight up most of the time with that implementation. Nevertheless, the new algorithm (which reflects the old one, but is much lighter) is:
boolean[] lines = new boolean[]{false, false, false};
byte checks =0;
while(checks < 3) // just 3 tries in total
{
dice = r.nextInt(3);
if(lines[dice]== false)
{
lines[dice] = true; // just 1 try per line
// calculated here since we reuse dice below
result[1] = yPos - 1 + dice; // will be above if dice==0; will be below if dice==2; same line if dice==1
if((dice == 0) || (dice == 2)) // top/bottom line
{dice = r.nextInt(3)-1;}
else if(dice == 1) // middle line
{dice = r.nextInt(2)==0?-1:1;} // we exclude the middle point since that's our current position
result[0] = xPos + dice; // logic is calculated above and just applied here
checks++;
}
if((result[0] >= 0)
&& (result[0] < img.getWidth())
&& (result[1] >= 0)
&& (result[1] < img.getHeight()))
{
if (img.getRGB(result[0], result[1]) == Color.white.getRGB()) // if the new cell is free
{
return result;
}
}
}
result[0] = -1; // in case we get here, reset the value so it's not used
This brings the code down from 167 lines to 33 lines (and makes it MUCH more readable). I have no idea who to select as the best solution. Please suggest if you have any ideas.
First, I have to admit I can't see what your algorithm is supposed to be doing -- it's not clear to me why you roll the each die when you do, other times using the existing value.
For a clear, easy to follow algorithm, I'd suggest scoping your dice variables inside the loop, rolling both at the same time, and making them final so that you know that each iteration has exactly one two-die roll:
while(strike < 9) {
final int roll1 = r.nextInt(3) - 1;
final int roll2 = r.nextInt(3) - 1;
strike += handleRoll(roll1,roll2);
}
You can prove the distribution to yourself by writing a simple counter for your handleRoll(), before later substituting your real code.
int[] counts = int[6];
void handleRoll(int roll1, int roll2) {
counts[1 + roll1] ++;
counts[4 + roll2] ++;
return 1;
}
(Increase the required strike count to get large enough samples to reason about)
Make sure you use the same instance of Random throughout the program -- don't keep making new ones.
(You could tidy this up a bit by creating a Coordinate class and a factory that creates random ones)
I simplified your code like this:
made a series of extract-method refactorings to tidy away detail
changed your rolls to use the range 0 to 2 instead of -1 to +1 -- since you use them in two places, and in one of those you add one again!
used x and y and only create result when needed
used final for the rolls and the resulting x and y, scoping them to the inside of the loop
turned nested ifs into an && logic
changed some odd type choices. The positions grid seems made for boolean. There's seldom any value in using short in Java.
So:
private int[] cellularSearch(int xPos, int yPos) {
boolean[][] positions =
new boolean[][] { { false, false, false },
{ false, true, false },
{ false, false, false } };
int strike = 0;
while (strike < 9) {
final int dice0 = r.nextInt(3);
final int dice1 = r.nextInt(3);
final int x = xPos + dice0 - 1;
final int y = yPos + dice1 - 1;
if (isInXrange(x) && isInYRange(y)) {
if (!alreadyTried(positions, dice1, dice0) && isWhite(x, y)) {
return new int[] { x, y };
}
markAsTried(positions, dice1, dice0);
strike++;
}
}
return null; // or whatever you intend to happen here
}
private boolean isInXrange(int x) {
return (x >= 0) && (x < img.getWidth());
}
private boolean isInYRange(int y) {
return (y >= 0) && (y < img.getHeight());
}
private boolean alreadyTried(boolean[][] positions, final int dice1, final int dice0) {
return positions[dice1 + 1][dice0 + 1];
}
private static void markAsTried(boolean[][] positions, int dice1, int dice0) {
positions[dice1][dice0] = true;
}
private boolean isWhite(final int x, final int y) {
return img.getRGB(x, y) == Color.white.getRGB();
}
I think this is equivalent to your code, with one exception -- yours doesn't roll the second die if the first roll takes you outside the width of the image. You could re-add this as a performance improvement later if you like.
But it exposes some issues. It looks as if the intent is to try every cell (you have a 3x3 grid, and you've chosen 9 "strikes") - but it doesn't increment strike when x,y is outside the image. It does increment strike when the position has been tried before. So you can exit the loop having not tried every cell.
I don't see a specific way that this causes the weighting you've described --
but it looks like the sort of thing that could lead to unexpected results.
(Anyway - since the code you've given doesn't compile, you didn't observe it with the code you've given us)
If the intention is to check every cell, it might be better to shuffle a list of cells to try, then test them in order:
List<Coords> coordsToTry = new ArrayList<>();
for(int x=0; x<2; x++) {
for(int y=0; y<2; y++) {
coordsToTry.add(new Coords( x, y));
}
}
Collections.shuffle(coordsToTry);
for(Coords coords : coordsToTry) {
if(isWhite(coords)) {
return coords;
}
}
return null; // or whatever is meant to happen when nothing found
The distribution of java.util.Random is not that uneven. You can confirm with the following code:
public static void main(String[] args) throws Exception {
final int N = 3;
Random r = new Random();
int[] counts = new int[N];
for (int i = 0; i <= 100_000; i++) {
counts[r.nextInt(N)]++;
}
System.out.println(Arrays.toString(counts));
}
UPDATE:
As you've said, the above code produces fairly evenly distributed values. However, add the following line at the beginning of the loop:
if (i % 6 == 0)
r = new Random(0);
And then you get [16667, 33334, 50000]. One value occurs twice as frequently, and another 3 times as frequently, as the first. This sets the random number generator to a newly created one with a constant seed. It simulates your code, in which you say you create a new Random() on entry to your function (albeit without a seed argument) and then your function calls nextInt() six times - this if (i % 6 == 0) statement ensures a new RNG is also created every 6 iterations.
Check your code and make sure you are only ever creating a RNG once in your whole program.
java.util.Random is a pseudorandom number generator (definition on wikipedia) and needs to be seeded.
From the docs:
If two instances of Random are created with the same seed, and the same sequence of method calls is made for each, they will generate and return identical sequences of numbers. In order to guarantee this property, particular algorithms are specified for the class Random.
If you want to be sure to get good random numbers, use SecureRandom, which is guaranteed to produce non-deterministic output
Since you are interested in the combined distribution of the two 'dices', on top of #DodgyCodeException's suggestion, you can check statistics like
public static void main(String[] args) {
Random r=new Random();
int stat[]=new int[9];
for(int i=0;i<9000;i++)
stat[r.nextInt(3)+r.nextInt(3)*3]++;
for (int i : stat)
System.out.println(i);
}
However it is pretty even too.
There is a minor difference between generating random numbers from a power-of-two-range and otherwise, so if you really want to do some magic, you can use the fact that you are actually picking a position out of 8 possibilities (since the middle one is ruled out at the beginning).
Something like
final int xhelper[]=new int[]{-1, 0, 1,-1, 1,-1, 0, 1};
final int yhelper[]=new int[]{-1,-1,-1, 0, 0, 1, 1, 1};
...
int dir=r.nextInt(8);
int dice0=xhelper[dir];
int dice1=yhelper[dir];
But in fact I do not think it makes a difference.

In Java finding numbers that are both a Triangle Number and a Star Number

This is the question I've been assigned:
A so-called “star number”, s, is a number defined by the formula:
s = 6n(n-1) + 1
where n is the index of the star number.
Thus the first six (i.e. for n = 1, 2, 3, 4, 5 and 6) star numbers are: 1, 13, 37,
73, 121, 181
In contrast a so-called “triangle number”, t, is the sum of the numbers from 1 to n: t = 1 + 2 + … + (n-1) + n.
Thus the first six (i.e. for n = 1, 2, 3, 4, 5 and 6) triangle numbers are: 1, 3, 6, 10, 15, 21
Write a Java application that produces a list of all the values of type int that are both star number and triangle numbers.
When solving this problem you MUST write and use at least one function (such as isTriangeNumber() or isStarNumber()
or determineTriangeNumber() or determineStarNumber()). Also you MUST only use the formulas provided here to solve the problem.
tl;dr: Need to output values that are both Star Numbers and Triangle Numbers.
Unfortunately, I can only get the result to output the value '1' in an endless loop, even though I am incrementing by 1 in the while loop.
public class TriangularStars {
public static void main(String[] args) {
int n=1;
int starNumber = starNumber(n);
int triangleNumber = triangleNumber(n);
while ((starNumber<Integer.MAX_VALUE)&&(n<=Integer.MAX_VALUE))
{
if ((starNumber==triangleNumber)&& (starNumber<Integer.MAX_VALUE))
{
System.out.println(starNumber);
}
n++;
}
}
public static int starNumber( int n)
{
int starNumber;
starNumber= (((6*n)*(n-1))+1);
return starNumber;
}
public static int triangleNumber( int n)
{
int triangleNumber;
triangleNumber =+ n;
return triangleNumber;
}
}
Here's a skeleton. Finish the rest yourself:
Questions to ask yourself:
How do I make a Triangle number?
How do I know if something is a Star number?
Why do I only need to proceed until triangle is negative? How can triangle ever be negative?
Good luck!
public class TriangularStars {
private static final double ERROR = 1e-7;
public static void main(String args[]) {
int triangle = 0;
for (int i = 0; triangle >= 0; i++) {
triangle = determineTriangleNumber(i, triangle);
if (isStarNumber(triangle)) {
System.out.println(triangle);
}
}
}
public static boolean isStarNumber(int possibleStar) {
double test = (possibleStar - 1) / 6.;
int reduce = (int) (test + ERROR);
if (Math.abs(test - reduce) > ERROR)
return false;
int sqrt = (int) (Math.sqrt(reduce) + ERROR);
return reduce == sqrt * (sqrt + 1);
}
public static int determineTriangleNumber(int i, int previous) {
return previous + i;
}
}
Output:
1
253
49141
9533161
1849384153
You need to add new calls to starNumber() and triangleNumber() inside the loop. You get the initial values but never re-call them with the updated n values.
As a first cut, I would put those calls immediatly following the n++, so
n++;
starNumber = starNumber(n);
triangleNumber = triangleNumber(n);
}
}
The question here is that "N" neednt be the same for both star and triangle numbers. So you can increase "n" when computing both star and triangle numbers, rather keep on increasing the triangle number as long as its less the current star number. Essentially you need to maintain two variable "n" and "m".
The first problem is that you only call the starNumber() method once, outside the loop. (And the same with triangleNumber().)
A secondary problem is that unless Integer.MAX_VALUE is a star number, your loop will run forever. The reason being that Java numerical operations overflow silently, so if your next star number would be bigger than Integer.MAX_VALUE, the result would just wrap around. You need to use longs to detect if a number is bigger than Integer.MAX_VALUE.
The third problem is that even if you put all the calls into the loop, it would only display star number/triangle number pairs that share the same n value. You need to have two indices in parallel, one for star number and another for triangle numbers and increment one or the other depending on which function returns the smaller number. So something along these lines:
while( starNumber and triangleNumber are both less than or equal to Integer.MAX_VALUE) {
while( starNumber < triangleNumber ) {
generate next starnumber;
}
while( triangleNumber < starNumber ) {
generate next triangle number;
}
if( starNumber == triangleNumber ) {
we've found a matching pair
}
}
And the fourth problem is that your triangleNumber() method is wrong, I wonder how it even compiles.
I think your methodology is flawed. You won't be able to directly make a method of isStarNumber(n) without, inside that method, testing every possible star number. I would take a slightly different approach: pre-computation.
first, find all the triangle numbers:
List<Integer> tris = new ArrayList<Integer>();
for(int i = 2, t = 1; t > 0; i++) { // loop ends after integer overflow
tris.add(t);
t += i; // compute the next triangle value
}
we can do the same for star numbers:
consider the following -
star(n) = 6*n*(n-1) + 1 = 6n^2 - 6n + 1
therefore, by extension
star(n + 1) = 6*(n+1)*n + 1 = 6n^2 + 6n +1
and, star(n + 1) - star(n - 1), with some algebra, is 12n
star(n+1) = star(n) + 12* n
This leads us to the following formula
List<Integer> stars = new ArrayList<Integer>();
for(int i = 1, s = 1; s > 0; i++) {
stars.add(s);
s += (12 * i);
}
The real question is... do we really need to search every number? The answer is no! We only need to search numbers that are actually one or the other. So we could easily use the numbers in the stars (18k of them) and find the ones of those that are also tris!
for(Integer star : stars) {
if(tris.contains(star))
System.out.println("Awesome! " + star + " is both star and tri!");
}
I hope this makes sense to you. For your own sake, don't blindly move these snippets into your code. Instead, learn why it does what it does, ask questions where you're not sure. (Hopefully this isn't due in two hours!)
And good luck with this assignment.
Here's something awesome that will return the first 4 but not the last one. I don't know why the last won't come out. Have fun with this :
class StarAndTri2 {
public static void main(String...args) {
final double q2 = Math.sqrt(2);
out(1);
int a = 1;
for(int i = 1; a > 0; i++) {
a += (12 * i);
if(x((int)(Math.sqrt(a)*q2))==a)out(a);
}
}
static int x(int q) { return (q*(q+1))/2; }
static void out(int i) {System.out.println("found: " + i);}
}

How to test percentage in an if statement?

How can I test the percentage in an if statement?
For example:
package Walker;
public class Walker {
int tuning = 10;
int speed = 0;
int gas = 100;
int energy = 100;
int time = 1;
int strecke = 0;
boolean test = true;
boolean beschleunigung = false;
Walker() {
tuning = 10;
gas = 0;
energy = 100;
}
public void setGas(int x) {
gas = x;
}
public void setSpeed(int x) {
tuning = x;
}
public void walk() {
boolean walking = true;
while (walking) {
if (speed<10) {
beschleunigung = true;
}else {
beschleunigung = false;
}
if (beschleunigung==true) {
speed +=1+(tuning);
energy -=1;
}
strecke = (speed*time);
speed = (strecke/time);
gas -= 1;
energy -= 1;
time +=1;
if (gas<1||energy<1){
break;
}
}
System.out.println("Distance "+(strecke)+" meter");
System.out.println("Gas left :"+gas);
System.out.println("Energy left : "+energy);
}
}
The _User is able to change the value "tuning" and "gas"
And thats the part i like to add :
if (strecke==33%) {
system.out.println("Test");
}
Could anyone help me?
There is no percentage operator in Java (it is used as the Modulo operator - the amount left over after a division) so you have to calculate the percentage yourself.
Unfortunately, from your code, I cannot work out what gas should be compared to in order to determine if it's 33% the way there.
Change this:
if (gas==33%)
to:
if (gas==0.33)
(assuming gas is a float/double)
edit: Why am I getting downvoted? 33% is mathematically equivalent to 0.33.
edit: You might also want to do a ranged check like
if (gas > 0.325 && gas < 0.335)
Because just checking for the exact value of 33% is probably not what you wanted.
Create a helper method
private double percentage(double value)
{
return 100 * value;
}
and use it to wrap gas:
if (percentage(gas) == 33)
{
...
}
You're missing an important piece of input here. 33% of what? Some people here have suggested that it's 33% of one, as in 0.33. That's quite unlikely, since you're doing --gas at the end, so you're probably working with integer numbers.
I deduce you intend to say '33% of the initial volume'. So that would become:
public void walk() {
boolean walking = true;
int currentGas = initialGas;
while (walking) {
if (currentGas == Math.round((double)initialGas * 0.33)) {
System.out.println("Walker reached at 33% of Gas "+(output*speed)+" meter");
}
if (currentGas <0||energy<0) {
System.out.println("Run out of Gas or Energy!");
walking = false;
break;
}
--currentGas ;
output +=1; }
System.out.println("Distance "+(output*speed)+" meter");
}
That should do it.
You're not using % correctly. In Java the % operator is used to find a remainder. For example the following are true:
0 == 6 % 3 (because 6 divided by 3 has no remainder)
1 == 7 % 3 (because 7 divided by 3 has a remainder of 1)
If you want to convert gas to a percentage then you should probably be dividing it by something. For example:
if (gas / fulltank == 0.33)
However, you also need to realize that it may never exactly equal .33. So you probably want to check to see if it's <= .33. If so, then print the message and set a boolean variable to remember that you already printed it.
Also note that if gas is an integer type then you need to first convert it to a float:
if ((float)gas / fulltank == 0.33)
You don't need a percentage in this particular case, just use plain a plain int. Initialize gas at 100 and then substract one at each iteration of the loop. Replace the code that says "if(gas==33%)" for "if(gas==33)" and that's it.

Categories