this is part of my program. I have to be sure that the amount of gas does not exceed the top gas capacity. I do not know how to write the else part? I ask the user to enter the current gas and it should be less or equal 30.
private final int GAS_CAP = 30
public int getGasCapacity(int gasCapacity)
{
if(currentGas <= GAS_CAP)
{
gasCapacity = GAS_CAP - currentGas;
}
else gasCapacity = currentGas;
return gasCapacity;
}
private final int GAS_CAP = 30
public int getGasCapacity()
{
int gasCapacity;
if(currentGas <= GAS_CAP)
{
gasCapacity = GAS_CAP - currentGas;
} else {
gasCapacity = 0;
}
return gasCapacity;
}
Your else statement was wrong, and there shouldn't be a parameter.
You could also easily accomplish this with one line, but I'm not sure if you know how to use ternary syntax.
Can made in one line as,
public int getGasCapacity(){
return (currentGas <= GAS_CAP ? (GAS_CAP - currentGas) : 0 );
}
First thing, you should make your question a little more clear because I don't really understand what you're trying to do. I'm going to write you what I think you're trying to achieve and you tell me if it's okay or comment what was wrong in the answer.
private final GAZ_LIMIT = 30;
public int ObserveGazCapacity(int gazCapacity)
{
if(gazCapacity<=GAZ_LIMIT)
{
gazCapacity-=GAZ_LIMIT;
}else{
gazCapacity=0; //in case higher than limit, capacity will be at the maximum value permitted
}
return gazCapacity;
}
Hopes that what you're looking for !
Related
I am making a number guessing game:
The computer generates a number inside an interval
I try to guess it and receive a reply whether it's higher/lower than my guess or equals to my guess and I've won
There is an interval in which I can guess, as well as a guess attempt limit
The trick is, however, that I need to implement another condition: each guess should "shrink" the interval in which I'm able to guess. For example: computer generates 50, I guess 25, computer replies "The random number is larger.". Now knowing that, I should not guess anything lower than 25 again, it's unreasonable. In case I guess i.e. 15, the computer should reply "The guess doesn't make sense.". I understand that I somehow need to save each guess value to a new variable, but nothing seems to work. I'm a beginner, please bear with the following code, I've tried a lot of things:
public String guess(int guess)
{
int lowerBound = 0;
int upperBound = 99;
Set<Integer> lowerGuesses = new TreeSet<>();
Set<Integer> higherGuesses = new TreeSet<>();
if (gameOver) {
return "The game is over.";
}
if (guess < 0 || guess > 99) {
return "The guess is out of bounds.";
}
if (guessCount < maxGuessCount) {
if (guess < secretNumber) {
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
lowerBound = guess;
lowerGuesses.add(guess);
return "The random number is larger.";
}
}
if (guess > secretNumber) {
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
else {
guessCount++;
upperBound = guess;
higherGuesses.add(guess);
return "The random number is smaller.";
}
}
if (lowerGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
if (higherGuesses.contains(guess)) {
return "The guess doesn't make sense.";
}
}
if (guess < lowerBound || guess > upperBound) {
return "The guess doesn't make sense.";
}
if (guessCount == maxGuessCount) {
gameOver = true;
victorious = false;
return "Ran out of guess attempts.";
}
guessCount++;
gameOver = true;
victorious = true;
return "You won.";
}
Thank you in advance!
First, to avoid confusion, let's rename the method in order to make sure that its name is not an exact match with its parameter, so this is how it should look like:
public String makeGuess(int guess)
avoid naming different entities in the same name space with the exact same name (local variables being present in different methods or parameters having similar names with data members for the purpose of initialization are an exception). From now on, you will call the method as makeGuess(25), for example.
Now, to the actual problem. You have an incorrect assumption. You assume that you need to keep track of past intervals. That's not the case. You can just change the edges of the intervals. Also, your code is superfluous, I advise you to refactor it. Finally, you always initialize upper bounds, local bounds and higher and lower guesses as local variables, so they will never be kept track of. Instead of this, you need to perform the following simple measures in order to make this work:
Define the bounds and limit as data members
protected int lowerBound = 0;
protected int higherBound = 99;
protected int lb = 0;
protected int hb = 99;
protected int limit = 5;
protected int guessCount = 0;
protected int randomizedNumber; //Initialize this somewhere
Note that I have hard-coded some values. You might want to make this dynamic with initialization and stuff like that, but that's outside the scope of the answer. lowerBound, higherBound, limit are game settings. while lb, hb, guessCount represent the game state. You could separate this logic into another class, but for the sake of simplicity, even though I would program differently, I will leave them here in this case.
Have a method that initializes the game
public void initialize() {
lb = lowerBound;
hb = higherBound;
guessCount = 0;
}
So you separate your concern of game initialization from the outer logic of starting and maintaining a game.
Implement makeGuess in a simplistic way
public String makeGuess(int guess) {
if (++guessCount >= limit) return "The game is over.";
else if ((lb > guess) || (hb < guess)) return "The guess doesn't make sense";
else if (randomizedNumber == guess) return "You won.";
else if (guess < randomizedNumber) {
hb = guess;
return "The random number is smaller.";
} else {
lb = guess;
return "The random number is larger.";
}
}
NOTE: I dislike mixing up the logic with the output layer, the reason I did it in the method above was that you have mentioned you are a beginner and my intention is to make this answer understandable for the person who just begun programming and is very confused. For the purpose of actual solutions, you should return a state and in a different layer process that state and perform the console/UI operations you need. I will not go through the details now, as it would also be outside of scope, but for now, please have some success with the solution above, but THEN you should DEFINITELY look into how you need to code, because that is almost as important as making your code work.
Okay, I'm totally rewriting this question because this works and I want to know why it works.
Suppose I have a number, testNumber with a value of 567.
I want to know if the next two numbers (shouldPassTest and shouldFailTest) the same digits, but in different 10s places.
So here's the code:
int testNumber = 567;
int num1 = 5;
int num2 = 6;
int num3 = 7;
int shouldPassTest = 756;
int shouldFailTest = 777;
if(Integer.toString(shouldPassTest).matches("[5,6,7][5,6,7][5,6,7]")
{
//Do some cool stuff
}
if(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]")
{
//Do some cool stuff
}
What happens when you run that, is that each digit is tested from the range of available digits (5, 6, and 7). Theoretically, shouldFailTest should actually pass the test seeing as how 7 matches one of my three criteria, albeit 3 times.
But what happens is that 777 returns false, when tested. This is precisely the result I wanted in my code, but I want to know why it happened. Does the matches method test to make sure that each number is only matched once?
Thanks!
This post was highly edited. After running my code, I found that the method does exactly what I want, but now I want to know why. Thanks.
I would use the following as regex is not a good solution to this problem:
public class Count {
private int value;
public Count() {
value=0;
}
void increment() {
value++;
}
void decrement() {
value--;
}
public int getValue() {
return value;
}
}
public static boolean isAnagram(int val1, int val2) {
Map<Character, Count> characterCountMap=new HashMap<>();
for(char c:Integer.toString(val1).toCharArray()) {
Count count=characterCountMap.get(c);
if(count==null) { count=new Count(); characterCountMap.put(c, count);}
count.increment();
}
for(char c:Integer.toString(val2).toCharArray()) {
Count count=characterCountMap.get(c);
if(count==null) { return false; }
else { count.decrement(); }
if(count.getValue()==0) {
characterCountMap.remove(c);
}
}
return characterCountMap.size()==0;
}
Please run:
System.out.println(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]"));
to view the actual return value.
Theoretically, shouldFailTest should actually pass the test seeing as
how 7 matches one of my three criteria, albeit 3 times.
But what happens is that 777 returns false, when tested. This is
precisely the result I wanted in my code, but I want to know why it
happened. Does the matches method test to make sure that each number
is only matched once?
No, "777" does match the pattern you have specified "[5,6,7][5,6,7][5,6,7]"
Following condition in your code will evaluate to true.
if(Integer.toString(shouldFailTest).matches("[5,6,7][5,6,7][5,6,7]"))
I'm trying to generate a new unique identifier for each object in a class, without using a static nextID field to just increment. Using that will create complications when unloading and unloading the program.
I came up with a solution to loop through the objects in a static method checking them all but for some unknown reason to me, it won't exit the while-loop.
I have been testing it in ideone.com here trying to create 5 objects to begin with, though it won't even create one.
Without having to go to the link to view the whole testing code, below is the method I'm using.
public static int newRandomID() {
int randomID = 0;
boolean notUnique = true;
while (notUnique) {
randomID = (int) (Math.random() * 999999 + 1);
for (Example e : examples) {
if (e.ID == randomID) {
notUnique = true;
break;
}
notUnique = false;
}
}
return randomID;
}
Have I just made a stupid mistake that I'm too blind to see, or is there a reason that this isn't working?
If all you need is a unique identifier (that need not be sequential) and it dosn't have to be an integer, have a look at java.util.UUID
your notUnique is bit confusing and i think you are doing it wrong in here
if (e.ID == randomID) {
notUnique = true;
break;
}
you dont need to break the statement if the id exists. i changed you code may be this helps.
int randomID = 0;
boolean ContinueLoop = true;
while (ContinueLoop) {
randomID = (int) (Math.random() * 999999 + 1);
boolean exist = false;
for (Example e : examples) {
if (e.ID == randomID) {
exist = true;
}else{
exist = false;
break;
}
}
if(exist==false){
ContinueLoop = false;
}else{
ContinueLoop = true;
}
}
return randomID;
Tried to execute your code (from the link you sent):
After you created and printed 50 new ids, I tried to generate 150,000 more:
for (int i = 0; i < 150000; i++)
new Example();
and... it works perfectly fine! Just took it a minute or so (which makes sense).
If I try to create only 15,000 records it works in less than a second.
Which leads me to the conclusion that miss rate is exponentially high and starts to be unbearable once you reach 15% of the ids capacity.
Don't continue with this solution.
Use a different approach such as a stored sequential number (if you store the records). If you don't store the records, I don't see a reason why not to use a static int variable.
For the past few months, I switched to programming in a functional language (Racket), and recently restarted coding in Java, so I'm a bit confused regarding a few concepts.
The following (simplified version) code is an implementation of euclid's algorithm. It works just fine. My problem with it is the return statement. Is it possible in java to store the results of a method in a variable? For example,in my code, I initialized the variable result to store the gcd of two numbers. But that returns an incorrect value. However, if I remove the variable result, I get the correct value for the gcd, which brings me to my 2nd question: return statements. I don't quite understand what the return statement is doing here. The only reason I have it in the 1st place was because I was aiming to store the result of the method Recursion in a variable. But as far as I've tried it, and seems to be only messing up my code.
Primary objective: To store the result of the gcd of two numbers in a variable, so I can re-use it elsewhere.
Is there is a way to make this possible?
Any suggestions would be appreciated!
import java.util.*;
public class StoringResults
{
public static void main(String[]args)
{
int big,small,remainder,gcd; //Variables declared.
Scanner sc=new Scanner(System.in);
/* Use enters input */
//Big is the larger number.
//Small is the smaller of the two.
remainder=big%small;
int result=recursion(big,small,remainder);
System.out.println("FINAL RESULT:"+result);
}
//recursive method.
public static int recursion(int big,int small,int remainder)
{
remainder=big%small;
if(remainder==0)
{
System.out.println(small);
}
else
{
int dummyvar=remainder;
big=small;
small=dummyvar;
recursion(big,small,remainder);
}
return remainder;
}
}
As my comment already stated your logic is faulty.
And your statement if I remove the variable result,I get the correct value for the gcd is plain wrong. You get the correct result printed but not returned. And that is caused by the fact that you return the wrong value.
remove the remainder from the method signature since your first statement is assigning something to it
return the correct value: smaller instead of remained
return in the else branch
That will result in the following code:
public static int recursion(int big,int small)
{
int remainder=big%small;
if(remainder==0)
{
System.out.println(small);
}
else
{
big=small;
small=remainder;
return recursion(big,small);
}
return small;
}
Shortening results in
public static int recursion(int big, int small) {
int remainder = big % small;
if(remainder == 0) {
return small;
} else {
return recursion(small,remainder);
}
}
Adding to TDG's answer, your code should be more like this:
//recursive method.
public static int recursion(int big, int small, int remainder) {
remainder = big%small
if (remainder==0) {
System.out.println(small);
return small;
} else {
Int dummyvar = remainder;
big = small;
small = dummyvar;
return recursion(big, small, remainder);
}
}
I'm trying some Java recently and look for some review of my style. If You like to look at this exercise placed in the image, and tell me if my style is good enought? Or maybe it is not good enought, so You can tell me on what aspect I should work more, so You can help me to improve it?
exercise for my question
/*
* File: MathQuiz.java
*
* This program produces Math Quiz.
*/
import acm.program.*;
import acm.util.*;
public class MathQuiz extends ConsoleProgram {
/* Class constants for Quiz settings. */
private static final int CHANCES = 3;
private static final int QUESTIONS = 5;
private static final int MIN = 0;
private static final int MAX = 20;
/* Start program. Number of questions to ask is assigned here. */
public void run() {
println("Welcome to Math Quiz");
while(answered != QUESTIONS) {
produceNumbers();
askForAnswer();
}
println("End of program.");
}
/* Ask for answer, and check them. Number of chances includes
* first one, where user is asked for reply. */
private void askForAnswer() {
int answer = -1;
if(type)
answer = readInt("What is " + x + "+" + y + "?");
else
answer = readInt("What is " + x + "-" + y + "?");
for(int i = 1; i < CHANCES+1; i++) {
if(answer != solution) {
if(i == CHANCES) {
println("No. The answer is " + solution + ".");
break;
}
answer = readInt("That's incorrect - try a different answer: ");
} else {
println("That's the answer!");
break;
}
}
answered++;
}
/* Produces type and two numbers until they qualify. */
private void produceNumbers() {
produceType();
produceFirst();
produceSecond();
if(type)
while(x+y >= MAX) {
produceFirst();
produceSecond();
}
else
while(x-y <= MIN) {
produceFirst();
produceSecond();
}
calculateSolution();
}
/* Calculates equation solution. */
private void calculateSolution() {
if(type) solution = x + y;
else solution = x - y;
}
/* Type of the equation. True is from plus, false is for minus. */
private void produceType() {
type = rgen.nextBoolean();
}
/* Produces first number. */
private void produceFirst() {
x = rgen.nextInt(0, 20);
}
/* Produces second number. */
private void produceSecond() {
y = rgen.nextInt(0, 20);
}
/* Class variables for numbers and type of the equation. */
private static boolean type;
private static int x;
private static int y;
/* Class variables for equation solution. */
private static int solution;
/* Class variable counting number of answered equations,
* so if it reaches number of provided questions, it ends */
private static int answered = 0;
/* Random generator constructor. */
RandomGenerator rgen = new RandomGenerator();
}
One thing I noticed was that all of your methods take no parameters and return void.
I think it would be clearer if you use method parameters and return values to show the flow of data through your program instead of using the object's state to store everything.
There are a few things you should do differently, and a couple you could do differently.
The things you should do differently:
Keep all fields together.
static fields should always be in THIS_FORM
you've used the static modifier for what clearly look like instance fields. (type,x,y,solution, answered). This means you can only ever run one MathsQuiz at a time per JVM. Not a big deal in this case, but will cause problems for more complex programs.
produceFirst and produceSecond use hardcoded parameters to nextInt rather than using MAX and MIN as provided by the class
There is no apparent need for answered to be a field. It could easily be a local variable in run.
Things you should do differently:
There is a small possibility (however tiny), that produceNumbers might not end. Instead of producing two random numbers and hoping they work. Produce one random number and then constrain the second so that a solution will always be formed. eg. say we are doing and addition and x is 6 and max is 20. We know that y cannot be larger than 14. So instead of trying nextInt(0,20), you could do nextInt(0,14) and be assured that you would get a feasible question.
For loop isn't really the right construct for askForAnswer as the desired behaviour is to ask for an answer CHANCES number of times or until a correct answer is received, whichever comes first. A for loop is usually used when you wish to do something a set number of times. Indeed the while loop in run is a good candidate for a for loop. A sample while loop might look like:
int i = 1;
boolean correct = (solution == readInt("What is " + x + "+" + y + "?"));
while (i < CHANCES && !correct) {
correct = (solution == readInt("Wrong, try again."));
i++;
}
if (correct) {
println("Well done!");
} else {
println("Nope, the answer is: "+solution);
}
Looks like a very clean program style. I would move all variables to the top instead of having some at the bottom, but other than that it is very readable.
Here is something I'd improve: the boolean type that is used to indicate whether we have an addition or subtraction:
private void produceType() {
type = rgen.nextBoolean();
}
produceType tells, that something is generated and I'd expect something to be returned. And I'd define enums to represent the type of the quiz. Here's my suggestion:
private QuizType produceType() {
boolean type = rgen.nextBoolean();
if (type == true)
return QuizType.PLUS;
else
return QuizType.MINUS;
}
The enum is defined like this:
public enum QuizType { PLUS, MINUS }
Almost good I have only a few improvements:
variables moves to the top
Inside produceNumbers and your while you have small repeat. I recommend refactor this
Small advice: Code should be like books - easy readable - in your run() method firstly you call produceNumber and then askForAnswer. So it will be better if in your code you will have the same order in definitions, so implementation askForAnswer before produceNumber. But it isn't necessary
Pay attention to have small methods. A method shouldn't have much to do - I think that askForAnswer you could split to two methods