## Global constants # Gravity accelaration (F/S^2) ~= 32 G = 32 # Used to indent the plotting of ball positions # so that the height digits don't affect # where we start plotting ball positions BALL_PLOT_INDENT = "\t" # The deviation between current plotted height and the actual # height of the ball that we will accept to plot the ball in # that plotted height BALL_PLOT_DEVIATION = 0.25 # The step we will take as we move down vertically while # plotting ball positions BALL_PLOT_HEIGHT_STEP = 0.5 ## Helper functions # Calculates the bounce speed (up) of the ball for a given # bounce number and coefficient def calc_velocity_for_bounce(v0, bounce, coefficient) v = v0 * coefficient**bounce end # Check https://physics.stackexchange.com/a/333436 for nice explanation def calc_bounce_total_time(v0, bounce, coefficient) v = calc_velocity_for_bounce(v0, bounce, coefficient) t = 2 * v / G end # Check https://physics.stackexchange.com/a/333436 for nice explanation def calc_ball_height(v0, bounce, coefficient, t) v = calc_velocity_for_bounce(v0, bounce, coefficient) h = v * t - 0.5 * G * t**2 end def heighest_position_in_next_bounce(time_in_bounce, v0, i, c) time_in_next_bounce = time_in_bounce[i+1] return -1 if time_in_next_bounce.nil? return calc_ball_height(v0, i, c, time_in_next_bounce / 2) unless time_in_next_bounce.nil? end def intro puts <<~INSTRUCTIONS BOUNCE CREATIVE COMPUTING MORRISTOWN, NEW JERSEY THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION COEFFICIENCY (LESS THAN 1). YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN 'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY). INSTRUCTIONS end ## Plottin functions def plot_header puts puts "FEET" end def plot_bouncing_ball(strobbing_time, v0, c) ## Initializing helper values # How many bounces we want to plot # original BASIC version is 70 / (V / (16 * S2)) # 70 is assumed to be an arbitrary number higher than 2G and 16 is 1/2G bounces_to_plot = (G**2 / (v0 / strobbing_time)).to_i # Holds the total time the ball spends in the air in every bounce time_in_bounce = bounces_to_plot.times.map { |i| calc_bounce_total_time v0, i, c } plot_width = 0 # Calculate the highest position for the ball after the very first bounce plotted_height = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i ## Plotting bouncing ball while plotted_height >= 0 do # We will print only whole-number heights print plotted_height.to_i if plotted_height.to_i === plotted_height print BALL_PLOT_INDENT bounces_to_plot.times { |i| (0..time_in_bounce[i]).step(strobbing_time) { |t| ball_pos = calc_ball_height v0, i, c, t # If the ball is within the acceptable deviation # from the current height, we will plot it if (plotted_height - ball_pos).abs <= BALL_PLOT_DEVIATION then print "0" else print " " end # Increment the plot width when we are plotting height = 0 # which will definitely be the longest since it never gets # skipped by line 98 plot_width += 1 if plotted_height == 0 } if heighest_position_in_next_bounce(time_in_bounce, v0, i, c) < plotted_height then # If we got no more ball positions at or above current height in the next bounce, # we can skip the rest of the bounces and move down to the next height to plot puts break end } plotted_height -= BALL_PLOT_HEIGHT_STEP end # Return plot_width to be used by the plot_footer plot_width end def plot_footer (plot_width, strobbing_time) # Dotted separator line puts print BALL_PLOT_INDENT (plot_width).times { |_| print "." } puts # Time values line print BALL_PLOT_INDENT points_in_sec = (1 / strobbing_time).to_i plot_width.times { |i| if i % points_in_sec == 0 then print (i / points_in_sec).to_i else print " " end } puts # Time unit line print BALL_PLOT_INDENT (plot_width / 2 - 4).to_i.times { |_| print " " } puts "SECONDS" puts end def game_loop # Read strobing, velocity and coefficient parameters from user input puts "TIME INCREMENT (SEC)" strobbing_time = gets.to_f puts "VELOCITY (FPS)" v0 = gets.to_f puts "COEFFICIENT" c = gets.to_f # Plotting plot_header plot_width = plot_bouncing_ball strobbing_time, v0, c plot_footer plot_width, strobbing_time end ## Entry point begin intro loop do game_loop end rescue SystemExit, Interrupt exit rescue => exception p exception end