13
\$\begingroup\$

In races in which racers go around at least one turn of a curved track, the starting positions for each racer are staggered, so that each racer travels the same distance around the track (otherwise, the racer in the innermost lane would have a huge advantage).

Given the lengths of the major and minor axes (or semi-major and semi-minor, if you'd prefer) of an elliptical track and the number of lanes in the track, output the distances from the innermost lane's starting point that each lane should be staggered.

Specifications

  • Each lane is an ellipse with semi-major axes 5 units longer than the next-shortest lane. For simplicity, assume that the lanes have 0 width.
  • The innermost lane always starts at 0, and every other starting point is a positive integer greater than or equal to the previous starting point.
  • Input and output may be in any convenient and reasonable format.
  • The inputs will always be integers.
  • You must calculate the circumference of the track to within 0.01 units of the actual value.
  • Outputs are to be rounded down to the nearest integer (floored).
  • The finish line is the starting point for the innermost racer. There is only one lap in the race.
  • The lengths of the axes are measured using the innermost lane of the track.
  • Outputting the 0 for the innermost lane's offset is optional.

Test Cases

Format: a, b, n -> <list of offsets, excluding innermost lane>

20, 10, 5 -> 30, 61, 92, 124
5, 5, 2 -> 31
15, 40, 7 -> 29, 60, 91, 121, 152, 183
35, 40, 4 -> 31, 62, 94

These test cases were generated with the following Python 3 script, which uses an approximation of the circumference of an ellipse devised by Ramanujan:

#!/usr/bin/env python3

import math

a = 35 # semi-major axis
b = 40 # semi-minor axis
n = 4  # number of lanes
w = 5  # spacing between lanes (constant)

h = lambda a,b:(a-b)**2/(a+b)**2
lane_lengths = [math.pi*(a+b+w*i*2)*(1+3*h(a+w*i,b+w*i)/(10+math.sqrt(4-3*h(a+w*i,b+w*i)))) for i in range(n)]

print("{}, {}, {} -> {}".format(a, b, n, ', '.join([str(int(x-lane_lengths[0])) for x in lane_lengths[1:]])))

The approximation used is:

ellipse circumference approximation

Finally, here is a helpful diagram for understanding the calculations of the offsets:

track

\$\endgroup\$
3
  • \$\begingroup\$ I use Ramanujan's approximation like you did. Is that what we're supposed to do, or do you want us to evaluate the convergence of the infinite series? \$\endgroup\$
    – Adám
    Aug 22, 2016 at 8:04
  • 1
    \$\begingroup\$ @Adám You can do whatever it takes to get the required precision. The Ramanujan approximation is good for many values because its error is on the order of h**5, which is well under 0.01 for a wide range of values. \$\endgroup\$
    – user45941
    Aug 22, 2016 at 8:05
  • \$\begingroup\$ What good is a minimum accuracy when there is no bound on the input size? \$\endgroup\$
    – feersum
    Aug 22, 2016 at 15:23

4 Answers 4

2
\$\begingroup\$

Haskell, 103 98 bytes

c!d|h<-3*d*d/c/c=pi*c*(1+h/(10+sqrt(4-h)))
f a b n|x<-a-b=[floor$(a+b+10*w)!x-(a+b)!x|w<-[1..n-1]]
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 43 bytes

UVFXY-nXY+WZn/3*©T4®-t+/>Z*žq*5DX+UY+V})¬-ï

Explanation

UV                                           # X = a, Y = b
  F                                   }      # n times do
   XY-n                                      # (a-b)^2
       XY+W                                  # Z = (a + b)
             /                               # divide (a-b)^2
           Zn                                # by (a+b)^2
              3*                             # multiply by 3
                ©                            # C = 3h
                       /                     # 3h divided by 
                 T                           # 10
                      +                      # +
                  4®-t                       # sqrt(4-3h)
                        >                    # increment
                         Z*žq*               # times (a + b)*pi
                              5DX+UY+V       # increase a and b by 5
                                       )     # wrap in list of circumferences
                                        ¬-   # divide by inner circumference
                                          ï  # floor
                                             # implicitly display

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Python 3, 168 164 bytes

Thanks to @Adám and @Mego for -2 bytes each

from math import*
h=lambda a,b:3*(a-b)**2/(a+b)**2;C=lambda a,b:pi*(a+b)*(1+h(a,b)/(10+sqrt(4-h(a,b))))
f=lambda a,b,n:[int(C(a+i*5,b+i*5)-C(a,b))for i in range(n)]

A function f that takes input via argument and returns a list of lane offsets, including 0 for the innermost lane.

How it works

This uses Ramanujan's approxiamtion. We simply define functions h and C for calculating the parameter and circumference, then subtract the length of the innermost lane from the length of the current lane and floor, for all lanes.

Try it on Ideone

\$\endgroup\$
5
  • \$\begingroup\$ sqrt(4-3*h(a,b)) is shorter as (4-3*h(a,b))**.5, and floor can be replaced by int. Doing both of those means you don't need to import math. \$\endgroup\$
    – user45941
    Aug 22, 2016 at 8:23
  • \$\begingroup\$ @Mego Thanks. Unless I'm being stupid, aren't those first two the same length? However, if the import statement gets removed, there is then the problem of defining pi. \$\endgroup\$ Aug 22, 2016 at 8:27
  • \$\begingroup\$ By including the the 3* in h, you should save two bytes. \$\endgroup\$
    – Adám
    Aug 22, 2016 at 8:28
  • \$\begingroup\$ I totally missed that you use pi You might be able to hardcode it with enough precision. And yeah, the first two are the same length - I meant without the import, of course! :P \$\endgroup\$
    – user45941
    Aug 22, 2016 at 8:29
  • \$\begingroup\$ @Adám Thanks for pointing that out. \$\endgroup\$ Aug 22, 2016 at 8:29
1
\$\begingroup\$

Dyalog APL, 45 bytes

Prompts for n, then for a b. Requires ⎕IO←0 which is default on many systems.

⌊1↓(⊢-⊃)(○+×1+h÷10+.5*⍨4-h←3×2*⍨-÷+)⌿⎕∘.+5×⍳⎕

⍳⎕ prompt for n, then give {0, 1, 2, ..., n−1)

multiply by five to get {0, 5, 10, ..., 5​n−5}

⎕∘.+ prompt for a and b, then make an addition table:
  a, a+5, a+10, ... a+5​n−5
  b, b+5, b+10, ... b+5​n−5

(...)⌿ apply the parenthesised function to each vertical pair, i.e.
  f(a, b), f(a+5, b+5), f(a+10, b+10), ..., f(a+5​n−5, b+5​n−5)
  where f(x, y) is*

pi times

(x + y) times

1+ one plus

h(x, y) [the function h will be defined later] divided by

10+ ten plus

.5*⍨ the square-root of

4- four minus

h← h(x, y), which is

three times

2*⍨ the square of

(xy) divided by

+ x + y

(⊢-⊃) on the result of the function applied to each pair, subtract the value of the first result

1↓ remove the first (zero)

round down

TryAPL online!


*In procedural language:

-÷+ find the fraction of the difference between and the sum of x and y

2*⍨ square that fraction

multiply that square by three

h← assign that product to h

4- subtract that product from four

.5*⍨ take the square-root of that difference

10+ add ten to that square-root

divide h by that sum

1+ add one to that fraction

multiply that sum with the sum of x and y

multiply that product by pi

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.