Playing Billiards
Python 2.7, 352 344 281 bytes
from math import*
def l(a,b,n):
a*=1.;b*=1.
r=set()
for i in range(1,n+3):
t=[]
for k in range(1,i):
for h in[0,.5]:
x=(i-k-h)
if 1-(x/k in r):r.add(x/k);t+=(x*a,k*b),
d=(a*n+1)**2+(b*n+1)**2
for x,y in t:
if x*x+y*y<d:d=x*x+y*y;o=degrees(atan(y/x))
return o
- -16 bytes thanks to @Dschoni
Explanation: instead calculating the cushions hits, I'm adding n tables and taking the new holes as valid :
Black border/holes is the original, green border/holes is the valid for n=1, red border/holes is the valid for n=2 and so on.
Then I remove the invalid holes (e.g. the blue arrow for n=1). I'll have a list of valid holes and their coordinates, then I calculate their distance from initial point, and then the angle of the smaller distance.
Notes:
a=4.76, b=3.64, n=27 - give 52.66286, trying to figure out why fixed, and saved 8 bytes in the process =D
a=43, b=21, n=10005 - takes ~80 seconds (but gives the right angle)
readable version:
from math import *
def bill(a,b,n):
a=float(a)
b=float(b)
ratios = set()
for i in range(0,n+2): # Create the new boards
outter = []
j=i+1
for k in range(1,j): # Calculate the new holes for each board
#y=k
for hole_offset in [0,0.5]:
x=(j-k-hole_offset)
if (x/k) not in ratios:
ratios.add(x/k)
outter.append((x*a,k*b))
min_dist = (a*n+1)**2+(b*n+1)**2
for x,y in outter:
if x*x+y*y<min_dist:
min_dist = x*x+y*y
min_alpha=degrees(atan(y/x))
return min_alpha
Haskell, 133 117 bytes
This is my implementation:
With a 2x1 table, a path will hit exactly n cushions before going into a pocket if: (x-1)/2 + (y-1) == n and x,y are mutually primes. where x,y are the distance of the ball over horizontal/vertical axes.
Paths are the same with arbitrary table size, so we just have to update lengths and angles with (a,b) and keep the shortest. Path length is sqrt((x*a/2)^2+(y*b)^2) and angle is atan((y*b)/(x*a/2))
z=toEnum
f a b n=minimum[[z x^2+r^2,180/pi*atan(r/z x)]|x<-[1..2*n+2],y<-[n+1-div(x-1)2],r<-[2*b/a*z y],gcd x y<2]!!1