Where will the ball land?

17

4

Given a string where the first line contains spaces and one period (., the "ball"), followed by lines containing spaces, forward slashes (/), and backslashes (\), determine what column the ball will land in after falling from its starting position. Each / moves it to the left by 1 column and each \ moves it to the right by 1 column.

Sample input

    .
  /   \  \
    /   /
 \   \/  \
   \   /\
    \ /\  \
     \    /

Sample output

The ball starts in column 5, hits the / on line 3, then the three \'s on lines 5 through 7 for a final position of:

7

Note that columns are 1-indexed, mostly for consistency with text editor conventions.

Edge cases

If the ball hits a / in the first column, it's eternally stuck in the nonexistent column 0. Your program should handle this correctly by printing 0.

If the ball hits either side of a \/ pattern, the result is undefined. Your program is permitted to terminate with no output, loop infinitely, or print an error message (my solution prints -1), but it must not print anything that can be perceived to be valid output.

If the ball hits the left slash in a \\ pattern, it should end up directly beneath the right slash, not to the right of it. The solution I originally envisioned was prone to getting this wrong, so don't go down that path!

There may or may not be spaces after the . or the last / or \ on each line. Your program should not rely on such padding being available. On a similar note, there may or may not be any lines following the first line.

You may assume that the first line will have zero or more spaces and exactly one .. Subsequent lines, if any, will have zero or more spaces and zero or more slashes.

Implementation details

Your program may read from a file (specified as a command-line argument) or read from standard input, at your convenience.

Your program must output a single number to standard output. (Yes, a trailing newline is fine. Yes, the number may have more than one digit.)

Test cases

Input:

.

Output:

1

Note that the input here is exactly one byte. This is the smallest case you should be able to handle.

 

Input:

 .
 \
  \
   \
    \

Output:

 6

Note that there are no spaces after these slashes.

 

Input:

  .
  /
 /\\  /  \
//\ \/// //
\\/ \/\ /\/

Output:

0

 

Input:

  .
/ / /
 \\\
  /\\
 /   \

Output:

1

 

Input:

   .


 \
       /
/

      \

Output:

4

 

Input:

 .
 \

\/\/\/

Output:

(anything but a nonnegative number)

Closing remarks

This question is similar to Simulate a (gravity-based) billiard-ball-type computer, but significantly simpler, so hopefully it will gain more interest.

I have a 169-character solution in Python. I'm sure the talented golfers here can tear that record to pieces, though. :^)

This is , so the shortest answer in characters will be accepted at the end of the month!

Fraxtil

Posted 2014-04-20T06:01:01.417

Reputation: 2 495

It's also very similar to A Mere Bagatelle with a slightly different import format and only one throw. You can borrow and modify my test scripts if you want.

– Gareth – 2014-04-20T06:52:33.037

Well, shoot, the title of that question wasn't suspicious enough for me to check it. Sorry about that. – Fraxtil – 2014-04-20T07:08:18.267

It's okay, that question was two and a half years ago. – Gareth – 2014-04-20T07:10:36.873

I suggest that in the last example, the output should be "The ball is stuck". – Mukul Kumar – 2014-04-24T16:30:50.273

Does it count as the end of the month yet >.< – alexander-brett – 2014-05-01T17:46:57.257

Indeed it does. – Fraxtil – 2014-05-01T22:18:16.497

Answers

5

Python, 143B

import sys
for l in sys.stdin:
 a=l.find('.')
 if a>-1:F=a
 elif F>-1: 
    if'\\/'in l[F-1:F+2]:z
    F+={'\\':1,'/':-1}.get((l+' '*F)[F],0)
print F+1

Using the space/tab indentation trick. I haven't done anything particularly clever here. F is the current index, l is the current line; z is undefined so it throws an exception, which is definitely not a positive integer, handling the \/ situation.

alexander-brett

Posted 2014-04-20T06:01:01.417

Reputation: 1 485

2

05AB1E, 37 bytes

¶¡ð«ć'.ksvU…/ \yXD>‚èJD„\/Qiõqëнk<X+]>

Input as a multi-line string. Outputs \/ if the ball is stuck.

Try it online or verify all test cases.

Explanation:

¶¡                       # Split the (implicit) input-string on newlines
                         # (work-around instead of `|`, because it will stop at empty lines)
  ð«                     # Add a trailing space to each line (work-around because indexing
                         # -1 in 05AB1E will wrap around to the other side)
    ć                    # Extract head; pop and push the remainder-lines and first line
                         # separated to the stack
     '.k                '# Get the 0-based index of "." in this first line
s                        # Swap to get the remainder-list of lines
v                        # Loop over each line `y`:
 U                       #  Pop and store the top value (the index) in variable `X`
       X                 #  Push the current index `X`
        D>               #  Duplicate it, and increase the copy by 1
          ‚              #  Pair to [X, X+1]
      y    è             #  Index both of those into the current line `y`
            JD           #  Join the two characters together, and duplicate it
              „\/Qi      #  If it's equal to "\/":
                   q     #   Stop the program
                         #   (after which the string is output implicitly as result)
                  ë      #  Else:
                   н     #   Only leave the first character (at index `X`)
  …/ \              k    #   Get its 0-based index in string "/ \"
                     <   #   Decrease it by 1
                      X+ #   And add it to `X`
]                        # After the loop:
 >                       # Increase the top of the stack (`X`) by 1
                         # (after which it's output implicitly as result)

Kevin Cruijssen

Posted 2014-04-20T06:01:01.417

Reputation: 67 575

1

CJam, 61 bytes

qN/('.#)\_:,0+:e>f{' e]" /"f#0\+}{1$1$=\@2$-_@=@[\]$[W1]#/z}/

If the rule regarding \/ is lifted (and we are not required to handle it), this can be shortened to 41 bytes:

qN/('.#)\_:,:e>f{' e]" /"f#0\+0+}{1$=-}/

Esolanging Fruit

Posted 2014-04-20T06:01:01.417

Reputation: 13 542

1

Java 10, 213 208 190 bytes

s->{int r=s.indexOf('.'),c;for(var x:s.split("\n")){for(;r>x.length()-2;x+=" ");c=x.charAt(r);if(c==46)continue;r/=c>47&x.charAt(r+1)==47?0:1;r+=c<33?0:c<48?-1:1;if(r<0)return 0;}return-~r;}

Throws a division by zero error when we are stuck inside a \/.

-5 bytes thanks to @EdgyNerd.

Explanation:

Try it here.

s->{                             // Method with String parameter and integer return-type
  int r=s.indexOf('.'),          //  Get the index of the dot on the first line
      c;                         //  Temp integer
  for(var x:s.split("\n")){      //  Split the input by newlines, and loop over the lines:
    for(;r>x.length()-2;x+=" "); //   Append trailing spaces if necessary
    c=x.charAt(r);               //   Get the character at the current index of this line
    if(c==46)                    //   If this is the first line (the char is the dot)
      continue;                  //    Continue to the next iteration of the loop
    r/=c>47&x.charAt(r+1)==47?   //   If we're stuck in a `\/`
        0                        //    Divide by 0 to exit the function with an error
       :1;                       //   Else: divide by 1 as no-op
    r+=c<33?                     //   If the current character is a space:
        0                        //    `r` remains at the same index
       :c<48?                    //   Else if it's a `/`:
        -1                       //    Index `r` is decreased by 1
       :                         //   Else (if it's a `\`):
        1;                       //    Index `r` is increased by 1
    if(r<0)                      //   If `r` is now -1:
      return 0;}                 //    Return 0
  return-~r;}                    //  After the loop: return the index `r` + 1

Kevin Cruijssen

Posted 2014-04-20T06:01:01.417

Reputation: 67 575

2I don't know Java at all, but wouldn't causing an error be shorter than returning -1? – EdgyNerd – 2019-10-08T14:23:29.233

@EdgyNerd Thanks, that indeed saves 5 bytes. :) – Kevin Cruijssen – 2019-10-08T14:47:15.913

1

Python 3, 124 bytes

import sys
for l in sys.stdin:i=('.'in l)*l.find('.')or(i<0)*i-2*('\\/'in l[i-1:i+2])or' \\'.find((l+i*' ')[i])+i
print(i+1)

Try it online!

Also works in Python 2.

Explanation

for l in sys.stdin:i=          # Change value i for each line in the input
('.'in l)*l.find('.')          # Set i to (0-indexed) dot position if present
or(i<0)*i                      # Keep i fixed if it is below zero
-2*('\\/'in l[i-1:i+2])        # Set i to -2 if \/ trap is encountered
or' \\'.find((l+i*' ')[i])+i   # Else: move position based on character
print(i+1)                     # Print final 1-indexed position

Jitse

Posted 2014-04-20T06:01:01.417

Reputation: 3 566

0

J, 95 bytes

[:>[:(<"1@|.@}.([:(1&{+_*0>[:*/2-/\])(]+{~ ::])^:(<3))&.>/@,2<@i.~{.)[:(0,'/ \'<:@i.]);._1 LF,]

Try it online!

Returns infinity _ when the ball gets stuck. Lost many bytes handling that special case. Otherwise it's more or less a simple reduction of the rows. Could surely be golfed further.

Jonah

Posted 2014-04-20T06:01:01.417

Reputation: 8 729