How to understand the order of this code running - java

As I know, the order of code running is top down. So when call 2 method book.ship(), chemistrySet.ship() at the bottom, I think the 1st one should be called first. So why the result shows as below:
High value item!
Shipping
Shipping cost: 1.75
Order not ready
For the book instance, the cost = 9.99, but it still shows High value item!. How can I figure this out?
public class Order {
boolean isFilled; //true
double billAmount; //9.99
String shipping; //Express
public Order(boolean filled, double cost, String shippingMethod) {
if (cost > 24.00) {
System.out.println("High value item!");
}
isFilled = filled;
billAmount = cost;
shipping = shippingMethod;
}
public void ship() {
if (isFilled) {
System.out.println("Shipping");
System.out.println("Shipping cost: " + calculateShipping());
} else {
System.out.println("Order not ready");
}
}
public double calculateShipping() {
// declare conditional statement here
if (shipping.equals("Regular")) {
return 0;
} else if (shipping.equals("Express")){
return 1.75;
} else {return .50;}
}
public static void main(String[] args) {
// do not alter the main method!
Order book = new Order(true, 9.99, "Express");
Order chemistrySet = new Order(false, 72.50, "Regular");
book.ship();
chemistrySet.ship();
}
}

The first thing happening here is the main() method, which is where the program starts:
public static void main(String[] args) {
// do not alter the main method!
Order book = new Order(true, 9.99, "Express"); //(1)
Order chemistrySet = new Order(false, 72.50, "Regular"); //(2)
book.ship(); //(3)
chemistrySet.ship(); //(4)
}
You call the constructor method of the class for "book":
public Order(boolean filled, double cost, String shippingMethod) {
if (cost > 24.00) {
System.out.println("High value item!");
}
isFilled = filled;
billAmount = cost;
shipping = shippingMethod;
}
And nothing is printed because cost < 24.00.
Now you call the constructor again for "chemistrySet", but this time it prints "High value item!" because its cost > 24.00
You call book.ship() and, since filled == true, it prints: Shipping and Shipping cost: 1.75
Now you call chemistrySet.ship(), but this time isFilled equals false, so it prints Order not ready

Related

Turning a Queue into a Priority Queue

In the CarWash program that I have right now there is currently a normal queue that I would like to change into a priority queue. My goal is to take one of the basic server characteristics and use that for priority but I am lost on how to do that. In previous attempts I have tried to change the normal queue into a priority queue and have ran into issues on how I am supposed to base it off a server characteristic.
public class CarWash {
public static void main(String[ ] args) {
Scanner kb = new Scanner (System.in);
System.out.println("Enter wash time: ");
int WASHTIME = kb.nextInt();
System.out.println("Enter arrival probability: ");
double ARRIVALPROB = kb.nextDouble();
System.out.println("enter time for simulation: ");
int TOTALTIME = kb.nextInt();
carWashSimulate(WASHTIME, ARRIVALPROB, TOTALTIME);
}
public static void carWashSimulate(int washTime, double arrivalProb, int totalTime) { //simulates the car wash
Queue<Integer> arrivalTimes = new LinkedList<Integer>( );
int next;
ClientGenerator arrival = new ClientGenerator(arrivalProb);
Server machine = new Server(washTime);
ExpressServer newM = new ExpressServer(washTime);
Averager waitTimes = new Averager( );
Averager lostCustomer = new Averager();
int currentSecond;
// Write the parameters to System.out.
System.out.println("Seconds to wash one car: " + washTime);
System.out.print("Probability of customer arrival during a second: ");
System.out.println(arrivalProb);
System.out.println("Total simulation seconds: " + totalTime);
// Check the precondition:
if (washTime <= 0 || arrivalProb < 0 || arrivalProb > 1 || totalTime < 0)
throw new IllegalArgumentException("Values out of range");
for (currentSecond = 0; currentSecond < totalTime; currentSecond++) {
// Simulate the passage of one second of time
// Check whether a new customer has arrived.
if (arrival.query( )){
System.out.println("Customer arrived at " + currentSecond);
if(arrivalTimes.size() <= 8){
arrivalTimes.add(currentSecond);
}
else{
System.out.println("They left, line was too long");
lostCustomer.addNumber(1);
}
// Check whether we can start washing another car.
if ((!machine.isBusy( )) && (!arrivalTimes.isEmpty( )))
{
next = arrivalTimes.remove( );
waitTimes.addNumber(currentSecond - next);
machine.start( );
System.out.println("Server started at " + currentSecond + " serving customer " + next);
}
// Subtract one second from the remaining time in the current wash cycle.
machine.reduceRemainingTime( );
} // end of for loop
// Write the summary information about the simulation.
System.out.println("Customers served: " + waitTimes.howManyNumbers( ));
if (waitTimes.howManyNumbers( ) > 0)
System.out.println("Average wait for customers served: " + waitTimes.average( ) + " sec");
System.out.println("The number of customers lost was " + lostCustomer);
}
}
}
Client Generator Class:
public class ClientGenerator {
private double probability;
// The approximate probability of query( ) returning true.
public ClientGenerator(double p) {
if ((p < 0) || (1 < p))
throw new IllegalArgumentException("Illegal p: " + p);
probability = p;
}
public void adjust(double a) {
if(a > 0 && a+probability < 1) {
probability = probability + a;
} else if (a < 0 && probability + a > 0) {
probability = probability + a;
}
}
public double getProbability() {
return probability;
}
public boolean query( ) {
return (Math.random( ) < probability);
}
}
Server Class:
public class Server {
private int secondsForService; // Seconds for a single wash
private int timeLeft; // Seconds until this Server is no longer busy
public Server(int s) {
secondsForService = s;
timeLeft =0;
}
public boolean isBusy( ) {
return (timeLeft > 0);
}
public void reduceRemainingTime( ) {
if (timeLeft > 0) timeLeft--;
}
public void start( ) {
if (timeLeft > 0)
throw new IllegalStateException("Server is already busy.");
timeLeft = secondsForService;
}
}
Averager class:
public class Averager
{
private int count; // How many numbers have been given to this averager
private double sum; // Sum of all the numbers given to this averager
public Averager( )
{
count =0;
sum = 0;
}
public void addNumber(double value)
{
if (count == Integer.MAX_VALUE)
throw new IllegalStateException("Too many numbers");
count++;
sum += value;
}
public double average( )
{
if (count == 0)
return Double.NaN;
else
return sum/count;
}
public int howManyNumbers( )
{
return count;
}
}
The question seems to be about how to configure the priority rules employed by a java.util.PriorityQueue. That's relatively straightforward. Depending on which constructor you use to instantiate one, PriorityQueue relies either on the natural order of its elements (see Comparable) or on the order defined by a specified Comparator. Whenever such a queue contains any elements, its head is the least with respect to the operative ordering, or among the least if there are multiple elements such that no other element is less.
In comments you clarified
my goal is to implement some way of randomly assigning a value that represents the type of car, which will then prioritize the luxury car before the other cars.
Note well that PriorityQueue uses the properties of the enqueued objects to establish their relative order. Right now you are enqueuing integer arrival times, which don't confer an ability to distinguish between classes of car. If you want to carry more information about each vehicle that arrives then you would probably want to create a new class for that, maybe something like this:
class ClientArrival {
enum Category { NORMAL, LUXURY }
Category category;
int arrivalTime;
// ...
}
You would then be able to create one or more implementations of Comparator<ClientArrival> to use to define the priority rule for a PriorityQueue<ClientArrival>. For example,
class LuxuryFirstComparator implements Comparator<ClientArrival> {
int compare(ClientArrival o1, ClientArrival o2) {
if (o1.getCategory() == o2.getCategory()) {
// ... order based on arrival time ...
} else if (o1.getCategory() == ClientArrival.Category.LUXURY) {
return -1;
} else {
return 1;
}
}
}
One might set up a PriorityQueue<ClientArrival> using that to determine priority via
Queue<ClientArrival> arrivals = new PriorityQueue<>(new LuxuryFirstComparator());

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.

JAVA Wrong output in object array program (beginner)

I have an assignment to calculate the amount of carbon dioxide produced in a year from
a household and compare how recycling can reduce its CO2 Footprint.
There are two classes in the program, CO2FromWaste, and CO2FromWasteTester.
The first class, CO2FromWaste is:
public class CO2FromWaste
{
//declaration of private instance variables
private int numPeople;
private boolean Paper, Plastic, Glass, Cans;
private double grossWasteEmission, wasteReduction, netWasteReduction;
//constructor
CO2FromWaste(int people, boolean paper, boolean plastic, boolean glass, boolean cans){
numPeople = people;
Paper = paper;
Plastic = plastic;
Glass = glass;
Cans = cans;
grossWasteEmission = 0.0;
wasteReduction = 0.0;
netWasteReduction = 0.0;
}
public void calcGrossWasteEmission(){
grossWasteEmission = numPeople * 1018;
}
public double getGrossWasteEmission(){
return grossWasteEmission;
}
public void calcWasteReduction(){
if (Paper == true){
wasteReduction = numPeople * 184;
}
if (Plastic == true){
wasteReduction += (numPeople * 25.6);
}
if (Glass == true){
wasteReduction+= (numPeople*46.6);
}
if (Cans == true){
wasteReduction+=(numPeople*165.8);
}
}
public double getWasteReduction()
{
return wasteReduction;
}
public void calcNetWasteReduction(){
netWasteReduction = grossWasteEmission = wasteReduction;
}
public double getNetWasteReduction(){
return netWasteReduction;
}
public int getNumPeople(){
return numPeople;
}
public boolean getPaper(){
return Paper;
}
public boolean getPlastic(){
return Plastic;
}
public boolean getGlass(){
return Glass;
}
public boolean getCans(){
return Cans;
}
}
The second class, CO2FromWasteTester is:
import java.util.ArrayList;
public class CO2FromWasteTester
{
public static void main(String[]args){
ArrayList<CO2FromWaste> waste = new ArrayList<CO2FromWaste>();
waste.add(new CO2FromWaste(1, true, true, true, true));
waste.add(new CO2FromWaste(3, true, false, true, true));
waste.add(new CO2FromWaste(4, false, false, false, false));
waste.add(new CO2FromWaste(1, true, true, true, true));
waste.add(new CO2FromWaste(1, true, true, true, true));
CO2FromWaste wasteRecord;
for (int index = 0; index < waste.size(); index++){
wasteRecord = waste.get(index);
wasteRecord.calcGrossWasteEmission();
wasteRecord.calcWasteReduction();
wasteRecord.calcNetWasteReduction();
}
System.out.println(" Household Waste Recycled Total Pounds of CO2 Net");
System.out.println(" Index People Paper Plastic Glass Cans Emission Reduction Emission ");
for (int index = 0; index < waste.size(); index ++)
{
wasteRecord = waste.get(index);
System.out.printf("%3d %9d %10s %10s %10s %10s %12.2f %10.2f %10.2f%n",index,wasteRecord.getNumPeople(),wasteRecord.getPaper(), wasteRecord.getPlastic(), wasteRecord.getGlass(),wasteRecord.getCans(),wasteRecord.getGrossWasteEmission(),wasteRecord.getWasteReduction(),wasteRecord.getNetWasteReduction());
}
}
}
The output should read like a table, with the correct data under the headers.
For the first line, the output should be
0 1 true true true true 1018.00 422.00 596.00
but it reads
0 1 true true true true 422.00 422.00 422.00
There is something wrong starting the the gross emission part, and that part should be fairly simple because all it needs to do is to multiply the number of people given by 1018.
I am not sure what to do from here and would appreciate some help.
This is the problem:
public void calcNetWasteReduction(){
netWasteReduction = grossWasteEmission = wasteReduction;
}
That's equivalent to:
public void calcNetWasteReduction(){
grossWasteEmission = wasteReduction;
netWasteReduction = grossWasteEmission;
}
In other words, it's modifying grossWasteEmission when it shouldn't be. I suspect you wanted:
public void calcNetWasteReduction(){
netWasteReduction = grossWasteEmission - wasteReduction;
}
In other words, making the second = a - instead.
It's not clear why you have the three separate methods at all, to be honest - why not perform the calculations in the constructor? Or in the getter methods (removing the intermediate fields altogether)?
Additionally, consider making an enum of waste reduction types (PAPER, GLASS, PLASTIC) and taking an EnumSet of them. If you do keep them as individual parameters, I would strongly advise you to change the names to be more conventional Java (paper instead of Paper etc) and use if (paper) rather than if (paper == true) etc. In general, avoid explicit checking against Boolean constants.
The problem is here:
for (int index = 0; index < waste.size(); index++){
wasteRecord = waste.get(index);
wasteRecord.calcGrossWasteEmission();
wasteRecord.calcWasteReduction();
wasteRecord.calcNetWasteReduction(); // <== netWasteReduction = grossWasteEmission = wasteReduction;
}
You just need to replace the '=' sign below. Its because of this line that you are getting all the three values equal. :-)
public void calcNetWasteReduction(){
netWasteReduction = grossWasteEmission = wasteReduction;
Hope this helps

How would I store the health values and run again until either player health == 0 or enemy health == 0

What would be the best way for me to code the the actual attack / defend between the two characters and how would I store the health value so that re attacks could be stored until either player health or enemy health reached 0, and then declare the victor. This is my first ever attempt at any kind programming after self teaching from various sources, please also give me feed back on any improvement I could make, I'm sure there will be many.
Thank you in advance.
:-)
package test;
public class BattleClass {
public static void main(String[] args) {
PlayerStats ps = new PlayerStats();
EnemyStats es = new EnemyStats();
int eh = es.getEnemyHealth();
int ph = ps.getPlayerHealth();
ps.PlayerAttackDefend();
es.AttackDefend();
System.out.println("You chose to " + ps.getpInput() + " and rolled "
+ ps.getPlayerRoll());
System.out.println("The enemy chose to " + es.getEaod()
+ " and rolled " + es.getEnemyRoll() + ".");
if (ps.getpInput().equals("Attack")) {
if (es.getEaod().equals("Attack")) {
System.out
.println("YOUR SWORDS BOUNCE OFF EACHOUTHERS... TRY AGAIN!");
System.exit(0);
}
if (es.getEaod().equals("Defend")) {
if (ps.getPlayerRoll() > es.getEnemyRoll())
eh -= ps.getPlayerRoll() - es.getEnemyRoll();
System.out.println("Enemy Health is " + eh);
}
}
if (ps.getpInput().equals("Defend")) {
if (es.getEaod().equals("Defend")) {
System.out
.println("YOUR SHIELDS BOUNCE OFF EACHOTHERS... TRY AGAIN!");
System.exit(0);
}
}
if (es.getEaod().equals("Attack")) {
if (es.getEnemyRoll() > ps.getPlayerRoll())
ph -= es.getEnemyRoll() - ps.getPlayerRoll();
System.out.println("Your Health is " + ph);
}
}
}
package test;
import java.util.Random;
import java.util.Scanner;
public class PlayerStats {
static Scanner paod = new Scanner(System.in);
//Players initial health value.
private int playerHealth = 10;
//RNG for attack value / defence value using dice as object.
private int playerRoll = new Random().nextInt(6) + 1;
private String pInput;
//Method for selecting Attack or Defence.
public void PlayerAttackDefend() {
System.out.println("Do you want to Attack or Defend?");
System.out.println("a = Attack / d = Defend");
//Player selects attack or defend.
String userInput = paod.nextLine();
if (userInput.equals("a")) {
pInput = "Attack";
}
if (userInput.equals("d")) {
pInput = "Defend";
}
}
public static Scanner getPaod() {
return paod;
}
public int getPlayerHealth() {
return playerHealth;
}
public int getPlayerRoll() {
return playerRoll;
}
public String getpInput() {
return pInput;
}
public static void setPaod(Scanner paod) {
PlayerStats.paod = paod;
}
public void setPlayerHealth(int playerHealth) {
this.playerHealth = playerHealth;
}
public void setPlayerRoll(int playerRoll) {
this.playerRoll = playerRoll;
}
public void setpInput(String pInput) {
this.pInput = pInput;
}
}
package test;
import java.util.Random;
public class EnemyStats {
//Enemy initial health value.
private int enemyHealth = 10;
//RNG for attack value / defence value using dice as object.
private static int enemyRoll = new Random().nextInt(6) + 1;
//RNG for enemy decision to Attack or Defend.
private static int eAttackDefend = new Random().nextInt(2) + 1;
//Used for returning attack or defend string.
private static String eaod;
//Attack or Defend method.
public void AttackDefend() {
if (eAttackDefend == 1) {
eaod = "Attack";
} else {
eaod = "Defend";
}
}
public int getEnemyHealth() {
return enemyHealth;
}
public int getEnemyRoll() {
return enemyRoll;
}
public int geteAttackDefend() {
return eAttackDefend;
}
public String getEaod() {
return eaod;
}
public void setEnemyHealth(int enemyHealth) {
this.enemyHealth = enemyHealth;
}
public void setEnemyRoll(int enemyRoll) {
EnemyStats.enemyRoll = enemyRoll;
}
public void seteAttackDefend(int eAttackDefend) {
EnemyStats.eAttackDefend = eAttackDefend;
}
public void setEaod(String eaod) {
EnemyStats.eaod = eaod;
}
}
An easy way would to be to set maxHp and actualHp values, if you want to be able to "heal".
If you just decrease until one is dead, you can just decrease the actual health variable you already have.
You might wanna take a look at Inheritance in general, as you have a lot of duplicate code.
In general, just make a loop
while(ps.getHealth() > 0 && es.getHealth() > 0) {
// your battle code
}
you might want to remove the System.exit(0) calls, as they terminate the program.
Add to the player/enemy a dealDamage(int damage) method to actually be able to reduce their health
The health values should be in the objects, and you should not need to store them in your BattleClass.
I could give you the short answer but I guess you get more out of a detailed explanation :-)
You want to run your code "until either player health or enemy health reached 0" so you need a loop.
In java you have 3 kinds of loops:
The for loop
for(int i=1;i<=3;i++) System.out.println("Hello Musketeer Nr. "+i);
The most elaborate loop, the for loop consists of three parts, the initialization, the condition, and the afterthought. While the for loop can be used differently, it is mostly is used in the fashion shown here, that is, you have a counter variable whose value you need somehow.
If you don't need the counter variable value, you can use the short form with collections and arrays:
for(Person p: persons) System.out.println("Hello, "+person.getName()+"!");
The while loop
The second most commonly used (at least by me) loop, it has an initial condition and iterates, as long as it is true.
while(ph>0&&eh>0)
{
...
}
As you see, it fits your problem very well. For completeness, I will however describe the third loop which is the
do-while loop
do
{
...
}
while(ph>0&&eh>0)
You use this loop like the while loop but if you want to have at least one run through.
Other Remarks
Why have two classes PlayerStats and EnemyStats in combat system (they both seem to have the same actions and values) ? You could just have:
Stats playerStats=new Stats();
Stats enemyStats=new Stats();

Making change recursively: How do I modify my algorithm to print all combinations?

I have an algorithm that recursively makes change in the following manner:
public static int makeChange(int amount, int currentCoin) {
//if amount = zero, we are at the bottom of a successful recursion
if (amount == 0){
//return 1 to add this successful solution
return 1;
//check to see if we went too far
}else if(amount < 0){
//don't count this try if we went too far
return 0;
//if we have exhausted our list of coin values
}else if(currentCoin < 0){
return 0;
}else{
int firstWay = makeChange(amount, currentCoin-1);
int secondWay = makeChange(amount - availableCoins[currentCoin], currentCoin);
return firstWay + secondWay;
}
}
However, I'd like to add the capability to store or print each combination as they successfully return. I'm having a bit of a hard time wrapping my head around how to do this. The original algorithm was pretty easy, but now I am frustrated. Any suggestions?
CB
Without getting into the specifics of your code, one pattern is to carry a mutable container for your results in the arguments
public static int makeChange(int amount, int currentCoin, List<Integer>results) {
// ....
if (valid_result) {
results.add(result);
makeChange(...);
}
// ....
}
And call the function like this
List<Integer> results = new LinkedList<Integer>();
makeChange(amount, currentCoin, results);
// after makeChange has executed your results are saved in the variable "results"
I don't understand logic or purpose of above code but this is how you can have each combination stored and then printed.
public class MakeChange {
private static int[] availableCoins = {
1, 2, 5, 10, 20, 25, 50, 100 };
public static void main(String[] args) {
Collection<CombinationResult> results = makeChange(5, 7);
for (CombinationResult r : results) {
System.out.println(
"firstWay=" + r.getFirstWay() + " : secondWay="
+ r.getSecondWay() + " --- Sum=" + r.getSum());
}
}
public static class CombinationResult {
int firstWay;
int secondWay;
CombinationResult(int firstWay, int secondWay) {
this.firstWay = firstWay;
this.secondWay = secondWay;
}
public int getFirstWay() {
return this.firstWay;
}
public int getSecondWay() {
return this.secondWay;
}
public int getSum() {
return this.firstWay + this.secondWay;
}
public boolean equals(Object o) {
boolean flag = false;
if (o instanceof CombinationResult) {
CombinationResult r = (CombinationResult) o;
flag = this.firstWay == r.firstWay
&& this.secondWay == r.secondWay;
}
return flag;
}
public int hashCode() {
return this.firstWay + this.secondWay;
}
}
public static Collection<CombinationResult> makeChange(
int amount, int currentCoin) {
Collection<CombinationResult> results =
new ArrayList<CombinationResult>();
makeChange(amount, currentCoin, results);
return results;
}
public static int makeChange(int amount, int currentCoin,
Collection<CombinationResult> results) {
// if amount = zero, we are at the bottom of a successful recursion
if (amount == 0) {
// return 1 to add this successful solution
return 1;
// check to see if we went too far
} else if (amount < 0) {
// don't count this try if we went too far
return 0;
// if we have exhausted our list of coin values
} else if (currentCoin < 0) {
return 0;
} else {
int firstWay = makeChange(
amount, currentCoin - 1, results);
int secondWay = makeChange(
amount - availableCoins[currentCoin],
currentCoin, results);
CombinationResult resultEntry = new CombinationResult(
firstWay, secondWay);
results.add(resultEntry);
return firstWay + secondWay;
}
}
}
I used the following:
/**
* This is a recursive method that calculates and displays the combinations of the coins included in
* coinAmounts that sum to amountToBeChanged.
*
* #param coinsUsed is a list of each coin used so far in the total. If this branch is successful, we will add another coin on it.
* #param largestCoinUsed is used in the recursion to indicate at which coin we should start trying to add additional ones.
* #param amountSoFar is used in the recursion to indicate what sum we are currently at.
* #param amountToChange is the original amount that we are making change for.
* #return the number of successful attempts that this branch has calculated.
*/private static int change(List<Integer> coinsUsed, Integer currentCoin, Integer amountSoFar, Integer amountToChange)
{
//if last added coin took us to the correct sum, we have a winner!
if (amountSoFar == amountToChange)
{
//output
System.out.print("Change for "+amountToChange+" = ");
//run through the list of coins that we have and display each.
for(Integer count: coinsUsed){
System.out.print(count + " ");
}
System.out.println();
//pass this back to be tallied
return 1;
}
/*
* Check to see if we overshot the amountToBeChanged
*/
if (amountSoFar > amountToChange)
{
//this branch was unsuccessful
return 0;
}
//this holds the sum of the branches that we send below it
int successes=0;
// Pass through each coin to be used
for (Integer coin:coinAmounts)
{
//we only want to work on currentCoin and the coins after it
if (coin >= currentCoin)
{
//copy the list so we can branch from it
List<Integer> copyOfCoinsUsed = new ArrayList<Integer>(coinsUsed);
//add on one of our current coins
copyOfCoinsUsed.add(coin);
//branch and then collect successful attempts
successes += change(copyOfCoinsUsed, coin, amountSoFar + coin, amountToChange);
}
}
//pass back the current
return successes;
}

Categories

Resources