Code Golf Simulated Golf

JavaScript (ES7), 128 126 bytes

(m,a,D,S,t=0)=>S.map((s,i)=>t+=(r=(f=d=>d>s/2?1+f((l=d<m?d:m,l*l+d*d-2*d*l*Math.cos(a*Math.PI/180))**.5,s):2)(D[i]))<8?r:8)&&t

Try it online!

Explanation

Because only the distance from the ball to the hole matters and not the coordinates of the ball, we can write an algorithm that calculates how close the ball gets to the hole with each shot, then run that repeatedly until the ball reaches the green. But how do we do this?

Re-using OP's helpful diagram explaining ball movement, with MS Paint modifications:

the science of golf

We have access to these numbers:

  • d, the current distance from ball to hole;
  • θ, the slice angle; and
  • l, the length of the shot (minimum of d and the max shot length).

And the goal is to find x, the distance from ball to hole after the shot is taken.

First we note that a and b are simply l cos θ and l sin θ, respectively. We can see that by the Pythagorean theorem, x can be represented as sqrt(b2 + (d-a)2). Expanding this out, we get

x = sqrt(b^2 + (d - a)^2)
  = sqrt((l*sin(θ))^2 + (d - l*cos(θ))^2)
  = sqrt((l^2 * sin^2(θ)) + (d^2 - 2*d*l*cos(θ) + l^2 * cos^2(θ))
  = sqrt(l^2 * sin^2(θ) + l^2 * cos^2(θ) + d^2 - 2dl*cos(θ))
  = sqrt(l^2 * (sin^2(θ) + cos^2(θ)) + d^2 - 2dl*cos(θ))
  = sqrt(l^2 * 1 + d^2 - 2dl*cos(θ))
  = sqrt(l^2 + d^2 - 2dl*cos(θ))

And so, the new distance from ball to hole will be sqrt(l2 + d2 - 2dl cos θ). Then we count the iterations it takes to get this distance within the radius of the green, add 2, and cap at 8 to get the final score for that hole.

(Thanks to @LegionMammal978 for pointing out that all of the calculations I made are a direct result of the law of cosines...)


Interestingly enough, when the ball is closer to the hole than its max shot, l = d and we can simplify the formula quite a bit further:

x = sqrt(l^2 + d^2 - 2dl*cos(θ))
  = sqrt(d^2 + d^2 - 2d^2*cos(θ))
  = sqrt(2d^2 - 2d^2*cos(θ))
  = sqrt(d^2(2 - 2cos(θ)))
  = d * sqrt(2 - 2cos(θ))

To find the # of remaining iterations, we could then simply find d / r (where r = the radius of the green) and divide that by sqrt(2 - 2cos(θ)), then take the ceiling of the result and add 2. Unfortunately, this doesn't seem to be as short as just finding the smaller of d and the max shot length.


Perl 5, 144 138 + 12 (-MMath::Trig) = 150 bytes

shaved a few bytes using @ETHproductions' simplification of the formula

sub p{$_=pi/180*pop;$m=pop;for$b(@_[0..17]){$s=!++$c;1while++$s<6&&$_[17+$c]/2<($b=sqrt$b*$b+($h=$m<$b?$m:$b)**2-2*$h*$b*cos);$t+=$s+2}$t}

Try it online!

Changed up the input format a bit:

Hole 1 distance
Hole 2 distance
...
Hole 18 distance
Hole 1 green diameter
...
Hole 18 green diameter
Maximum distance
Slice angle

Julia 0.6, 106 bytes

S(m,t,D,G)=(s(m,d,g,v=2)=d<=g/2?v<8?v:8:(l=d<m?d:m;s(l,(d^2+l^2-2d*l*cosd(t))^.5,g,v+1));sum(s.([m],D,G)))

Try it online!

Based on ETHproductions' answer.

Explanation

  • s(m,d,g,v=2)=... Define function s that calculates the score for one hole recursively.
  • sum(s.([m],D,G)) Apply s for each hole and sum the result. . is element-wise function application with singleton expansion. E.g.: min.([1],[2,3]) = [min(1,2), min(1,3)]
d<=g/2?v<8?v:8:(l=d<m?d:m;s(...)) #
d<=g/2?       :                   # is the ball on the green?
       v<8?v:8                    # yes -> return min(v,8)
               (l=d<m?d:m;s(...)) # no  ->
                                  # calculate new distance using ETHproductions' formula
                                  # increment current score
                                  # call s recursively