18
\$\begingroup\$

This is a mini golf hole:

The outer boundary is a circle with radius 10 and center (0,0). The inner boundary is a circle with radius 3 and center (0,5). The tee is at (0,-8). Assume the ball is just a point with radius 0.

The dynamics of the ball are governed by the following rules:

  • The ball is initially hit with energy 50, and with a given angle.

    • The angle is in degress in the Cartesian coordinate system, so 0° means directly to the right, 90° is directly up, and so on.
  • When the ball hits the edge of the inner or outer circle, it bounces off the circle using the law of reflection.

    • The angle of collision with the circle at that point is equal to the angle of reflection. (Here angles are relative to the tangent line of the circle at the point of collision.)

    • For clarification, see this or this (in the notation of the second link, R_0 = 0 in this challenge.)

  • The ball loses energy as it moves.

    • For every unit of ground it covers, it loses 1 unit of energy.

    • Every time it bounces off a wall it loses 5 units of energy.

  • The ball stops either when it runs out of energy or when it falls into the hole.

    • If the ball hits a wall with <= 5 units of energy, it stops.

    • It falls into the hole if it has energy < 10 when it is within distance 1 of the hole, otherwise it keeps moving.

Challenge

Given the x-y coordinates of a hole, return an angle at which that you can hit the ball in order for the ball to fall into the hole (if such an angle exists).

Input

Take as input the x- and y-coordinates of the center of the hole in any convenient form. Input may be taken from STDIN (or closest alternative), command line parameters, or function arguments.

Output

Print or return an angle in degrees at which the ball can be hit from the tee such that the ball will fall into the hole. If such an angle exists, the output should be in the range [0, 360), otherwise the output should be -1.

\$\endgroup\$
  • \$\begingroup\$ You might want to specify how the x and y values should be read (standard input, function argument etc.). \$\endgroup\$ – Loovjo Jul 18 '15 at 20:22
  • \$\begingroup\$ What should be returned if no such angle exists? \$\endgroup\$ – Alex A. Jul 20 '15 at 20:58
  • \$\begingroup\$ Let's specify that the function will return a value in [0,360) if there is a solution, and return -1 otherwise. \$\endgroup\$ – Eric Brooks Jul 20 '15 at 21:57
  • \$\begingroup\$ I made a couple of edits. If it doesn't match your intent, please roll back the edit. \$\endgroup\$ – Alex A. Jul 21 '15 at 17:22
  • \$\begingroup\$ Also, could you provide at least one test case? \$\endgroup\$ – Alex A. Jul 21 '15 at 17:26
4
\$\begingroup\$

C, 415 430

EDIT: Like @Winny mentioned, exit values above 255 aren't possible, so I had to increase this code size in order to print values up to 360.

Assumes 2 (and only 2) command-line inputs (x y) as ints. Answer in degrees is printed or -1 if no degree exists.

#include <math.h>
#define E(z) {if((e-=5)<0)break;q=n/sqrt(n*n+pow(m-z,2));w=(m-z)/sqrt(n*n+pow(m-z,2));d=(t=d)*(1-2*q*q)-2*f*q*w;f=f*(1-2*w*w)-2*t*q*w;}
main(a,v)char**v;{float D=.01,e,d,f,n,m,p=.0174,q,t,w;a-=4;while(++a<360){n=0,m=-8,d=D*cos(a*p),f=D*sin(a*p),e=50;while(e>0){if((pow(n-atoi(v[1]),2)+pow(m-atoi(v[2]),2)<1)&(e<10)&&printf("%d",a))return;n+=d,m+=f,e-=D;if(n*n+m*m>100)E(0)if(n*n+pow(m-5,2)<9)E(5)}}puts("-1");}

Ex.

>./golfed 0 2; echo $?
90
>./golfed 0 10; echo $?
0
>./golfed -2 -7; echo $?
12

First time golfer; could probably be improved quite a bit. If we need to have more precision, I have a version that takes in x y and returns the angle with doubles working with .01 degree precision at 449 chars.

Readable version:

#include <math.h>
int main(int argc, char** argv)
{
    // p is roughly pi/180 and q, t, and w are temp vars
    float Delta=.01, energy, delta_x, f(delta_y), n(cur_x), m(cur_y), p=.0174, q, t, w;
    argc -= 4; /*using argc as int for angle*/
    // iterate through each degree
    while (++argc < 360)
    {
        n=0, m=-8, d=D*cos(a*p), f=D*sin(a*p), e=50;
        // then move in discrete .01 steps
        while (e > 0)
        {
            // check to see if we're inside the hole
            if ((pow(n-atoi(v[1]),2) + pow(m-atoi(v[2]),2) < 1) 
                & (e<10) && printf("%d",a)) return;
            // move forward
            n += d, m += f, e -= D;
            // check if we've hit the outer wall
            if (n * n + m * m > 100)
            {
                // if too slow, finish this iteration
                // if not, find reflection vector
                if ((e -= 5) < 0) break;
                q = n / sqrt(n * n + pow(m,2));
                w = (m) / sqrt(n * n + pow(m,2));
                d = (t = d) * (1 - 2 * q * q) - 2 * f * q * w;
                f = f * (1 - 2 * w * w) - 2 * t * q * w;
            }
            // check inner wall collision
            if (n * n + pow(m - 5,2) < 9)
            {
                // if too slow, finish this iteration
                // if not, find reflection vector
                if ((e -= 5) < 0) break;
                q = n / sqrt(n * n + pow(m - 5,2));
                w = (m - 5) / sqrt(n * n + pow(m - 5,2));
                d = (t = d) * (1 - 2 * q * q) - 2 * f * q * w;
                f = f * (1 - 2 * w * w) - 2 * t * q * w;
            }
        }
    }
    // if an angle not found, return -1
    puts("-1");
}
\$\endgroup\$
  • \$\begingroup\$ I don't think you can return values larger than 255 via exit(code). Tested on Linux and FreeBSD via echo 'int main(){return 300;}' > test.c && cc test.c && ./a.out; echo $?. \$\endgroup\$ – Winny Jul 28 '15 at 2:36

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.