I am attempting to create a probability generator based on the game of Craps to see the various probabilities.
My CrapsGame program seems to not work when doing probability of winning based off on my logical statements and frankly, I do not know what exactly is the problem as the Console does not mention any when ran.
public class CrapsGame
{
private int point = 0;
/**
* Calculates the result of the next dice roll in the Craps game.
* The parameter total is the sum of dots on two dice.
* point is set to the saved total, if the game continues,
* or 0, if the game has ended.
* Returns 1 if player won, -1 if player lost,
* 0 if player continues rolling.
*/
public int processRoll(int total)
{
int result = 0;
if (point == 0){
if (total == 7 || total == 11){
result = 1;
}else if (total == 2 || total == 3 || total == 12){
result = -1;
}else{
point = total;
result = 0;
}
}else{
if (total == point){
point = 0;
result = 1;
}else if (total == 7){
point = 0;
result = -1;
}else{
result = 0;
}
}
return result;
}
When I attempt to run the program only returns a 0% win rate, no matter the amount of games.
If I append
public static void main(String[] args) {
System.err.println(new CrapsGame().processRoll(7));
}
}
then it prints
1
So clearly the problem is not (entirely) within the code presented.
Edit: Or are you referring to point?
CrapsGame game = new CrapsGame();
game.processRoll(4);
System.err.println(game.point);
Gives:
4
I'm not sure where JFrame comes into this or the eclipse tag.
So I posted my question earlier and thought I was all good, but I messed up and realized I had understood the question completely wrong.
I do not need to calculate the average of snake eyes over 1000 dice rolls, but the average of number of rolls to get a snake eyes, over a 1000 play.
I am a little lost in how to accomplish that.
I tried this:
public class RollDiceforloop {
public static void main(String[] args) {
int die1, die2, snakeye, rolls, game;
snakeye = 0;
die1 = 0;
die2 = 0;
rolls = 0;
for (game = 0; game < 1000; game++) {
die1 = (int)(Math.random()*6)+1;
die2 = (int)(Math.random()*6)+1;
if (die1 != 1 && die2 != 1); {
rolls +=1;
}
if (die1 == 1 && die2 == 1) {
snakeye +=1;
rolls +=1;
}
}
float average = snakeye / (float) rolls;
TextIO.putln(""+snakeye+" Snake Eyes over "+game+" games, with an average of "+average+" rolls required to get a Snake Eye.");
}
}
But I am not getting the correct result. I am a bit lost on how to accomplish this. Help please?
A way to simply calculate the number of throws it took you to get a Snakeeyes would be the following:
int count = 0;
for (int i = 0; i < 1000; ++i)
{
int result = 0;
while (result != 2)
{
result = (int) (Math.random() * 6) + (int) (Math.random() * 6) + 2;
++count;
}
}
System.out.println(count / 1000.d);
Running should get you a result of round about 36, which is basically the expected value as you have a chance of 1/36 on each throw to get a Snakeeyes, so in theory on the long run you will get one every 36 throws.
However, this is kinda skewed math. Does this tell you that after 37 throws without a Snakeeyes your die are inbalanced? Or that if you get a Snakeeyes after 2 rolls you are cheating somehow?
No, obviously not.
This is where math comes into the equation. Let me say this first, there is no way to calculate the exact number of throws it's going to take you to get a Snakeeyes. What we can do is calculate a probability based on a confidence.
A confidence here is basically saying:
I want a chance of x% to get a snakeeyes.
x is the confidence. With the confidence you can use the simple formula of
1 - (35 / 36) ^ n > x and solve this for n to get a number of throws that with the given confidence will give you one or more snakeeyes. Note that 35/36 is the chance to not get a snakeyes but anything else.
So let's say we really really want that snakeeyes. We take a confidence of 99.9%.
With the formula this gets us n = 246. So we need 246 throws to get a 99.9% chance of at least one snakeeyes.
How about us gambling a bit more. We say that we are fine with just a 50% chance of getting a snakeyes. So with that we get n = 25.
Which is actually below our calculated value.
So what am I trying to say with that? You can obviously do an experiment with a big enough number of tries and in the end you will always get to the expected value of the throw (this is actually called the "Law of large numbers"). This however holds no value in determining how many throws you actually need to get a snakeeyes. It's just calculating the expected value. Which is something that doesn't really need an experiment for die.
So the method
return 36;
would actually be good enough here.
You got your logic a bit wrong. You need to do N amount of test(games) and every test has to wait until a snakeeye appears and count the necessary rolls. You could say you need to wait while no snakeeye appeared. To calculate the average you need to store the result of every test.
Example:
public static void main( String[] args )
{
int dice1;
int dice2;
// The amount of tests
final int SIZE = 10000000;
// store all results we got from a single test
int[] result = new int[SIZE];
// loop through the tests
for(int i = 0; i < SIZE;i++)
{
// initialize counter for every test
int rolls = 0;
do
{
// roll counter increases
rolls++;
dice1 = (int)(Math.random()*6)+1;
dice2 = (int)(Math.random()*6)+1;
// check if condition is met.
}while(dice1 != 1 || dice2 != 1);
// store the result of the test
result[i] = rolls;
}
// calculate the average amount of rolls necessary
double avg = Arrays.stream( result ).sum() / (double)SIZE;
System.out.println( avg );
}
Now my rolls required doesn't even compute.
public class RollDiceforloop3 {
public static void main(String[] args) {
int die1, die2, game, rolls;
rolls = 0;
for (game = 0; game < 1000; game++)
{
die1 = 0;
die2 = 0;
while (die1 != 1 || die2 != 1)
{
die1 = (int)(Math.random()*6)+1;
die2 = (int)(Math.random()*6)+1;
rolls +=1;
}
}
double average = rolls / (double) game;
TextIO.putln("The average number of rools required to get Snake Eyes is "+average+", after running the program 1000 times.");
}
}
If understood your code, I think you may wanna start counting over when achieved the snake eye, and increase the number of rolls otherwise. Also you probably want to increase the counter when only one of the rolls is equal to one. This two things may be polluting your result.
if (die1 == 1 && die2 == 1) {
snakeye ++;
rolls = 0;
} else {
rolls ++;
}
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.
Supposed I want to create a game. At the start of the game, the player will pick a monster.
It's easy to picks the monster fairly.
// get all monsters with equal chance
public Monster getMonsterFair(){
Monster[] monsters = {new GoldMonster(), new SilverMonster(), new BronzeMonster()};
int winIndex = random.nextInt(monsters.length);
return monsters[winIndex];
}
And picks the monster unfairly.
// get monsters with unequal chance
public Monster getMonsterUnFair(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to winthe silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 70% to win the bronze one
else {
return new BronzeMonster();
}
}
The problem is that, when I add a new monster to the game, I have to edit the if-else.
Or I change the chance of winning GoldMonster to 0.2, I have to change all 0.1 into 0.2
.It's ugly, and not easily maintained.
// get monsters with unequal change & special monster
public Monster getMonsterSpecial(){
double r = Math.random();
// about 10% to win the gold one
if (r < 0.1){
return new GoldMonster();
}
// about 30% to win the silver one
else if ( r < 0.1 + 0.2){
return new SilverMonster();
}
// about 50% to win the special one
else if ( r < 0.1 + 0.2 + 0.2){
return new SpecialMonster();
}
// about 50% to win the bronze one
else {
return new BronzeMonster();
}
}
How can this probability algorithm can be refactored so that the codes can be maintained easily when new monster is added and the chances of winning monsters are adjusted?
Basically what #Egor Skriptunoff said. This should scale easily. You could use a collection of Class<Monster> if you didn't want to use an enum.
enum Monster {
GOLD(1),
SILVER(3),
BRONZE(6) // pseudo probabilities
private int weight;
// constructor etc..
}
public Monster getMonsterSpecial() {
List<Monster> monsters = new ArrayList<>();
for(Monster monsterType : Monster.values()) {
monsters.addAll(Collections.nCopies(monsterType.getWeight(), monsterType));
}
int winIndex = random.nextInt(monsters.length);
return monsters.get(winIndex);
}
You could perhaps make the enum Monsters plural, and have it point to a Class<? extends Monster> if you still want to instantiate monster classes. I just tried to make the example clearer.
I would uses a total weight which increases with each monster added.
private final Random rand = new Random();
public Monster getMonsterSpecial() {
int weight = rand.nextInt(1+2+2+5);
if ((weight -= 1) < 0) return new GoldMonster();
if ((weight -= 2) < 0) return new SilverMonster();
if ((weight -= 2) < 0) return new SpecialMonster();
// 50% chance of bronze
return new BronzeMonster();
}
This is based off of Peter's answer, just more maintainable. All you have to do is add a new monster to the array and add the weight to the total weight - this can easily be extended to happen during runtime if you wish (thus, never mind making code changes, you don't even need to restart the program to add a monster (assuming the rest of your program allows this)).
Monster class:
Have an int weight variable for each monster.
If the weights are 1,2 and 7, the respective probabilities will be 10%, 20% and 70% (calculated as 100*x/(1+2+7)).
Globals:
Random rand = new Random();
int totalMonsterWeight;
Monster[] monsters; // set this up somewhere
Global weight initialization:
totalMonsterWeight = 0;
for (Monster monster: monsters)
totalMonsterWeight += monster.getWeight();
Get-monster function:
public Monster getMonster()
{
int weight = rand.nextInt(totalMonsterWeight);
for (Monster monster: monsters)
if ((weight -= monster.getWeight()) < 0)
return monster.getClass().newInstance();
}
The above is a lazy way (probably not the best way) to return a new instance during each call. The right way is probably using a Factory pattern.
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.