13
\$\begingroup\$

Intro

Let's play some mini-golf! The golf ball is represented by a . and the hole by a O. You want to get a hole in one on every hole, but you are not good at putting. In fact, you refuse to attempt putting diagonally! Only up, down, and to either side.

You plan to cheat by placing extra bumpers \ and / so you can put the ball in with one shot. The ball bounces off of the bumpers at right angles, as shown in this picture.

Golf

Remember to call your shot! Tell us what direction you're putting.


Holes

1: The first hole is easy, a straight shot! No bumpers needed to place here.

Input:

.         O

Output:

right
.         O

2: Another basic one, a short turn. The ball is hit off the bumper into the hole.

Input:

     .
O

Output:

left
/    .
O

or

down
     .
O    /

3: Some holes have bumpers already!

Input:

.   \O

Output:

right
.   \O
    \/

or

right
   / \
.  /\O

4: Some holes are overly complex!

Input:

    /  \  \    /
   /  . \  \  /
  /  /\/   /\ \  /
 /  /     /  \ \/
/  /   /\ \  /  \  /
\  \  /  \ \/    \/ 
      \  /          /
  /\   \//\ \      /
 /  \   /  \ \     \/
 \  /\  \  /  \     \
  \/  \  \/    \ O/  \
      /         \/

Output: (one possible solution, more exists)

down
    /  \  \    /
   /  . \  \  /
  /  /\/   /\ \  /
 /  /     /  \ \/
/  /   /\ \  /  \  /
\  \  /  \ \/    \/ 
/     \  /          /
  /\   \//\ \      /
\/  \   /  \ \     \/
 \  /\  \  /  \  /  \
  \/  \  \/    \ O/  \
      /  \      \/
                \   /

Rules

  • The input is the mini-golf hole on STDIN.
  • The output is the direction you hit the ball and the mini-golf hole with newly placed bumpers on STDOUT.
  • Existing bumpers cannot be moved.
  • You can add any number of bumpers to solve a hole.
  • Assume there are valid locations for the bumpers to be placed that will allow the course to be solved in one putt.
  • The outputted hole may be bigger than the input.
  • The input may be padded with trailing white space, but please specify in your answer if you do this.
  • The output must look correct, but can have leading or trailing white space.
  • Your program should work for any valid hole. Feel free to post your test cases too!

Scoring

This is . Your score is the number of characters in your program. Lowest score wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ I'm pretty sure the directions (up, left, right, down) are wrong in the following examples: #2 example 2 should be right, #3 example 1 should be down, and #3 example 2 should be up. Interesting challenge, though! \$\endgroup\$ – Doorknob Sep 10 '14 at 2:58
  • \$\begingroup\$ @Doorknob thanks! . is the ball you're hitting and O is the hole. I messed up on #2 example 1 but they should be good now. \$\endgroup\$ – chilemagic Sep 10 '14 at 2:59
6
\$\begingroup\$

Javascript (ES6) - 651 bytes

G=s=>{Q='\\';S=[[]];n=L=1;s.split(N='\n').map(t=>{j=S[L++]=[];l=t.length;n=n>l?n:l;k=1;t.split('').map(T=>{j[k++]=T})});S[O=L++]=[];n++;for(r=0;r<L;r++)for(c=0;c<=n;c++){v=S[r][c];if(!v)S[r][c]=' ';if(v=='.'){x=c;y=r}if(v=='o'){X=c;Y=r}}f=M=>{J=M?'.':'o';K=M?'o':'.';R=0;for(D=0;1;D++){R=D&4;D=D&3;c=e=D;g=M?X:x;h=M?Y:y;while(c!=K){c=S[h+=[-1,0,1,0][e]][g+=[0,1,0,-1][e]];e=c=='/'?(B=c,e^1):c==Q?(B=c,3-e):e;E=h*(h-O)?g*(g-n)?0:2:1;if(R&&c==' '){S[h][g]=Q;R=D=0;c=K}if(c==J||E){E&&(S[h][g]=(E+M)%2?Q:'/');H=M?E?H:(e+2)&3:D;return}}}};f(0);f(1);S[0][0]=S[O][n]='/';S[0][n]=S[O][0]=Q;return['up','right','down','left'][H]+N+S.map(t=>t.join('')).join(N)}

Creates a function G that accepts a string (golf course) as input and returns the requested putting solution. The input string may or may not have leading lines, trailing lines, and trailing whitespace. The output will not have leading or trailing whitespace.

Expanded code is:

G = s => {
    Q = '\\';
    S = [[]];
    n = L = 1;
    s.split( N = '\n' ).map( t => {
        j = S[L++] = [];
        l = t.length;
        n = n > l ? n : l;
        k = 1;
        t.split('').map( T => {
            j[k++] = T;
        } );
    } );
    S[O = L++] = [];
    n++;
    for( r = 0; r < L; r++ )
        for( c = 0; c <= n; c++ ) {
            v = S[r][c];
            if( !v )
                S[r][c] = ' ';
            if( v == '.' ) {
                x = c;
                y = r;
            }
            if( v == 'o' ) {
                X = c;
                Y = r;
            }
        }
    f = M => {
        J = M ? '.' : 'o';
        K = M ? 'o' : '.';
        R = 0;
        for( D = 0; 1; D++ ) {
            R = D & 4;
            D = D & 3;
            c = e = D;
            g = M ? X : x;
            h = M ? Y : y;
            while( c != K ) {
                c = S[h += [-1,0,1,0][e]][g += [0,1,0,-1][e]];
                e = c == '/' ? (B=c,e^1) : c == Q ? (B=c,3-e) : e;
                E = h*(h-O) ? g*(g-n) ? 0 : 2 : 1;
                if( R && c == ' ' ) {
                    S[h][g] = B;
                    R = D = 0;
                    c = K;
                }
                if( c == J || E ) {
                    E && (S[h][g] = (E+M)%2 ? Q : '/');
                    H = M ? E ? H : (e+2)&3 : D;
                    return;
                }
            }
        }
    };
    f(0);
    f(1);
    S[0][0] = S[O][n] = '/';
    S[0][n] = S[O][0] = Q;
    return ['up','right','down','left'][H] + N + S.map( t => t.join('') ).join( N );
}

The solver operates on the premise that any path from the ball (hole) will either

  1. lead back to the ball (hole) again
  2. lead to the hole (ball)
  3. exit the course

We trace the ball's path in all four directions. If we find case 3, the problem is solved. If we find case 2, we mark the ball's exit location. If all four directions result in case 1, we convert the first non-bumper space along any trajectory to a bumper (if the problem is solvable, such a space is always guaranteed to exist) and try again. The bumper we convert to will have the same type as the last bumper our trajectory encountered*. If the ball is still stuck in a loop, we repeat the process as many times as needed. If the problem is solvable, this procedure is guaranteed to eventually lead to outcome 2 or 3.

(*Note that if we simply convert to a fixed bumper [say, \], there exist extremely contrived but nevertheless possible cases where a solution exists but we will fail to find it.)

We perform a similar trace from the hole, leading to either outcome 2 or outcome 3.

If both the ball trace and hole trace result in outcome 2, we place bumpers on the periphery of the course that link the two exit points (in fact, these periphery bumpers are placed regardless of the trace outcomes, to shorten the code). This completes the solution.

Test Cases and Outputs

In

   /   \   / \ /\    
   \\      /    \  \ 
       /     / o   / 
   /   \       /     
   \   .  \  \    \\ 
       /  /     \ \  
       \          /  
           \      /  
 \ /\     /  \/  //\

Out

right
/   /               \
   /   \   / \ /\    
   \\      /    \  \ 
       /     / o   / 
   /   \       /     
   \   .  \  \    \\ 
       /  /     \ \  
       \          / /
           \      /  
 \ /\     /  \/  //\ 
\                   /

In

  / \   / /    /  \    / \  /  \\ /
\   \ /  \  // \    \   /   /\   \
/ \   // \  //   \ \   \ /  / \\ \
 \  / \    /   \  \  / / \\ / /  //
/ /   /\ \\ //  / \   /  \ / \\ \ \
\   \  \ \ // \ /  /    \ \  /  / /
/ \ /   /  / \     / \ /\   /  \  /
\ /\  //\   .\  \ \ //\ /  \  / \ /
/ \/ \ /\ //\   /   \   / o// \ / \
/   / \    / \ / \\ / \   / \   \ \
/ /   / \  / \ //   \    / \/  /\/
   / \   / \  /   \\  / \    /\ / \
/ \/   \   /   \/  \   /  \    /\\
/ /\\ //\  / \  /\ /\   /  / \ / \/

Out

left
/                                   \
   / \   / /    /  \    / \  /  \\ / 
 \   \ /  \  // \    \   /   /\   \  
 / \   // \  //   \ \   \ /  / \\ \  
  \  / \    /   \  \  / / \\ / /  // 
 / /   /\ \\ //  / \   /  \ / \\ \ \ 
 \   \  \ \ // \ /  /    \ \  /  / / 
 / \ /   /  / \     / \ /\   /  \  / 
 \ /\  //\   .\  \ \ //\ /  \  / \ / 
 / \/ \ /\ //\   /   \   / o// \ / \ 
 /   / \    / \ / \\ / \   / \   \ \ 
 / /   / \  / \ //   \    / \/  /\/  
    / \   / \  /   \\  / \    /\ / \ 
 / \/   \   /   \/  \   /  \    /\\  
 / /\\ //\  / \  /\ /\   /  / \ / \/ 
\         \                         /

In

/\/ \      
\  \ \     
 \ \\ \   o
  \ .\ \   
   \ / /   
    \ /    

Out

down
/   \      /\
 /\/\\       
 \ \\ \      
  \ \\ \   o 
   \ .\ \    
    \ / /    
     \ /     
\           /
\$\endgroup\$
  • \$\begingroup\$ Fails on this test case: "/\\/\\\n\\.//\n// \\\n\\/ \no \\/" \$\endgroup\$ – Anders Kaseorg May 20 '16 at 4:21

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.