trying to call a toString method in different Java Class - java

The assignment is to create a class called Temp that runs against the instructors TestTemp class which he provided to us for free. So far everything seems to test out pretty well except for my out put in the toString that we are supposed to use. It is supposed to format like the commented out section but doesn't seem to be working. I posed the TestTemp class and my code for the Temp class. I feel like I am missing something little but just need a nudge in the right direction and my instructor doesn't have office hours again until after the assignment is due. I also pasted the assignment instructions he added to the assignment.
The class will be called Temp
Add a compareTo method. (returns -1 if the invoking object has a lower
temp, 0 if the same, 1 if larger)
Add a static counter (object id)to keep track of how many Temperature
objects have been created(1,2,3,...)
Add a static method to tell you how many Temperature objects have been
created.
Include a toString method that displays the object as follows(assumes
3rd one created):
Object Id: 3 Temperature in F: 32.0 Temperature in C: 0.0
Note that calling getF or getC returns the value only. They do not
change the native data.
To be clear the only methods are as follows: 4 constructors, getF,
getC, setDegrees, setScale, equals, toString, compareTo and a static
getTempCount that returns the total number of objects that have been
created.
Note that the getters will return the degrees in the requested scale
rounded to a tenth of a degree. Never round the native data.
Note that the equals method will return true if the temperatures are
the same when compared in celsius (that was rounded to a tenth of a
degree).
Be sure to make great use of this() and have only one contructor do
any real work.
Besure to validate the scale and follow the default (C) if a "bad
scale" is sent in
No need to validate the degrees and worry about things such as
absolute zero and so on.
NOTE: Your Temp class must work correctly with the TestTemp class
supplied in UNIT-04-CodeSamples
//32 - 212 180 ticks
//
//0-100 1/10
//
public class TestTemp
{
public static void main(String [] args)
{
// only one constructor does any real work
Temp temp1 = new Temp(); // 0 C
Temp temp2 = new Temp(32); // 32 C
Temp temp3 = new Temp('F'); // 0 F
Temp temp4 = new Temp(32, 'F'); // 32 F
Temp temp5 = new Temp(); // 0 C
temp5.setDegrees(10);
temp5.setScale('F'); // 10 F
System.out.println("C: " + temp1.getC() ); // C: 0.0
System.out.println("F: " + temp1.getF() ); // F: 32.0
System.out.println(temp1.equals(temp4)); // true
System.out.println(temp1.equals(temp2)); // false
System.out.println("You have " + Temp.getTempCount() ); // You have 5
if( temp3.compareTo(temp5)< 0 ) //temp3 is lower than than temp5
{
System.out.println("temp3 is lower than than temp5");
}
else
{
System.out.println("temp3 is same or larger than temp5");
}
System.out.println(temp1);
/*
TEMP OBJECT #1
IN C: 0.0
IN F: 32.0
*/
}
}
public class Temp implements Comparable<Temp>
{
private double degrees;
private char scale;
private static int tempCount = 0;
private int id;
public Temp()
{
this.degrees = 0;
this.scale = 'C';
// this(0.0, 'C');
}
public Temp(double degrees)
{
this.degrees = degrees;
this.scale = 'C';
// this(degrees, 'C');
}
public Temp(char scale)
{
this.degrees = 0;
this.scale = scale;
// this(0.0, scale);
}
public Temp(double degrees, char scale)
{
this.id = ++tempCount;
this.degrees = degrees;
this.scale = scale;
//(degrees, scale);
}
public static int getTempCount()
{
return tempCount;
}
public int getId()
{
return this.id;
}
public void setScale(char scale)
{
if(scale == 'C')
{
this.scale = scale;
}
else
{
this.scale = 'F';
}
}
public void setDegrees(double degrees)
{
this.degrees = degrees;
}
public double getC()
{
if(scale == 'C')
{
return degrees;
}
else
{
return (double)(5.0 * (degrees-32)/9.0);
}
}
public double getF()
{
if(scale == 'F')
{
return (double) degrees;
}
else
{
return (double)(9.0*(degrees)/5.0)+32;
}
}
#Override
public int compareTo(Temp obj)
{
if(this.getC() < obj.getC() )
{
return -1;
}
if(this.getC() > obj.getC() )
{
return 1;
}
return 0;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Temp))
{
return false;
}
Temp other = (Temp)obj;
return this.getC() == other.getC();
}
**public String toString()
{
return String.format("TEMP OBJECT ", this.id) + "\n" +
String.format("IN C: ", this.getC() ) + "\n" +
String.format("IN F: ", this.getF() );
}**
}

You need place holders in the formatter, Your toString method should be like
public String toString()
{
return String.format("TEMP OBJECT %d", this.id) + "\n" +
String.format("IN C: %.2f", this.getC() ) + "\n" +
String.format("IN F: %.2f", this.getF() );
}
Here %d for integers and %f for decimals. and the .2f limits the number of decimal places to 2. See some more examples here

Your use of String.format shouldn't require multiple creations. Just use one.
return String.format("TEMP OBJECT: $d, %nIN C: %.2f, %nIN F: %.2f", this.id, this.getC(), this.getF());
Modify the precision of the floating points by altering the value after the decimal point %.2f to %.5f will print 0.00000 instead of 0.00 for example.
If you have anymore questions on the use of format, I recommend reading the documentation for it as well to see what else it can do. Link
Edit: Added newline breaks. Forgot to mention just put %n for a newline. Do not space, after them, unless you want your newline to start with a space.

Related

How does one set a number of spaces based on user input?

The assignment is asking me to create a class named Vehicle that stimulates a car moving along a 40 block stretch of road.
Here's more information:
Your class will build a vehicle and keep track of its location on the road. Location values may range from -20 to 20. A location value of 0 represents block 0, a location value of 1 represents block 1, a location value of 2 represents block 2, etc. If the user tries to move the vehicle beyond block +20 or -20, set the location to +/- 20 respectively.(I dont understand how to do this part)
Variable
int location - An integer that holds the current block location of the car on the road, with possible values ranging from -20 to 20.
Methods
Vehicle () - Sets location to 0.
Vehicle (int loc) - If loc is between -20 and 20 inclusive, sets location to loc. Otherwise, sets location to 0.
void forward () - Increments the vehicle forward one block. Do not let the user move past block 20.
void backward () - Increments the vehicle backward one block. Do not let the user move past block -20.
int getLocation () - Returns an integer representing the block location of the car.
String toString () - Returns a String representation showing the vehicle as an # character, with spaces to show its location. When the vehicle is at location -20 the # character appears at the start of the String. When the vehicle is at a higher position, one space for each number from -20 to the car's current location appears before the #. For example if the car is at block -10, the method will return " #" (10 spaces then the '#'). If the car is at block 5 the method will return " #" (25 spaces then the '#').
Here's my code so far(this is in my Vehicle.java file) :
public class Vehicle
{
private int location;
public Vehicle(int loc)
{
return location;
}
public void forward()
{
if (location>=-20 && location <=20)
{
location++;
}
}
public void backward()
{
if (location>=-20 && location <=20)
{
location--;
}
}
public int getLocation()
{
return location;
}
public String toString()
{
return "";
}
}
Here is the runner file:
import java.util.Scanner;
public class runner_Vehicle
{
public static void main (String str[]){
Scanner scan = new Scanner(System.in);
Vehicle v = new Vehicle ();
String instruction = "";
while(!instruction.equals("q")){
System.out.println(v);
System.out.println("Location: " + v.getLocation());
System.out.println("Type \"f\" to move forwards, \"b\" to move backwards, \"n\" for new vehicle, \"q\" to quit.");
instruction = scan.nextLine();
if(instruction.equals("f")){
v.forward();
}
else if(instruction.equals("b")){
v.backward();
}
else if(instruction.equals("n")){
System.out.println("Starting location for new vehicle?");
int start = scan.nextInt();
v = new Vehicle(start);
scan.nextLine();
}
else if(!instruction.equals("q")){
System.out.println("Instruction not recognized.");
}
}
}
}
If the user tries to move the vehicle beyond block +20 or -20, set the location to +/- 20 respectively. (I dont understand how to do this part)
Simply check it and cap the value
public void forward()
{
location++;
if (location > 20) location = 20;
}
public void backward()
{
location--;
if (location < 20) location = -20;
}
Regarding the toString method - Look at the StringBuilder class
StringBuilder sb = new StringBuilder();
for (int i = -20; i <= 20; i++) {
if (i == getLocation()) {
sb.append("#");
}
else sb.append(" ");
}
return sb.toString();
First time answering a question, but hope I can be of some help:
I've tried to explain what each thing does in places I thought you might have been confused. If you are going to hand this in, please remove the comments.
class Vehicle {
private int location;
public Vehicle() {
// Known as the constructor.
// Creates an instance of the class, meaning it creates the vehicle object when you say
// Vehicle car = new Vehicle();
location = 0;
}
public Vehicle(int loc) {
// known as a parameterized constructor, which is just a constructor but you give it some default values.
// It does not return a value, all it does it make the object in question.
// In this case, it would be a Vehicle object.
if (loc >= -20 && loc <= 20) {
location = loc;
}
}
public void forward() {
location++;
if (location >= 21) {
location = -20;
}
}
public void backward() {
location--;
if (location <= -21) {
location = 20;
}
}
public int getLocation() {
return location;
}
public String toString() {
String output = "";
for (int i = -20; i < location; i++) {
output += ' ';
}
return output + '#';
}
}
Hopefully that helps!

How to fix leaking accessor methods?

so I am having trouble figuring out why my test in JUnit is failing. I have a Bill class, a Money class, and a Date class. A new Bill object is being created in the test and the line
assertTrue( myBill.getAmount().getCents() == 0);
is failing. So I am aware of where it is happening but I'm not exactly sure how to fix it. I have tried changing my mutator methods to things like
return new Date(dueDate);
instead of just
return dueDate;
but it is still failing in JUnit. Please help!
Test code:
#Test
public void testBillConstructorPrivacyLeak()
{
Date date1 = new Date( 1, 1, 2020);
Money money1 = new Money( 10);
Bill myBill = new Bill( money1, date1, "sam");
date1.setYear( 2021);
money1.setMoney( 5, 10);
//Now get values and make sure they have not changed
assertTrue( myBill.getAmount().getCents() == 0);
assertTrue( myBill.getDueDate().getYear() == 2020);
}
My classes:
public class Bill
{
private Money amount;
private Date dueDate;
private Date paidDate;
private String originator;
//paidDate set to null
public Bill (Money amount, Date dueDate, String originator) {
this.amount = amount;
this.dueDate = dueDate;
this.originator = originator;
paidDate = null;
}
//copy constructor
public Bill (Bill toCopy) {
this.amount = toCopy.amount;
this.dueDate = toCopy.dueDate;
this.paidDate = toCopy.paidDate;
this.originator = toCopy.originator;
}
public Money getAmount () {
return new Money(amount);
}
public Date getDueDate () {
return new Date(dueDate);
}
public String getOriginator () {
return originator;
}
//returns true if bill is paid, else false
public boolean isPaid () {
return (paidDate != null);
}
//if datePaid is after the dueDate, the call does not update anything and returns false.
//Else updates the paidDate and returns true
//If already paid, we will attempt to change the paid date.
public boolean setPaid (Date datePaid) {
if (datePaid.isAfter(dueDate)) {
return false;
}
else {
paidDate = new Date(datePaid);
return true;
}
}
//Resets the due date – If the bill is already paid, this call fails and returns false.
//Else it resets the due date and returns true.
public boolean setDueDate (Date newDueDate) {
if (isPaid()) {
return false;
}
else {
dueDate = new Date(newDueDate);
return true;
}
}
//Change the amount owed.
//If already paid returns false and does not change the amount owed else changes
//the amount and returns true.
public boolean setAmount (Money amount) {
if (isPaid()) {
return false;
}
else {
amount = new Money(amount);
return true;
}
}
public void setOriginator (String originator) {
this.originator = originator;
}
//Build a string that reports the amount, when due, to whom, if paid, and if paid
//the date paid
public String toString () {
return "Amount: " + amount + " Due date: " + dueDate + " To: " + "originator" + " Paid?" + isPaid() + "Paid date: " + paidDate;
}
//Equality is defined as each field having the same value.
public boolean equals (Object toCompare) {
if (toCompare instanceof Bill) {
Bill that = (Bill) toCompare;
return this.amount.equals(that.amount) &&
this.dueDate.equals(that.dueDate) &&
this.paidDate.equals(that.paidDate) &&
this.originator.equals(that.originator);
}
return false;
}
}
public class Money
{
private int dollars;
private int cents;
//Constructor which sets the dollar amount, and sets cents to 0
//If the user enters in an amount LT 0, you will throw an IllegalArgumentException
public Money (int dol) {
if (dol < 0) {
throw new IllegalArgumentException ("Must be greater than 0.");
}
this.dollars = dol;
cents = 0;
}
//Constructor which initialized dollars and cents.
//If the user enters in an amount LT 0, you will throw an IllegalArgumentException
public Money (int dol, int cent) {
if (dol < 0 || cent < 0) {
throw new IllegalArgumentException ("Must be greater than 0.");
}
this.dollars = dol;
this.dollars += cent / 100;
this.cents = cent % 100;
}
//Copy constructor
public Money (Money other) {
this.dollars = other.dollars;
this.cents = other.cents;
}
public int getDollars () {
return dollars;
}
public int getCents () {
return cents;
}
//If the user enters in an amount LT 0, you will throw an IllegalArgumentException
public void setMoney (int dollars, int cents) {
if (dollars < 0 || cents < 0) {
throw new IllegalArgumentException ("Must be greater than 0.");
}
this.dollars = dollars;
this.dollars += cents / 100;
this.cents = cents % 100;
}
//Gets the money amount as a double
//For example it might return 5.75
public double getMoney () {
return dollars + (cents / 100.0);
}
//If the user enters in an amount LT 0, you will throw an IllegalArgumentException4
public void add (int dollars) {
if (dollars < 0) {
throw new IllegalArgumentException ("Must be greater than 0.");
}
this.dollars += dollars;
}
//If the user enters in an amount LT 0, you will throw an IllegalArgumentException
public void add (int dollars, int cents) {
if (dollars < 0 || cents < 0) {
throw new IllegalArgumentException ("Must be greater than 0.");
}
this.dollars += dollars;
this.cents += cents;
this.dollars += this.cents / 100;
this.cents = this.cents % 100;
}
//Adds the amounts in other to our money object – reducing cents appropriately.
public void add (Money other) {
this.dollars += other.dollars;
this.cents += other.cents;
this.dollars += this.cents / 100;
this.cents = this.cents % 100;
}
//Two money objects are the same if they have the same value for dollars and cents.
public boolean equals (Object o) {
if( o instanceof Money) {
return this.dollars == ((Money)o).dollars && this.cents == ((Money)o).cents;
}
return false;
}
//Prints out the amount as a string IE “$3.75” or “$4.00” Note the number of digits displayed for cents.
//Again for testing and grading purposes use this EXACT output format
public String toString () {
String c = String.format("%.02d",cents);
return "$" + dollars + "." + c;
}
}
Your problem results from the fact that in your constructor for Bill you store references to the Money and Date objects. Then, when you modify those objects in the test case you are modifying the same objects.
If you don't want that behavior you have to make a deep copy of the Money and Date objects in the Bill constructor, i.e.:
public Bill (Money amount, Date dueDate, String originator) {
this.amount = new Money(amount);
this.dueDate = new Date(dueDate);
this.originator = originator;
paidDate = null;
}
You don't have to do this for originator because Strings are immutable.
Although you do not show the implementation of your Money class, the fact that it has a setMoney method suggests it's mutable. In that case, your problem is that Bill's constructor isn't making copies of the objects it's passed in, and thus any changes to money1 also change the state of myBill. Similar remarks apply to the Date objects.
Try modifying your code as follows:
public Bill (Money amount, Date dueDate, String originator) {
this.amount = new Money(amount); // needs copy-constructor for Money
this.dueDate = new Date(dueDate); // likewise for Date
this.originator = originator; // no copying needed as String is immutable
paidDate = null;
}
//copy constructor
public Bill (Bill toCopy) {
// Make copies also in the copy-constructor
this.amount = new Money(toCopy.amount);
this.dueDate = new Date(toCopy.dueDate);
this.paidDate = (toCopy.paidDate == null) ? null : new Date(toCopy.paidDate);
this.originator = toCopy.originator;
}
In general, designing your objects to be mutable means you have to copy defensively in constructors and elsewhere.
On the other hand, designing your objects to be immutable is better as it avoids such problems (and is in fact the advice given by Joshua Bloch in his "Effective Java" book), but it turns out that Java doesn't help you a lot with them either and it's likely you'll struggle for quite some time with getting them done right.
My recommendation is for you to explore the http://immutables.github.io/ library for a better starting point with this design approach.
When I am trying to replicate your code, I am getting error in this line:
public Date getDueDate () {
return new Date(dueDate);
}
Can you please tell what Date constructor you are using. As java.util.date has no such constructor which takes Date as an arguments.
Please elaborate so that I can proceed with debug and answer your query.
Thanks.

Error trying to use command line arguments in Java

I am new to Java and am still getting used to the minor difference so please excuse any mistakes you may find ridiculous.
I am trying to write a program that stores temperature and can be used to call that temperature in Celsius or in Fahrenheit. My only issue comes with the command line arguments, after successfully compiling my program I enter the following:
java Driver 0.0C 32.0F
And then I get this:
Exception in thread "main" java.lang.NumberFormatException: For input string:
"0.0C"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Float.parseFloat(Float.java:452)
at Driver.main(Driver.java:47)
My program is still not completely polished up so I know that the getters can be written to be much for efficient and that the driver program doesn't even call the temperature class, but this is not my concern at the moment. My Driver is supposed to take in the input and determine from the 'C' or 'F' character whether the value is in Celsius or Fahrenheit. It then parses the string and truncates the C or F and stores the values contained in the strings as floats. I am using Eclipse and the program is object oriented, this is my code:
public class Temperature {
private float temperature;
private char scale;
// default constructor
Temperature() {
this.temperature = 0;
this.scale = 'C';
}
Temperature(float temperatureIn) {
this.temperature = temperatureIn;
this.scale = 'C';
}
Temperature(char scaleIn) {
this.temperature = 0;
this.scale = scaleIn;
}
Temperature(float temperatureIn, char scaleIn) {
this.temperature = temperatureIn;
this.scale = scaleIn;
}
float degreesC(float degreesF) {
float degreesC = (5 * (degreesF - 32)) / 9;
return degreesC;
}
float degreesF(float degreesC) {
float degreesF = (9*(degreesC / 5)) + 32;
return degreesF;
}
void setTemperature(float temperatureIn) {
temperature = temperatureIn;
}
void setScale(char scaleIn) {
scale = scaleIn;
}
void setBothValues(float temperatureIn, char scaleIn) {
temperature = temperatureIn;
scale = scaleIn;
}
int compareTemps(Temperature temp1, Temperature temp2) {
// both values will be compared in Farenheit
Temperature temp1temp = temp1;
if (temp1temp.scale == 'C') {
temp1temp.temperature = degreesF(temp1temp.temperature);
temp1temp.scale = 'F';
}
Temperature temp2temp = temp2;
if (temp2temp.scale == 'C') {
temp2temp.temperature = degreesF(temp2temp.temperature);
temp2temp.scale = 'F';
}
if (temp1temp.temperature == temp2temp.temperature) {
return 0;
}
if (temp1temp.temperature > temp2temp.temperature)
return 1;
if (temp1temp.temperature < temp2temp.temperature)
return -1;
return 0;
}
}
And the main driver program:
public class Driver {
public static void main(String[] args) {
// ints to hold the temperature values
float temp1Value = 0;
float temp2Value = 0;
// strings to hold the scale types
char temp1Scale = 'C';
char temp2Scale = 'C';
// declare objects of type temperature
Temperature firstTemp = null;
Temperature secondTemp = null;
// copy scale values of temperatures
int scaleIndex = 0;
int scaleIndex2 = 0;
if (args.length > 0) {
if (args[0].indexOf('C') != -1)
{
scaleIndex = args[0].indexOf('C');
temp1Scale = args[0].charAt(scaleIndex);
}
else if (args[0].indexOf('F') != -1)
{
scaleIndex = args[0].indexOf('F');
temp1Scale = args[0].charAt(scaleIndex);
}
if (args[1].indexOf('C') != -1)
{
scaleIndex = args[1].indexOf('C');
temp2Scale = args[1].charAt(scaleIndex2);
}
else if (args[1].indexOf('F') != -1)
{
scaleIndex = args[1].indexOf('F');
temp2Scale = args[1].charAt(scaleIndex2);
}
}
// parse the values to exclude scales and copy to strings holding temperature values
if (args.length > 0) {
temp1Value = Float.parseFloat(args[0].substring(0, scaleIndex));
temp2Value = Float.parseFloat(args[1].substring(0, scaleIndex2));
}
}
}
the exception you are getting is beacuse you passed '0.0C' to the float parser at:
tempValue = Float.parseFloat(args[1].substring(0, scaleIndex));
that is beacuse you do
scaleIndex = args[1].indexOf('F');
effectively overwriting the scaleIndex instead of setting scaleIndex2
please be open minded with my following recommendations:
object oriented means you create classes which will take up responsibility
your Temperature class stores temp in celsius and in fahrenheit too..which might be easier, but storing only for example Kelvins would mean you have a strong inner concept inside the class
when someone asks for C or F it calculates from the K
after that the Temperature class's constructor should be responsible for parsing '0.0C' and '42.0F'
It is better you take inputs as <temp1> <unit1> <temp2> <unit2>. This way you'll get all the parameter you need in the desired format. You can now parse args[0] and args[2] for tempValues and the other two parameter for the units. Even better, just take <temp1> <temp2> as you command line arguments and decide that <temp1> is in degC and <temp2> is in F.

Recursive function to calculate possible finish for darts

I'm trying to write a recursive function in Java, to determine how to finish for a game of Darts. Basically, you have a maximum of 3 darts, en you have to finish with a double.
If you don't know the rule of Darts x01 games with Double Out finishing, it's difficult to understand this question... Let me try to explain. For simplicity, I keep the Bull's eye out of the equation for now.
Rules:
1) You have three darts which you can throw at number 1 through 20
2) A single hit can have a single, double or triple score
E.g. you can hit:
single 20 = 20 points or
double 20 = 40 points or
triple 20 = 60 points
3) In one turn, you can score a maximum of 180 points (3x triple 20 = 3*60 = 180). Anything higher than 180 is impossible. This doesn't mean anything below 180 IS possible. 179 for example, is impossible as well, because the next best score is triple20+triple20+triple19 = 167
4) Normally, you start at 501, and you throw 3 darts, untill you have exactly 0 points left.
5) Now, in Double Out, it is required that the last dart hits a Double
E.g. if you have 180 points left, you cannot finish, because your last dart has to be a double. So the maximum (with ignoring the bulls eye) = triple20 + triple20 + double20 = 160
And if your score is 16, you can simply finish using 1 dart by hitting the double 8.
Another example, if your score is 61, you can hit triple17 + double5 (= 51 + 10)
Current Code
Anyway, below is what I have so far. I know it's far from what I need, but no matter what I try, i always get stuck. Perhaps someone can share his thoughts on an another approach
private class Score{
int number; // the actual number, can be 1...20
int amount; // multiplier, can be 1, 2 or 3
public Score(int number, int amount){
this.number = number; // the actual number, can be 1...20
this.amount = amount; // multiplier, can be 1, 2 or 3
}
public int value()
{
return number * amount; // the actual score
}
public void increment()
{
if(this.amount == 0)
this.amount = 1;
this.number++;
if(this.number >= 20)
{
this.number = 0;
this.amount++;
if(this.amount >= 3)
this.amount = 3;
}
}
}
public ArrayList<Score> canFinish(int desired, ArrayList<Score> score){
// If this is the case -> we have bingo
if(eval(score) == desired) return score;
// this is impossible -> return null
if(eval(score) > 170) return null;
// I can't figure out this part!!
Score dart3 = score.remove(2);
Score dart2 = score.remove(1);
if(dart2.eval() < 60){
dart2.increment();
}
else if(dart3.eval() < 60){
dart3.increment();
}
score.add(dart2);
score.add(dart3);
return canFinish(desired, score);
}
public int eval(ArrayList<Score> scores)
{
int total = 0;
for(Score score : scores){
total += score.value();
}
return total;
}
I want to simply call:
ArrayList<Score> dartsNeeded = new ArrayList<Score>();
dartsNeeded.add(new Score(16, 2)); // Add my favourite double
dartsNeeded.add(new Score(0, 0));
dartsNeeded.add(new Score(0, 0));
// and call the function
dartsNeeded = canFinish(66, dartsNeeded);
// In this example the returned values would be:
// [[16,2],[17,2],[0,0]] -> 2*16 + 2*17 + 0*0 = 66
// So I can finish, by throwing Double 17 + Double 16
So, if it is impossible to finish, the function would return null, but if there is any possible finish, i reveive that ArrayList with the 3 darts that I need to make my desired score...
Short Summary
The problem is that the above code only helps to find 1 dart, but not for the combination of the two darts. So canFinish(66, darts) works -> but canFinish(120, darts) gives a StackOverflow Exception. For 120, I would expect to get somthing like triple20, double14, double16 or any other valid combination for that matter.
If you log the scores that canFinish tries, you can see that there are a lot of possibilities missed out. Values of 20 are ignored, and one dart is incremented completely before the other dart values are modified.
Instead, it can be solved recursively as follows. canFinish(desired, score) returns any combination of darts that can be added to score to give the total of desired. Call it with a list of however many darts you know, or any empty list to find any possibility.
canFinish(desired, score)
if darts sum to desired, return desired
if there are fewer than 3 darts in score
for each possible value of a dart (if it's the last dart, check for a double)
add dart to score
if canFinish(desired, score) != null
return canFinish(desired, score)
end
remove dart from score
end
end
return null
end
I ended up using the following functions. Which kind of is a combination of switch statments and recursion... Hope someone finds it as usefull as I
public static void getCheckout(int score, int fav_double, ICheckOutEvent listener)
{
if(score > 170) return;
if(score == 170) listener.onCheckOut("T20 T20 Bull");
ArrayList<Dart> darts = new ArrayList<Dart>();
darts.add(new Dart(fav_double, 2));
darts.add(new Dart(0,0));
darts.add(new Dart(0,0));
darts = getDarts(score, darts);
if(darts != null) {
listener.onCheckOut(toString(darts));
return;
}
for(int dubble = 20 ; dubble >= 1 ; dubble--)
{
if(dubble == fav_double) continue;
darts = new ArrayList<Dart>();
darts.add(new Dart(dubble, 2));
darts.add(new Dart(0,0));
darts.add(new Dart(0,0));
darts = getDarts(score, darts);
if(darts != null){
listener.onCheckOut(toString(darts));
return;
}
}
}
public static ArrayList<Dart> getDarts(int desired, ArrayList<Dart> score)
{
Dart dart1 = canFinish(desired);
if(dart1 != null){
score.set(0, dart1);
return score;
}
int rest = desired - score.get(0).value();
Dart dart2 = canScore(rest);
if(dart2 != null)
{
score.set(0, score.get(0));
score.set(1, dart2);
return score;
}
Dart temp = score.get(1);
if(temp.increment())
{
rest = desired - score.get(0).value() - temp.value();
score.set(0, score.get(0));
score.set(1, temp);
Dart dart3 = canScore(rest);
if(dart3 != null)
{
score.set(2, dart3);
return score;
}
if(rest > 60 && temp.increment())
temp.estimate(rest / 2);
score.set(1, temp);
return getDarts(desired, score);
}
return null;
}
public static int eval(ArrayList<Dart> scores)
{
int total = 0;
for(Dart score : scores){
total += score.value();
}
return total;
}
public static Dart canFinish(int points)
{
switch(points)
{
case 2: return new Dart(1, 2);
case 4: return new Dart(2, 2);
case 6: return new Dart(3, 2);
case 8: return new Dart(4, 2);
case 10: return new Dart(5, 2);
case 12: return new Dart(6, 2);
case 14: return new Dart(7, 2);
// etc. etc.
case 40: return new Dart(20, 2);
case 50: return new Dart(25, 2);
}
return null;
}
public static Dart canScore(int points)
{
switch(points)
{
case 1: return new Dart(1, 1);
case 2: return new Dart(2, 1);
case 3: return new Dart(3, 1);
// etc. etc.
case 20: return new Dart(20, 1);
case 21: return new Dart(7, 3);
case 22: return new Dart(11, 2);
//case 23: impossible
case 24: return new Dart(12, 2);
// etc. etc.
case 57: return new Dart(19, 3);
case 60: return new Dart(20, 3);
}
return null;
}
And for completeness, here's the Dart class I created as a helper
private static class Dart{
int number;
int amount;
public Dart(int number, int amount){
this.number = number;
this.amount = amount;
}
public int value()
{
return number * amount;
}
public void estimate(int estimate)
{
Dart temp = canScore(estimate);
if(temp != null){
this.amount = temp.amount;
this.number = temp.number;
} else{
this.number = estimate / 3;
if(number >= 19)
this.number = 19;
this.amount = 3;
}
}
public boolean increment()
{
if(this.amount == 3 && this.number == 20)
return false;
if(this.amount == 0)
this.amount = 1;
this.number++;
if(this.number >= 20)
{
this.number = 20;
this.amount++;
if(this.amount >= 3){
this.amount = 3;
}
}
return true;
}
public String toString()
{
return "["+number+","+amount+"]";
}
}
class RecursiveDartboard {
public Set<Out> outsFor(int target) {
HashSet<Out> outs = new HashSet<>();
for (Score doubleScore : doubles()) {
List<Score> scores = new ArrayList();
scores.add(doubleScore);
outs.addAll(recursiveOutsFor(target, scores)
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList())
);
}
return outs;
}
private List<Optional<Out>> recursiveOutsFor(int target, List<Score> scores) {
List<Optional<Out>> outs = new ArrayList<>();
Out possibleOut = new Out(scores);
if (possibleOut.target() == target) {
outs.add(of(possibleOut));
} else if (scores.size() == 3) {
outs.add(empty());
} else {
for (Score score : allPossibleScores()) {
List<Score> nextScores = new ArrayList<>();
nextScores.addAll(scores);
nextScores.add(score);
outs.addAll(recursiveOutsFor(target, nextScores));
}
}
return outs;
}
}

Convert float to String and String to float in Java

How could I convert from float to string or string to float?
In my case I need to make the assertion between 2 values string (value that I have got from table) and float value that I have calculated.
String valueFromTable = "25";
Float valueCalculated =25.0;
I tried from float to string:
String sSelectivityRate = String.valueOf(valueCalculated);
but the assertion fails
Using Java’s Float class.
float f = Float.parseFloat("25");
String s = Float.toString(25.0f);
To compare it's always better to convert the string to float and compare as two floats. This is because for one float number there are multiple string representations, which are different when compared as strings (e.g. "25" != "25.0" != "25.00" etc.)
Float to string - String.valueOf()
float amount=100.00f;
String strAmount=String.valueOf(amount);
// or Float.toString(float)
String to Float - Float.parseFloat()
String strAmount="100.20";
float amount=Float.parseFloat(strAmount)
// or Float.valueOf(string)
You can try this sample of code:
public class StringToFloat
{
public static void main (String[] args)
{
// String s = "fred"; // do this if you want an exception
String s = "100.00";
try
{
float f = Float.valueOf(s.trim()).floatValue();
System.out.println("float f = " + f);
}
catch (NumberFormatException nfe)
{
System.out.println("NumberFormatException: " + nfe.getMessage());
}
}
}
found here
I believe the following code will help:
float f1 = 1.23f;
String f1Str = Float.toString(f1);
float f2 = Float.parseFloat(f1Str);
This is a possible answer, this will also give the precise data, just need to change the decimal point in the required form.
public class TestStandAlone {
/**
* This method is to main
* #param args void
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Float f1=152.32f;
BigDecimal roundfinalPrice = new BigDecimal(f1.floatValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
System.out.println("f1 --> "+f1);
String s1=roundfinalPrice.toPlainString();
System.out.println("s1 "+s1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Output will be
f1 --> 152.32
s1 152.32
If you're looking for, say two decimal places..
Float f = (float)12.34;
String s = new DecimalFormat ("#.00").format (f);
well this method is not a good one, but easy and not suggested. Maybe i should say this is the least effective method and the worse coding practice but, fun to use,
float val=10.0;
String str=val+"";
the empty quotes, add a null string to the variable str, upcasting 'val' to the string type.
There are three ways to convert float to String.
"" + f
Float.toString(f)
String.valueOf(f)
There are two ways Convert String to float
Float.valueOf(str)
Float.parseFloat(str);
Example:-
public class Test {
public static void main(String[] args) {
System.out.println("convert FloatToString " + convertFloatToString(34.0f));
System.out.println("convert FloatToStr Using Float Method " + convertFloatToStrUsingFloatMethod(23.0f));
System.out.println("convert FloatToStr Using String Method " + convertFloatToStrUsingFloatMethod(233.0f));
float f = Float.valueOf("23.00");
}
public static String convertFloatToString(float f) {
return "" + f;
}
public static String convertFloatToStrUsingFloatMethod(float f) {
return Float.toString(f);
}
public static String convertFloatToStrUsingStringMethod(float f) {
return String.valueOf(f);
}
}
String str = "1234.56";
float num = 0.0f;
int digits = str.length()- str.indexOf('.') - 1;
float factor = 1f;
for(int i=0;i<digits;i++) factor /= 10;
for(int i=str.length()-1;i>=0;i--){
if(str.charAt(i) == '.'){
factor = 1;
System.out.println("Reset, value="+num);
continue;
}
num += (str.charAt(i) - '0') * factor;
factor *= 10;
}
System.out.println(num);
To go the full manual route: This method converts doubles to strings by shifting the number's decimal point around and using floor (to long) and modulus to extract the digits. Also, it uses counting by base division to figure out the place where the decimal point belongs. It can also "delete" higher parts of the number once it reaches the places after the decimal point, to avoid losing precision with ultra-large doubles. See commented code at the end. In my testing, it is never less precise than the Java float representations themselves, when they actually show these imprecise lower decimal places.
/**
* Convert the given double to a full string representation, i.e. no scientific notation
* and always twelve digits after the decimal point.
* #param d The double to be converted
* #return A full string representation
*/
public static String fullDoubleToString(final double d) {
// treat 0 separately, it will cause problems on the below algorithm
if (d == 0) {
return "0.000000000000";
}
// find the number of digits above the decimal point
double testD = Math.abs(d);
int digitsBeforePoint = 0;
while (testD >= 1) {
// doesn't matter that this loses precision on the lower end
testD /= 10d;
++digitsBeforePoint;
}
// create the decimal digits
StringBuilder repr = new StringBuilder();
// 10^ exponent to determine divisor and current decimal place
int digitIndex = digitsBeforePoint;
double dabs = Math.abs(d);
while (digitIndex > 0) {
// Recieves digit at current power of ten (= place in decimal number)
long digit = (long)Math.floor(dabs / Math.pow(10, digitIndex-1)) % 10;
repr.append(digit);
--digitIndex;
}
// insert decimal point
if (digitIndex == 0) {
repr.append(".");
}
// remove any parts above the decimal point, they create accuracy problems
long digit = 0;
dabs -= (long)Math.floor(dabs);
// Because of inaccuracy, move to entirely new system of computing digits after decimal place.
while (digitIndex > -12) {
// Shift decimal point one step to the right
dabs *= 10d;
final var oldDigit = digit;
digit = (long)Math.floor(dabs) % 10;
repr.append(digit);
// This may avoid float inaccuracy at the very last decimal places.
// However, in practice, inaccuracy is still as high as even Java itself reports.
// dabs -= oldDigit * 10l;
--digitIndex;
}
return repr.insert(0, d < 0 ? "-" : "").toString();
}
Note that while StringBuilder is used for speed, this method can easily be rewritten to use arrays and therefore also work in other languages.

Categories

Resources