import java.util.Scanner;
import java.util.Random;
import java.text.DecimalFormat;

class GolfPracticeRange3
{
        public static void main( String[] args )
        {
                //
                // welcome message & golfing ability question...
                //
                System.out.println( "===================================\n"
                                  + "Welcome to the Golf Practice Range!\n"
                                  + "===================================\n" );

                System.out.println( "What is your golfing ability?" );

                System.out.println( "\n-----------------------------------\n"
                                  + " EXAMPLE PLAYER TYPES...\n"
                                  + "-----------------+-----------------\n"
                                  + " who             | golfing ability\n"
                                  + "-----------------+-----------------\n"
                                  + " Little Sally    |       0.55\n"
                                  + " Luc Devroy      |       0.6\n"
                                  + " Grampa Golfer   |       0.7\n"
                                  + " Frequent Golfer |       0.75\n"
                                  + " \"The Rock\"      |       0.8\n"
                                  + " Average Pro     |       0.95\n"
                                  + " Tiger Woods     |       1.0\n" );

                System.out.print( "\nPlease enter a number, between 0.1 and 1.0,\n"
                                + "corresponding to your \"golfing ability\" ==> " );

                Scanner scan = new Scanner( System.in );
                double golfing_ability = scan.nextDouble();
                scan.skip("\n");  // work-around for nextDouble bug in Scanner class


                //
                // check the golfing ability and if it's out of range, set a default
                //
                if ( (golfing_ability < 0) || (golfing_ability > 1.0) )
                {
                        System.out.println( "\nSorry, I don't understand; I'll chose for you..." );
                        golfing_ability = 0.5;
                        System.out.println( "\n\nYou'll be hitting with ability: "
                                          + golfing_ability + " that of Tiger Woods." );
                }


                //
                // generate a random number for the magnitude of the vertical offset
                //
                Random generator = new Random();
                double vertical_offset = generator.nextFloat();


                //
                // generate a random number for the sign of the vertical offset;
                // if vertical_offset is zero, we want it to look like "0", not "-0"
                //
                int up_or_down = generator.nextInt(2); // 0 (down) or 1 (up)
                if ( up_or_down == 0 && vertical_offset != 0 )
                {
                        up_or_down = -1;
                }


                //
                // combine the vertical offset factors (sign and magnitude)
                //
                vertical_offset = up_or_down * vertical_offset; // meters


                //
                // range length will is: max 330 yards
                // generate a random number for the...
                // magnitude of the horizontal offset (distance to target)
                //
                final double meters_per_yard = 0.9144;
                int yards_to_target = 30 + generator.nextInt(301); // 30 to 330
                int meters_to_target = (int) (yards_to_target * meters_per_yard);


                //
                // club-face angles (loft)
                //
                final double w1a = 13.0; // 14.0 degrees; real club loft: 10.0
                final double w3a = 15.0; // 19.5 degrees; real club loft: 15.0
                                        
                final double i3a = 16.5; // 24.0 degrees; real club loft: 21.0
                final double i4a = 17.5; // 26.0 degrees; real club loft: 24.0
                final double i5a = 19.0; // 28.0 degrees; real club loft: 27.0
                final double i6a = 20.5; // 31.0 degrees; real club loft: 31.0
                final double i7a = 22.5; // 35.0 degrees; real club loft: 35.0
                final double i8a = 25.0; // 42.0 degrees; real club loft: 39.0
                final double i9a = 28.0; // 45.0 degrees; real club loft: 43.0


                //
                // club maximum yardages 
                // (as expected by Tiger Woods)
                //
                final double w1my = 300; // yards
                final double w3my = 265; // yards

                final double i3my = 240; // yards
                final double i4my = 227; // yards
                final double i5my = 213; // yards
                final double i6my = 200; // yards
                final double i7my = 187; // yards
                final double i8my = 173; // yards
                final double i9my = 160; // yards


                //
                // club swing-speed coefficients
                // (maximum yardage as compared with the 1 wood)
                //
                final double w1ssc = (double) w1my/w1my; // 1.00
                final double w3ssc = (double) w3my/w1my; // 0.88

                final double i3ssc = (double) i3my/w1my; // 0.80
                final double i4ssc = (double) i4my/w1my; // 0.76
                final double i5ssc = (double) i5my/w1my; // 0.71
                final double i6ssc = (double) i6my/w1my; // 0.67
                final double i7ssc = (double) i7my/w1my; // 0.62
                final double i8ssc = (double) i8my/w1my; // 0.58
                final double i9ssc = (double) i9my/w1my; // 0.53


                //
                // reveal the target
                //
                DecimalFormat Dfmt2 = new DecimalFormat( "0.##" );
                String target = "target is " + meters_to_target + " meters ("
                              + yards_to_target + " yards) away,\n"
                              + "and " + Dfmt2.format(vertical_offset) + " meters "
                              + "in height, relative to your position.";

                System.out.println( "\n\nThe " + target );


                //
                // club selection question... if it's out of range, set a default
                //
                System.out.println( "\n-----------------------\n"
                                  + " YOUR CLUBS...\n"
                                  + "--------+-------+------\n"
                                  + " club   | angle | code\n"
                                  + "--------+-------+------\n"
                                  + " 1 wood |  " + w1a + " |  1w\n"
                                  + " 3 wood |  " + w3a + " |  3w\n"
                                  + "--------+-------+------\n"
                                  + " 3 iron |  " + i3a + " |  3i\n"
                                  + " 4 iron |  " + i4a + " |  4i\n"
                                  + " 5 iron |  " + i5a + " |  5i\n"
                                  + " 6 iron |  " + i6a + " |  6i\n"
                                  + " 7 iron |  " + i7a + " |  7i\n"
                                  + " 8 iron |  " + i8a + " |  8i\n"
                                  + " 9 iron |  " + i9a + " |  9i\n" );

                System.out.print( "\nPlease enter the code of the club you want to use ==> " );
                String club_code = scan.nextLine();


                //
                // given the club selection, prepare the club...
                //
                String club_name = "";
                double club_angle = 0.0;
                double club_swing_speed_coefficient = 1.0;

                if ( club_code.equals( "1w" ) ) {
                        club_name = "1 wood";
                        club_angle = w1a;
                        club_swing_speed_coefficient = w1ssc;
                } else if ( club_code.equals( "3w" ) ) {
                        club_name = "3 wood";
                        club_angle = w3a;
                        club_swing_speed_coefficient = w3ssc;
                } else if ( club_code.equals( "3i" ) ) {
                        club_name = "3 iron";
                        club_angle = i3a;
                        club_swing_speed_coefficient = i3ssc;
                } else if ( club_code.equals( "4i" ) ) {
                        club_name = "4 iron";
                        club_angle = i4a;
                        club_swing_speed_coefficient = i4ssc;
                } else if ( club_code.equals( "5i" ) ) {
                        club_name = "5 iron";
                        club_angle = i5a;
                        club_swing_speed_coefficient = i5ssc;
                } else if ( club_code.equals( "6i" ) ) {
                        club_name = "6 iron";
                        club_angle = i6a;
                        club_swing_speed_coefficient = i6ssc;
                } else if ( club_code.equals( "7i" ) ) {
                        club_name = "7 iron";
                        club_angle = i7a;
                        club_swing_speed_coefficient = i7ssc;
                } else if ( club_code.equals( "8i" ) ) {
                        club_name = "8 iron";
                        club_angle = i8a;
                        club_swing_speed_coefficient = i8ssc;
                } else if ( club_code.equals( "9i" ) ) {
                        club_name = "9 iron";
                        club_angle = i9a;
                        club_swing_speed_coefficient = i9ssc;
                } else {
                        System.out.println( "\nSorry, I don't understand; I'll chose for you..." );
                        // maybe here generate two random numbers...
                        // one for wood or iron, and one for club number
                        club_name = "5 iron";
                        club_angle = i5a;
                        club_swing_speed_coefficient = i5ssc;
                }


                //
                // remind the user what club they've selected, and its properties
                //
                System.out.println( "\n\nYou'll be hitting with a " + club_name
                                  + ", which will hit\nyour ball at an angle of "
                                  + club_angle + " degrees above the ground." );


                //
                // swing strength question...
                //
                System.out.println( "\n---------------------\n"
                                  + " SWING STRENGTHS...\n"
                                  + "---------------+-----\n"
                                  + " Gentle swing  | 0.1\n"
                                  + " Half strength | 0.5\n"
                                  + " Let it rip!!! | 1.0\n" );

                System.out.println( "\nHow hard do you want to swing the " + club_name + "?\n" );
                System.out.println( "Remember that the " + target );
                System.out.print( "\nPlease enter a number, between 0.1 and 1.0,\n"
                                + "corresponding to how you want to swing the club ==> " );
                double swing_strength = scan.nextDouble();
                scan.skip("\n");  // work-around for nextDouble bug in Scanner class


                //
                // check the swing strength input and if it's out of range, set a default
                //
                if ( (swing_strength < 0) || (swing_strength > 1.0) )
                {
                        System.out.println( "\nSorry, I don't understand; I'll chose for you..." );
                        swing_strength = 0.5;
                }


                //
                // calculate the initial speed of the ball
                //
                // conversion: 0.277777 m/s in 1 km/hr
                // 33.00 m/s == 120 km/hr (Average Golfer)
                // 58.06 m/s == 209 km/hr (Tiger Woods, with 1 wood)
                double max_club_speed_by_super_pro = 58.06;
                double ball_elacticity_coefficient = 1.35;
                
                double initial_speed = max_club_speed_by_super_pro
                                     * club_swing_speed_coefficient
                                     * Math.sqrt( golfing_ability )
                                     * Math.sqrt( swing_strength )
                                     * ball_elacticity_coefficient;


                //
                // tell the user how fast their club choice and swing strength will
                // launch the ball
                //
                DecimalFormat Dfmt1 = new DecimalFormat( "0.#" );
                System.out.println( "\n\nSwinging the " + club_name + " with "
                                  + swing_strength + " strength, will launch the ball "
                                  + Dfmt1.format(initial_speed) + " m/s." );


                //
                // calculate the initial velocity (speed in the x and y direction)
                //
                double club_angle_in_radians = club_angle * Math.PI / 180;
                double vix = initial_speed * Math.cos( club_angle_in_radians );
                double viy = initial_speed * Math.sin( club_angle_in_radians );


                //
                // setup the quadratic equation coefficients
                //
                final double acceleration_of_gravity = -9.81; // at the surface of Earth
                double a = 0.5 * acceleration_of_gravity;
                double b = viy;
                double c = -1 * vertical_offset;


                //
                // quadratic equation calculation
                //
                double discriminant = Math.pow(b, 2) - (4 * a * c);
                //double time1 = ((-1 * b) + Math.sqrt(discriminant)) / (2 * a);
                double time2 = ((-1 * b) - Math.sqrt(discriminant)) / (2 * a);


                //
                // tell the user the ball's flight time
                //
                System.out.println( "Your ball's flight time: "
                                  + Dfmt2.format(time2) + " seconds");


                //
                // calculate and report the distance to the landing
                //
                double hit_distance = vix * time2;  // distance to first touch
                System.out.println( "Distance to where your ball first hit the ground: "
                                  + Dfmt2.format(hit_distance) + " meters ("
                                  + Dfmt2.format(hit_distance / meters_per_yard) + " yards)" );


                //
                // calculate and report a random extra bounce in (meters)
                //
                int randomBounce = generator.nextInt(6);  // at most 5 meters
                System.out.println( "Your ball bounced an extra: " + randomBounce + " meters!" );


                //
                // calculate the distance away from target
                //
                meters_to_target -= hit_distance;
                meters_to_target -= randomBounce;
                System.out.println( "Meters left to target: "
                                  + Dfmt2.format(meters_to_target) + " meters ("
                                  + Dfmt2.format(meters_to_target / meters_per_yard) + " yards)" );


                //
                // if target achieved or overshot, say something...
                //
                if ( meters_to_target == 0 ) {
                        System.out.println( "\nAmazing!\n" );
                } else if ( meters_to_target < 0 ) {
                        System.out.println( "\nOvershot!\n" );
                }
        }
}
