13
\$\begingroup\$

Given a list of hole yardages, green sizes, a slice angle and a max distance, compute a golf score.

Assumptions

  • Earth is flat
  • All greens are circular
  • Slice angle will be between -45 and 45 degrees and will be given in degrees
  • All distances in the same metric (yards or meters, doesn't matter)
  • No out of bounds, obstructions or doglegs
  • Max score on any hole is 8
  • All shots travel the lesser of max distance or distance to the hole, in a direction defined by the angle to the hole plus the slice angle.
  • Distance is measured as the straight line or Euclidean distance between the start and end point.
  • Max distance and slice angle are the same for all shots on all holes
  • The golfer always two-putts once on the green (or exactly on the edge of the green).

Example

Let's look at the hacker from the test case #5 below for hole #2. The hacker can hit the ball 320 yards, but always slices 30 degrees. If we assume without loss of generality that the tee box is at {0,0} and the green is at {497,0}, then he will hit shots to the following points, arriving on the green with the 7th shot:

{{0.,0.},{277.128,-160.},{547.543,-131.372},{569.457,7.67088},{502.872,37.2564},{479.159,7.92741},{490.646,-7.85868},{500.078,-4.22987}}

At this point, his score would be 9 due to the two putts required, so the final score for him gets capped at 8, per the assumptions.

Graphically, it will look like this: enter image description here

Test Cases

All the test cases have standard 18-hole courses

Case#1
{MaxDistance->280,SliceAngle->10,HoleDistances->{181,368,161,416,158,526,377,427,509,148,405,443,510,494,396,388,483,172},GreenDiameters->{26,18,17,23,27,23,21,23,25,21,19,24,21,23,25,24,22,22}}
Scores: 
{4,5,4,5,4,5,5,5,5,4,5,5,5,5,5,5,5,4}
Output: 85

Case#2 (same course as Test Case #1, shorter more accurate golfer)
{MaxDistance->180,SliceAngle->5,HoleDistances->{181,368,161,416,158,526,377,427,509,148,405,443,510,494,396,388,483,172},GreenDiameters->{26,18,17,23,27,23,21,23,25,21,19,24,21,23,25,24,22,22}}
Scores:
{4,5,4,5,4,6,5,5,6,4,5,5,6,6,5,5,5,4}
Output: 89

Case#3 (Same golfer as test case #1, shorter course)
{MaxDistance->280,SliceAngle->10,HoleDistances->{147,497,110,528,409,118,196,154,134,514,374,491,131,138,523,478,481,494},GreenDiameters->{32,16,36,25,32,20,30,30,33,29,25,26,26,25,33,28,21,28}}
Scores:
{4,5,4,5,5,4,4,4,4,5,5,5,4,4,5,5,5,5}
Output: 82

Case#4 (Same course as test case #3)
{MaxDistance->180,SliceAngle->5,HoleDistances->{147,497,110,528,409,118,196,154,134,514,374,491,131,138,523,478,481,494},GreenDiameters->{32,16,36,25,32,20,30,30,33,29,25,26,26,25,33,28,21,28}}
Scores:
{3,6,3,6,5,4,4,3,3,5,5,5,3,3,5,5,6,5}
Output: 79

Case#5 (Hacker)
{MaxDistance->320,SliceAngle->30,HoleDistances->{147,497,110,528,409,118,196,154,134,514,374,491,131,138,523,478,481,494},GreenDiameters->{32,16,36,25,32,20,30,30,33,29,25,26,26,25,33,28,21,28}}
Scores:
{6,8,5,8,7,6,6,6,6,8,8,8,6,6,8,8,8,8}
Output: 126

Rules

  • Any format can be used for the input. Output is simply the number of simulated strokes, so should be an integer.
  • This is so the shortest answer in bytes wins. Standard loopholes apply.
\$\endgroup\$
  • 4
    \$\begingroup\$ Why is "the Earth is flat" under assumptions? \$\endgroup\$ – Jo King Jan 22 '18 at 21:54
  • \$\begingroup\$ Can we assume that it will never take more than 6 shots to get the ball to within MaxDistance of the hole? \$\endgroup\$ – ETHproductions Jan 22 '18 at 21:59
  • 1
    \$\begingroup\$ @JoKing Mainly, so that plane rather than spherical geometry is used; secondly because there was no need to assume spherical chickens :) \$\endgroup\$ – Kelly Lowder Jan 22 '18 at 21:59
  • \$\begingroup\$ @ETHproductions, well you could but that's unnecessary. I think maybe you mean GreenDiameter/2, in which case yes, since score is capped at 8 and there are always 2 putts. \$\endgroup\$ – Kelly Lowder Jan 22 '18 at 22:02
  • \$\begingroup\$ Don't worry, I worded that question how I meant it ;-) My technique which relies on this doesn't seem to be anywhere near as short as my current answer though, so never mind I guess... \$\endgroup\$ – ETHproductions Jan 22 '18 at 22:04
10
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ This looks pretty solid. Could you please post a TIO link when you have a chance? \$\endgroup\$ – Kelly Lowder Jan 22 '18 at 21:54
  • 1
    \$\begingroup\$ @KellyLowder Sure, done. \$\endgroup\$ – ETHproductions Jan 22 '18 at 22:08
  • 2
    \$\begingroup\$ Wouldn't your final equation be a direct consequence of the law of cosines? \$\endgroup\$ – LegionMammal978 Jan 22 '18 at 22:54
  • \$\begingroup\$ @LegionMammal978 I guess it would... Sorry, my trigonometry is a little rusty :P \$\endgroup\$ – ETHproductions Jan 22 '18 at 23:00
  • 1
    \$\begingroup\$ @kamoroso94 That might be a good idea. Using .0174533 gives an error of just 2.38e-7 on the cosine of 45 degrees, so it might be negligible enough to work. Actually now that I look at it, 71/4068 (= 355/113 / 180) is even better, giving an error of just 4.135e-10... \$\endgroup\$ – ETHproductions Jan 23 '18 at 18:15
3
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.