Print out a table that displays how far a cannon can shoot an object at incremental speeds and angles

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite
1












Does the way I am storing and printing out the data make any sense? or am I going about it all wrong. the code works great, but I'm not entirely sure it was the best way to go about it. Also, I think I can ditch the arrayList and use an array, but I'm not sure if I should.



import java.util.ArrayList;
public class CatapultTester

public static void main (String args)
25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
System.out.println("*************************************************************************");

for(int x = 0, i = 0; x < NumSpeeds; x++)

double mph = cat.get(i).getMilesPerHour();

System.out.printf(" %-8.0f", mph);

for(int y = 0; y < NumAngles; y++, i++)

double dist = cat.get(i).getDist();

System.out.printf("%-10.2f ", dist);


System.out.print("n");


System.out.println("*************************************************************************");




Here is the Catapult class



public class Catapult

private double launchAngle;
private double milesPerHour;
private double distance;

/**
* Constructor for objects of class Catapult
*
* @param angle The angle at whitch the projectile is launched.
*
* @param mph The speed at whitch the projectile is launched.
*/
public Catapult(int angle, int mph)

launchAngle = angle;
milesPerHour = mph;


/**
* Calulates how far the projectile travels
*/
public void calcDist()

distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);


/**
* @return Returns distance.
*/
public double getDist()

return distance;


//not used, but I added it anyway. it could be used to make a dynamic header for the output.
/**
* @return Returns launchAngle.
*/
public double getLaunchAngle()

return launchAngle;


/**
* @return Returns milesPerHour.
*/
public double getMilesPerHour()

return milesPerHour;




Also, sorry about the messy code.







share|improve this question

















  • 1




    You should add the code for the Catapult class. Everything else is a good first question already. :)
    – Roland Illig
    Jan 13 at 5:55










  • You don't need to be sorry about any messy code. At least I don't see anything messy.
    – Roland Illig
    Jan 13 at 5:58
















up vote
3
down vote

favorite
1












Does the way I am storing and printing out the data make any sense? or am I going about it all wrong. the code works great, but I'm not entirely sure it was the best way to go about it. Also, I think I can ditch the arrayList and use an array, but I'm not sure if I should.



import java.util.ArrayList;
public class CatapultTester

public static void main (String args)
25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
System.out.println("*************************************************************************");

for(int x = 0, i = 0; x < NumSpeeds; x++)

double mph = cat.get(i).getMilesPerHour();

System.out.printf(" %-8.0f", mph);

for(int y = 0; y < NumAngles; y++, i++)

double dist = cat.get(i).getDist();

System.out.printf("%-10.2f ", dist);


System.out.print("n");


System.out.println("*************************************************************************");




Here is the Catapult class



public class Catapult

private double launchAngle;
private double milesPerHour;
private double distance;

/**
* Constructor for objects of class Catapult
*
* @param angle The angle at whitch the projectile is launched.
*
* @param mph The speed at whitch the projectile is launched.
*/
public Catapult(int angle, int mph)

launchAngle = angle;
milesPerHour = mph;


/**
* Calulates how far the projectile travels
*/
public void calcDist()

distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);


/**
* @return Returns distance.
*/
public double getDist()

return distance;


//not used, but I added it anyway. it could be used to make a dynamic header for the output.
/**
* @return Returns launchAngle.
*/
public double getLaunchAngle()

return launchAngle;


/**
* @return Returns milesPerHour.
*/
public double getMilesPerHour()

return milesPerHour;




Also, sorry about the messy code.







share|improve this question

















  • 1




    You should add the code for the Catapult class. Everything else is a good first question already. :)
    – Roland Illig
    Jan 13 at 5:55










  • You don't need to be sorry about any messy code. At least I don't see anything messy.
    – Roland Illig
    Jan 13 at 5:58












up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1





Does the way I am storing and printing out the data make any sense? or am I going about it all wrong. the code works great, but I'm not entirely sure it was the best way to go about it. Also, I think I can ditch the arrayList and use an array, but I'm not sure if I should.



import java.util.ArrayList;
public class CatapultTester

public static void main (String args)
25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
System.out.println("*************************************************************************");

for(int x = 0, i = 0; x < NumSpeeds; x++)

double mph = cat.get(i).getMilesPerHour();

System.out.printf(" %-8.0f", mph);

for(int y = 0; y < NumAngles; y++, i++)

double dist = cat.get(i).getDist();

System.out.printf("%-10.2f ", dist);


System.out.print("n");


System.out.println("*************************************************************************");




Here is the Catapult class



public class Catapult

private double launchAngle;
private double milesPerHour;
private double distance;

/**
* Constructor for objects of class Catapult
*
* @param angle The angle at whitch the projectile is launched.
*
* @param mph The speed at whitch the projectile is launched.
*/
public Catapult(int angle, int mph)

launchAngle = angle;
milesPerHour = mph;


/**
* Calulates how far the projectile travels
*/
public void calcDist()

distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);


/**
* @return Returns distance.
*/
public double getDist()

return distance;


//not used, but I added it anyway. it could be used to make a dynamic header for the output.
/**
* @return Returns launchAngle.
*/
public double getLaunchAngle()

return launchAngle;


/**
* @return Returns milesPerHour.
*/
public double getMilesPerHour()

return milesPerHour;




Also, sorry about the messy code.







share|improve this question













Does the way I am storing and printing out the data make any sense? or am I going about it all wrong. the code works great, but I'm not entirely sure it was the best way to go about it. Also, I think I can ditch the arrayList and use an array, but I'm not sure if I should.



import java.util.ArrayList;
public class CatapultTester

public static void main (String args)
25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
System.out.println("*************************************************************************");

for(int x = 0, i = 0; x < NumSpeeds; x++)

double mph = cat.get(i).getMilesPerHour();

System.out.printf(" %-8.0f", mph);

for(int y = 0; y < NumAngles; y++, i++)

double dist = cat.get(i).getDist();

System.out.printf("%-10.2f ", dist);


System.out.print("n");


System.out.println("*************************************************************************");




Here is the Catapult class



public class Catapult

private double launchAngle;
private double milesPerHour;
private double distance;

/**
* Constructor for objects of class Catapult
*
* @param angle The angle at whitch the projectile is launched.
*
* @param mph The speed at whitch the projectile is launched.
*/
public Catapult(int angle, int mph)

launchAngle = angle;
milesPerHour = mph;


/**
* Calulates how far the projectile travels
*/
public void calcDist()

distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);


/**
* @return Returns distance.
*/
public double getDist()

return distance;


//not used, but I added it anyway. it could be used to make a dynamic header for the output.
/**
* @return Returns launchAngle.
*/
public double getLaunchAngle()

return launchAngle;


/**
* @return Returns milesPerHour.
*/
public double getMilesPerHour()

return milesPerHour;




Also, sorry about the messy code.









share|improve this question












share|improve this question




share|improve this question








edited Jan 13 at 6:34
























asked Jan 13 at 4:47









HamBone41801

386




386







  • 1




    You should add the code for the Catapult class. Everything else is a good first question already. :)
    – Roland Illig
    Jan 13 at 5:55










  • You don't need to be sorry about any messy code. At least I don't see anything messy.
    – Roland Illig
    Jan 13 at 5:58












  • 1




    You should add the code for the Catapult class. Everything else is a good first question already. :)
    – Roland Illig
    Jan 13 at 5:55










  • You don't need to be sorry about any messy code. At least I don't see anything messy.
    – Roland Illig
    Jan 13 at 5:58







1




1




You should add the code for the Catapult class. Everything else is a good first question already. :)
– Roland Illig
Jan 13 at 5:55




You should add the code for the Catapult class. Everything else is a good first question already. :)
– Roland Illig
Jan 13 at 5:55












You don't need to be sorry about any messy code. At least I don't see anything messy.
– Roland Illig
Jan 13 at 5:58




You don't need to be sorry about any messy code. At least I don't see anything messy.
– Roland Illig
Jan 13 at 5:58










2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










Welcome to Code Review! You did a good job so far, but I have some style and logic suggestions for you.



Let's talk about the Catapult class first. In its current form is a good container but it has two flaws. First, you declare the constructor to accept int parameters but are storing them in double variables. Either it should be all int or should be all double, but I am assuming for the rest of this answer that you want double. The second flaw is that you calculate the distance in a separate function and not the constructor. This concept of a cached value is not the flaw, but the way you are using it, is. The only reason you would want to calculate that distance in a different location than in the constructor of Catapult is if it was a very expensive operation that might not need to be called. For this simple example, make the function private and call it in the constructor as follows:



private double angle;
private double speed;
private double distance;

// The second parameter is named "speed" to be consistent with the rest of the
// code. Its better to write a comment or documentation stating that "angle"
// is in degrees and "speed" is in miles per hour.
public Catapult(double angle, double speed)
this.angle = angle;
this.speed = speed;
this.distance = this.calculateDistance();


...

private double calculateDistance()
return speed * speed * Math.sin(2 * Math.toRadians(angle)) / 9.8;


public double getDistance()
return this.distance;



Also, rename the other getters to getAngle and getSpeed accordingly.



(Edit: perhaps getLaunchAngle can stay, but getMilesPerHour is not a good function name.)



Next let's talk about CatapultTester. You should move the constants that are defined at the top of main into the class definition itself. I suggest making a constructor for a CatapultTester that takes in those arguments. This way, you have the ability to make several unique CatapultTester objects. If, for example, you want the user of your library to test the Catapult in a custom way, they can build their own CatapultTester objects. Provide that ability to the user:



public class CatapultTester 
// make sure these are reasonable defaults
private double startAngle = 25;
private double startSpeed = 20;
private double angleInterval = 5;
private double speedInterval = 5;
private double numAngles = 6;
private double numSpeeds = 7;

public CatapultTester()
public CatapultTester(double startAngle, double startSpeed,
double angleInterval, double speedInterval,
double numAngles, double numSpeeds)

... // implement custom constructor here


public void printTest()
... // put your test program here instead


... // add more functionality in the future?



The point of doing this is that you're putting all the details of the object in the class itself instead of the main program. The main function would end up looking something like this:



public static void main(String args) 
new CatapultTester().printTest();



This clearly conveys the meaning behind your main function, without the specifics that don't need to be known by the user. Now, if you want to expand main in any way, you have a more powerful API to work with.



Now to your actual test function. There are several instances of duplicated code, note the three for loops that run over the same range. What you should do instead is just loop over the range you need and do all the computation in one step. This would also remove the need for an array for the Catapult objects.



The last for loop is enough:



System.out.println(" | Projectile Distance (ft.) ");
System.out.println("*************************************************************************");
System.out.println(" MPH | 25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
System.out.println("*************************************************************************");

for (int speed = 0; speed < this.numSpeeds; ++speed)
StringBuilder output = new StringBuilder(); // StringBuilder is fast!
for (int angle = 0; angle < this.numAngles; ++angle)

// build one catapult at a time and calculate all necessary values in one go
Catapult cat = new Catapult(
angle * this.angleInterval + this.startAngle,
speed * this.speedInterval + this.startSpeed
);

// prints only once at the beginning of the angle loop
if (angle == 0)
output.append(String.format(" %-8.0f", cat.getSpeed()));


output.append(String.format("%-10.2f ", cat.getDistance()));


System.out.println(output.toString());


System.out.println("*************************************************************************");


You will have to import java.util.StringBuilder for this functionality. This drastically reduces the number of computations and repetitions in your code. Its important to keep in mind the acronym DRY (Don't Repeat Yourself) and if you see something that happens over and over again, see if you can write it once but get the same computations out of it. It will speed up your code and make it more readable. I hope you found these suggestions helpful. Good job and good luck!






share|improve this answer



















  • 1




    Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
    – HamBone41801
    Jan 13 at 7:37










  • I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
    – Brandon Gomes
    Jan 13 at 7:39

















up vote
1
down vote














 System.out.println(" | Projectile Distance (ft.) ");



Maybe I'm missing something, but where's the conversion to feet? I see a calculation using a speed in miles per hour and an acceleration in metres per second squared. It would be an astonishing coincidence if that gave a distance in feet without an extra conversion factor.





 distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);



Magic number alert! The acceleration due to gravity should be pulled out into a constant (static final field).



Where does this formula come from? What limitations does it have?




There are two big limitations:



1. It assumes no air resistance. If you want to calculate values for practical use (e.g. a realistic game) you need to use air resistance, and then you don't get a nice formula but have to do quadrature. If you look hard enough it's possible to find data on historical cannons' shell weights, muzzle velocities, and maximum ranges; and from that data and an assumption that air resistance has a linear and a quadratic component in the speed of the shell it's possible to estimate their coefficients and interpolate/extrapolate. But it's 15 years since I did this, and I don't still have the values to hand.



2. It assumes that the ranges are short enough that the curvature of the Earth is irrelevant. (This is realistic: ICBMs are not launched from a cannon).




Both of these issues can be finessed by limiting the muzzle velocity severely, but the constructor doesn't place any limits on muzzle velocity. In fact, it doesn't even complain if it's negative! I think an IllegalArgumentException would be appropriate in that case.



But just to make it clear: the main point here is that the calculation would benefit from some comments to explain the derivation (or point to a reference) and the limitations / assumptions.






share|improve this answer





















    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185009%2fprint-out-a-table-that-displays-how-far-a-cannon-can-shoot-an-object-at-incremen%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    Welcome to Code Review! You did a good job so far, but I have some style and logic suggestions for you.



    Let's talk about the Catapult class first. In its current form is a good container but it has two flaws. First, you declare the constructor to accept int parameters but are storing them in double variables. Either it should be all int or should be all double, but I am assuming for the rest of this answer that you want double. The second flaw is that you calculate the distance in a separate function and not the constructor. This concept of a cached value is not the flaw, but the way you are using it, is. The only reason you would want to calculate that distance in a different location than in the constructor of Catapult is if it was a very expensive operation that might not need to be called. For this simple example, make the function private and call it in the constructor as follows:



    private double angle;
    private double speed;
    private double distance;

    // The second parameter is named "speed" to be consistent with the rest of the
    // code. Its better to write a comment or documentation stating that "angle"
    // is in degrees and "speed" is in miles per hour.
    public Catapult(double angle, double speed)
    this.angle = angle;
    this.speed = speed;
    this.distance = this.calculateDistance();


    ...

    private double calculateDistance()
    return speed * speed * Math.sin(2 * Math.toRadians(angle)) / 9.8;


    public double getDistance()
    return this.distance;



    Also, rename the other getters to getAngle and getSpeed accordingly.



    (Edit: perhaps getLaunchAngle can stay, but getMilesPerHour is not a good function name.)



    Next let's talk about CatapultTester. You should move the constants that are defined at the top of main into the class definition itself. I suggest making a constructor for a CatapultTester that takes in those arguments. This way, you have the ability to make several unique CatapultTester objects. If, for example, you want the user of your library to test the Catapult in a custom way, they can build their own CatapultTester objects. Provide that ability to the user:



    public class CatapultTester 
    // make sure these are reasonable defaults
    private double startAngle = 25;
    private double startSpeed = 20;
    private double angleInterval = 5;
    private double speedInterval = 5;
    private double numAngles = 6;
    private double numSpeeds = 7;

    public CatapultTester()
    public CatapultTester(double startAngle, double startSpeed,
    double angleInterval, double speedInterval,
    double numAngles, double numSpeeds)

    ... // implement custom constructor here


    public void printTest()
    ... // put your test program here instead


    ... // add more functionality in the future?



    The point of doing this is that you're putting all the details of the object in the class itself instead of the main program. The main function would end up looking something like this:



    public static void main(String args) 
    new CatapultTester().printTest();



    This clearly conveys the meaning behind your main function, without the specifics that don't need to be known by the user. Now, if you want to expand main in any way, you have a more powerful API to work with.



    Now to your actual test function. There are several instances of duplicated code, note the three for loops that run over the same range. What you should do instead is just loop over the range you need and do all the computation in one step. This would also remove the need for an array for the Catapult objects.



    The last for loop is enough:



    System.out.println(" | Projectile Distance (ft.) ");
    System.out.println("*************************************************************************");
    System.out.println(" MPH | 25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
    System.out.println("*************************************************************************");

    for (int speed = 0; speed < this.numSpeeds; ++speed)
    StringBuilder output = new StringBuilder(); // StringBuilder is fast!
    for (int angle = 0; angle < this.numAngles; ++angle)

    // build one catapult at a time and calculate all necessary values in one go
    Catapult cat = new Catapult(
    angle * this.angleInterval + this.startAngle,
    speed * this.speedInterval + this.startSpeed
    );

    // prints only once at the beginning of the angle loop
    if (angle == 0)
    output.append(String.format(" %-8.0f", cat.getSpeed()));


    output.append(String.format("%-10.2f ", cat.getDistance()));


    System.out.println(output.toString());


    System.out.println("*************************************************************************");


    You will have to import java.util.StringBuilder for this functionality. This drastically reduces the number of computations and repetitions in your code. Its important to keep in mind the acronym DRY (Don't Repeat Yourself) and if you see something that happens over and over again, see if you can write it once but get the same computations out of it. It will speed up your code and make it more readable. I hope you found these suggestions helpful. Good job and good luck!






    share|improve this answer



















    • 1




      Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
      – HamBone41801
      Jan 13 at 7:37










    • I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
      – Brandon Gomes
      Jan 13 at 7:39














    up vote
    2
    down vote



    accepted










    Welcome to Code Review! You did a good job so far, but I have some style and logic suggestions for you.



    Let's talk about the Catapult class first. In its current form is a good container but it has two flaws. First, you declare the constructor to accept int parameters but are storing them in double variables. Either it should be all int or should be all double, but I am assuming for the rest of this answer that you want double. The second flaw is that you calculate the distance in a separate function and not the constructor. This concept of a cached value is not the flaw, but the way you are using it, is. The only reason you would want to calculate that distance in a different location than in the constructor of Catapult is if it was a very expensive operation that might not need to be called. For this simple example, make the function private and call it in the constructor as follows:



    private double angle;
    private double speed;
    private double distance;

    // The second parameter is named "speed" to be consistent with the rest of the
    // code. Its better to write a comment or documentation stating that "angle"
    // is in degrees and "speed" is in miles per hour.
    public Catapult(double angle, double speed)
    this.angle = angle;
    this.speed = speed;
    this.distance = this.calculateDistance();


    ...

    private double calculateDistance()
    return speed * speed * Math.sin(2 * Math.toRadians(angle)) / 9.8;


    public double getDistance()
    return this.distance;



    Also, rename the other getters to getAngle and getSpeed accordingly.



    (Edit: perhaps getLaunchAngle can stay, but getMilesPerHour is not a good function name.)



    Next let's talk about CatapultTester. You should move the constants that are defined at the top of main into the class definition itself. I suggest making a constructor for a CatapultTester that takes in those arguments. This way, you have the ability to make several unique CatapultTester objects. If, for example, you want the user of your library to test the Catapult in a custom way, they can build their own CatapultTester objects. Provide that ability to the user:



    public class CatapultTester 
    // make sure these are reasonable defaults
    private double startAngle = 25;
    private double startSpeed = 20;
    private double angleInterval = 5;
    private double speedInterval = 5;
    private double numAngles = 6;
    private double numSpeeds = 7;

    public CatapultTester()
    public CatapultTester(double startAngle, double startSpeed,
    double angleInterval, double speedInterval,
    double numAngles, double numSpeeds)

    ... // implement custom constructor here


    public void printTest()
    ... // put your test program here instead


    ... // add more functionality in the future?



    The point of doing this is that you're putting all the details of the object in the class itself instead of the main program. The main function would end up looking something like this:



    public static void main(String args) 
    new CatapultTester().printTest();



    This clearly conveys the meaning behind your main function, without the specifics that don't need to be known by the user. Now, if you want to expand main in any way, you have a more powerful API to work with.



    Now to your actual test function. There are several instances of duplicated code, note the three for loops that run over the same range. What you should do instead is just loop over the range you need and do all the computation in one step. This would also remove the need for an array for the Catapult objects.



    The last for loop is enough:



    System.out.println(" | Projectile Distance (ft.) ");
    System.out.println("*************************************************************************");
    System.out.println(" MPH | 25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
    System.out.println("*************************************************************************");

    for (int speed = 0; speed < this.numSpeeds; ++speed)
    StringBuilder output = new StringBuilder(); // StringBuilder is fast!
    for (int angle = 0; angle < this.numAngles; ++angle)

    // build one catapult at a time and calculate all necessary values in one go
    Catapult cat = new Catapult(
    angle * this.angleInterval + this.startAngle,
    speed * this.speedInterval + this.startSpeed
    );

    // prints only once at the beginning of the angle loop
    if (angle == 0)
    output.append(String.format(" %-8.0f", cat.getSpeed()));


    output.append(String.format("%-10.2f ", cat.getDistance()));


    System.out.println(output.toString());


    System.out.println("*************************************************************************");


    You will have to import java.util.StringBuilder for this functionality. This drastically reduces the number of computations and repetitions in your code. Its important to keep in mind the acronym DRY (Don't Repeat Yourself) and if you see something that happens over and over again, see if you can write it once but get the same computations out of it. It will speed up your code and make it more readable. I hope you found these suggestions helpful. Good job and good luck!






    share|improve this answer



















    • 1




      Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
      – HamBone41801
      Jan 13 at 7:37










    • I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
      – Brandon Gomes
      Jan 13 at 7:39












    up vote
    2
    down vote



    accepted







    up vote
    2
    down vote



    accepted






    Welcome to Code Review! You did a good job so far, but I have some style and logic suggestions for you.



    Let's talk about the Catapult class first. In its current form is a good container but it has two flaws. First, you declare the constructor to accept int parameters but are storing them in double variables. Either it should be all int or should be all double, but I am assuming for the rest of this answer that you want double. The second flaw is that you calculate the distance in a separate function and not the constructor. This concept of a cached value is not the flaw, but the way you are using it, is. The only reason you would want to calculate that distance in a different location than in the constructor of Catapult is if it was a very expensive operation that might not need to be called. For this simple example, make the function private and call it in the constructor as follows:



    private double angle;
    private double speed;
    private double distance;

    // The second parameter is named "speed" to be consistent with the rest of the
    // code. Its better to write a comment or documentation stating that "angle"
    // is in degrees and "speed" is in miles per hour.
    public Catapult(double angle, double speed)
    this.angle = angle;
    this.speed = speed;
    this.distance = this.calculateDistance();


    ...

    private double calculateDistance()
    return speed * speed * Math.sin(2 * Math.toRadians(angle)) / 9.8;


    public double getDistance()
    return this.distance;



    Also, rename the other getters to getAngle and getSpeed accordingly.



    (Edit: perhaps getLaunchAngle can stay, but getMilesPerHour is not a good function name.)



    Next let's talk about CatapultTester. You should move the constants that are defined at the top of main into the class definition itself. I suggest making a constructor for a CatapultTester that takes in those arguments. This way, you have the ability to make several unique CatapultTester objects. If, for example, you want the user of your library to test the Catapult in a custom way, they can build their own CatapultTester objects. Provide that ability to the user:



    public class CatapultTester 
    // make sure these are reasonable defaults
    private double startAngle = 25;
    private double startSpeed = 20;
    private double angleInterval = 5;
    private double speedInterval = 5;
    private double numAngles = 6;
    private double numSpeeds = 7;

    public CatapultTester()
    public CatapultTester(double startAngle, double startSpeed,
    double angleInterval, double speedInterval,
    double numAngles, double numSpeeds)

    ... // implement custom constructor here


    public void printTest()
    ... // put your test program here instead


    ... // add more functionality in the future?



    The point of doing this is that you're putting all the details of the object in the class itself instead of the main program. The main function would end up looking something like this:



    public static void main(String args) 
    new CatapultTester().printTest();



    This clearly conveys the meaning behind your main function, without the specifics that don't need to be known by the user. Now, if you want to expand main in any way, you have a more powerful API to work with.



    Now to your actual test function. There are several instances of duplicated code, note the three for loops that run over the same range. What you should do instead is just loop over the range you need and do all the computation in one step. This would also remove the need for an array for the Catapult objects.



    The last for loop is enough:



    System.out.println(" | Projectile Distance (ft.) ");
    System.out.println("*************************************************************************");
    System.out.println(" MPH | 25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
    System.out.println("*************************************************************************");

    for (int speed = 0; speed < this.numSpeeds; ++speed)
    StringBuilder output = new StringBuilder(); // StringBuilder is fast!
    for (int angle = 0; angle < this.numAngles; ++angle)

    // build one catapult at a time and calculate all necessary values in one go
    Catapult cat = new Catapult(
    angle * this.angleInterval + this.startAngle,
    speed * this.speedInterval + this.startSpeed
    );

    // prints only once at the beginning of the angle loop
    if (angle == 0)
    output.append(String.format(" %-8.0f", cat.getSpeed()));


    output.append(String.format("%-10.2f ", cat.getDistance()));


    System.out.println(output.toString());


    System.out.println("*************************************************************************");


    You will have to import java.util.StringBuilder for this functionality. This drastically reduces the number of computations and repetitions in your code. Its important to keep in mind the acronym DRY (Don't Repeat Yourself) and if you see something that happens over and over again, see if you can write it once but get the same computations out of it. It will speed up your code and make it more readable. I hope you found these suggestions helpful. Good job and good luck!






    share|improve this answer















    Welcome to Code Review! You did a good job so far, but I have some style and logic suggestions for you.



    Let's talk about the Catapult class first. In its current form is a good container but it has two flaws. First, you declare the constructor to accept int parameters but are storing them in double variables. Either it should be all int or should be all double, but I am assuming for the rest of this answer that you want double. The second flaw is that you calculate the distance in a separate function and not the constructor. This concept of a cached value is not the flaw, but the way you are using it, is. The only reason you would want to calculate that distance in a different location than in the constructor of Catapult is if it was a very expensive operation that might not need to be called. For this simple example, make the function private and call it in the constructor as follows:



    private double angle;
    private double speed;
    private double distance;

    // The second parameter is named "speed" to be consistent with the rest of the
    // code. Its better to write a comment or documentation stating that "angle"
    // is in degrees and "speed" is in miles per hour.
    public Catapult(double angle, double speed)
    this.angle = angle;
    this.speed = speed;
    this.distance = this.calculateDistance();


    ...

    private double calculateDistance()
    return speed * speed * Math.sin(2 * Math.toRadians(angle)) / 9.8;


    public double getDistance()
    return this.distance;



    Also, rename the other getters to getAngle and getSpeed accordingly.



    (Edit: perhaps getLaunchAngle can stay, but getMilesPerHour is not a good function name.)



    Next let's talk about CatapultTester. You should move the constants that are defined at the top of main into the class definition itself. I suggest making a constructor for a CatapultTester that takes in those arguments. This way, you have the ability to make several unique CatapultTester objects. If, for example, you want the user of your library to test the Catapult in a custom way, they can build their own CatapultTester objects. Provide that ability to the user:



    public class CatapultTester 
    // make sure these are reasonable defaults
    private double startAngle = 25;
    private double startSpeed = 20;
    private double angleInterval = 5;
    private double speedInterval = 5;
    private double numAngles = 6;
    private double numSpeeds = 7;

    public CatapultTester()
    public CatapultTester(double startAngle, double startSpeed,
    double angleInterval, double speedInterval,
    double numAngles, double numSpeeds)

    ... // implement custom constructor here


    public void printTest()
    ... // put your test program here instead


    ... // add more functionality in the future?



    The point of doing this is that you're putting all the details of the object in the class itself instead of the main program. The main function would end up looking something like this:



    public static void main(String args) 
    new CatapultTester().printTest();



    This clearly conveys the meaning behind your main function, without the specifics that don't need to be known by the user. Now, if you want to expand main in any way, you have a more powerful API to work with.



    Now to your actual test function. There are several instances of duplicated code, note the three for loops that run over the same range. What you should do instead is just loop over the range you need and do all the computation in one step. This would also remove the need for an array for the Catapult objects.



    The last for loop is enough:



    System.out.println(" | Projectile Distance (ft.) ");
    System.out.println("*************************************************************************");
    System.out.println(" MPH | 25 Deg 30 Deg 35 Deg 40 Deg 45 Deg 50 Deg ");
    System.out.println("*************************************************************************");

    for (int speed = 0; speed < this.numSpeeds; ++speed)
    StringBuilder output = new StringBuilder(); // StringBuilder is fast!
    for (int angle = 0; angle < this.numAngles; ++angle)

    // build one catapult at a time and calculate all necessary values in one go
    Catapult cat = new Catapult(
    angle * this.angleInterval + this.startAngle,
    speed * this.speedInterval + this.startSpeed
    );

    // prints only once at the beginning of the angle loop
    if (angle == 0)
    output.append(String.format(" %-8.0f", cat.getSpeed()));


    output.append(String.format("%-10.2f ", cat.getDistance()));


    System.out.println(output.toString());


    System.out.println("*************************************************************************");


    You will have to import java.util.StringBuilder for this functionality. This drastically reduces the number of computations and repetitions in your code. Its important to keep in mind the acronym DRY (Don't Repeat Yourself) and if you see something that happens over and over again, see if you can write it once but get the same computations out of it. It will speed up your code and make it more readable. I hope you found these suggestions helpful. Good job and good luck!







    share|improve this answer















    share|improve this answer



    share|improve this answer








    edited Jan 13 at 7:26


























    answered Jan 13 at 7:15









    Brandon Gomes

    25017




    25017







    • 1




      Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
      – HamBone41801
      Jan 13 at 7:37










    • I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
      – Brandon Gomes
      Jan 13 at 7:39












    • 1




      Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
      – HamBone41801
      Jan 13 at 7:37










    • I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
      – Brandon Gomes
      Jan 13 at 7:39







    1




    1




    Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
    – HamBone41801
    Jan 13 at 7:37




    Thanks for the tips! Just out of curiosity, why didn't you assign a name to the CatapultTester object that you created?
    – HamBone41801
    Jan 13 at 7:37












    I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
    – Brandon Gomes
    Jan 13 at 7:39




    I left it with no name to just provide the simplest piece of code that would reproduce the logic of your main function. It is common practice in Java and other OOP languages to create unnamed objects in this way if the name is not needed.
    – Brandon Gomes
    Jan 13 at 7:39












    up vote
    1
    down vote














     System.out.println(" | Projectile Distance (ft.) ");



    Maybe I'm missing something, but where's the conversion to feet? I see a calculation using a speed in miles per hour and an acceleration in metres per second squared. It would be an astonishing coincidence if that gave a distance in feet without an extra conversion factor.





     distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);



    Magic number alert! The acceleration due to gravity should be pulled out into a constant (static final field).



    Where does this formula come from? What limitations does it have?




    There are two big limitations:



    1. It assumes no air resistance. If you want to calculate values for practical use (e.g. a realistic game) you need to use air resistance, and then you don't get a nice formula but have to do quadrature. If you look hard enough it's possible to find data on historical cannons' shell weights, muzzle velocities, and maximum ranges; and from that data and an assumption that air resistance has a linear and a quadratic component in the speed of the shell it's possible to estimate their coefficients and interpolate/extrapolate. But it's 15 years since I did this, and I don't still have the values to hand.



    2. It assumes that the ranges are short enough that the curvature of the Earth is irrelevant. (This is realistic: ICBMs are not launched from a cannon).




    Both of these issues can be finessed by limiting the muzzle velocity severely, but the constructor doesn't place any limits on muzzle velocity. In fact, it doesn't even complain if it's negative! I think an IllegalArgumentException would be appropriate in that case.



    But just to make it clear: the main point here is that the calculation would benefit from some comments to explain the derivation (or point to a reference) and the limitations / assumptions.






    share|improve this answer

























      up vote
      1
      down vote














       System.out.println(" | Projectile Distance (ft.) ");



      Maybe I'm missing something, but where's the conversion to feet? I see a calculation using a speed in miles per hour and an acceleration in metres per second squared. It would be an astonishing coincidence if that gave a distance in feet without an extra conversion factor.





       distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);



      Magic number alert! The acceleration due to gravity should be pulled out into a constant (static final field).



      Where does this formula come from? What limitations does it have?




      There are two big limitations:



      1. It assumes no air resistance. If you want to calculate values for practical use (e.g. a realistic game) you need to use air resistance, and then you don't get a nice formula but have to do quadrature. If you look hard enough it's possible to find data on historical cannons' shell weights, muzzle velocities, and maximum ranges; and from that data and an assumption that air resistance has a linear and a quadratic component in the speed of the shell it's possible to estimate their coefficients and interpolate/extrapolate. But it's 15 years since I did this, and I don't still have the values to hand.



      2. It assumes that the ranges are short enough that the curvature of the Earth is irrelevant. (This is realistic: ICBMs are not launched from a cannon).




      Both of these issues can be finessed by limiting the muzzle velocity severely, but the constructor doesn't place any limits on muzzle velocity. In fact, it doesn't even complain if it's negative! I think an IllegalArgumentException would be appropriate in that case.



      But just to make it clear: the main point here is that the calculation would benefit from some comments to explain the derivation (or point to a reference) and the limitations / assumptions.






      share|improve this answer























        up vote
        1
        down vote










        up vote
        1
        down vote










         System.out.println(" | Projectile Distance (ft.) ");



        Maybe I'm missing something, but where's the conversion to feet? I see a calculation using a speed in miles per hour and an acceleration in metres per second squared. It would be an astonishing coincidence if that gave a distance in feet without an extra conversion factor.





         distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);



        Magic number alert! The acceleration due to gravity should be pulled out into a constant (static final field).



        Where does this formula come from? What limitations does it have?




        There are two big limitations:



        1. It assumes no air resistance. If you want to calculate values for practical use (e.g. a realistic game) you need to use air resistance, and then you don't get a nice formula but have to do quadrature. If you look hard enough it's possible to find data on historical cannons' shell weights, muzzle velocities, and maximum ranges; and from that data and an assumption that air resistance has a linear and a quadratic component in the speed of the shell it's possible to estimate their coefficients and interpolate/extrapolate. But it's 15 years since I did this, and I don't still have the values to hand.



        2. It assumes that the ranges are short enough that the curvature of the Earth is irrelevant. (This is realistic: ICBMs are not launched from a cannon).




        Both of these issues can be finessed by limiting the muzzle velocity severely, but the constructor doesn't place any limits on muzzle velocity. In fact, it doesn't even complain if it's negative! I think an IllegalArgumentException would be appropriate in that case.



        But just to make it clear: the main point here is that the calculation would benefit from some comments to explain the derivation (or point to a reference) and the limitations / assumptions.






        share|improve this answer














         System.out.println(" | Projectile Distance (ft.) ");



        Maybe I'm missing something, but where's the conversion to feet? I see a calculation using a speed in miles per hour and an acceleration in metres per second squared. It would be an astonishing coincidence if that gave a distance in feet without an extra conversion factor.





         distance = (Math.pow(milesPerHour, 2) * Math.sin( 2 * Math.toRadians(launchAngle)) / 9.8);



        Magic number alert! The acceleration due to gravity should be pulled out into a constant (static final field).



        Where does this formula come from? What limitations does it have?




        There are two big limitations:



        1. It assumes no air resistance. If you want to calculate values for practical use (e.g. a realistic game) you need to use air resistance, and then you don't get a nice formula but have to do quadrature. If you look hard enough it's possible to find data on historical cannons' shell weights, muzzle velocities, and maximum ranges; and from that data and an assumption that air resistance has a linear and a quadratic component in the speed of the shell it's possible to estimate their coefficients and interpolate/extrapolate. But it's 15 years since I did this, and I don't still have the values to hand.



        2. It assumes that the ranges are short enough that the curvature of the Earth is irrelevant. (This is realistic: ICBMs are not launched from a cannon).




        Both of these issues can be finessed by limiting the muzzle velocity severely, but the constructor doesn't place any limits on muzzle velocity. In fact, it doesn't even complain if it's negative! I think an IllegalArgumentException would be appropriate in that case.



        But just to make it clear: the main point here is that the calculation would benefit from some comments to explain the derivation (or point to a reference) and the limitations / assumptions.







        share|improve this answer













        share|improve this answer



        share|improve this answer











        answered Jan 13 at 9:08









        Peter Taylor

        14.1k2454




        14.1k2454






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185009%2fprint-out-a-table-that-displays-how-far-a-cannon-can-shoot-an-object-at-incremen%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Chat program with C++ and SFML

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            Will my employers contract hold up in court?