17
\$\begingroup\$

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!

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – Gareth
    Commented Apr 20, 2014 at 6:52
  • \$\begingroup\$ Well, shoot, the title of that question wasn't suspicious enough for me to check it. Sorry about that. \$\endgroup\$
    – ashastral
    Commented Apr 20, 2014 at 7:08
  • \$\begingroup\$ It's okay, that question was two and a half years ago. \$\endgroup\$
    – Gareth
    Commented Apr 20, 2014 at 7:10
  • \$\begingroup\$ I suggest that in the last example, the output should be "The ball is stuck". \$\endgroup\$ Commented Apr 24, 2014 at 16:30
  • \$\begingroup\$ Does it count as the end of the month yet >.< \$\endgroup\$
    – alyx-brett
    Commented May 1, 2014 at 17:46

7 Answers 7

5
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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)
\$\endgroup\$
1
\$\begingroup\$

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$=-}/
\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

Java 11, 213 208 190 175 162 160 bytes

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

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

-5 bytes thanks to @EdgyNerd
-17 bytes thanks to @ceilingcat

Try it online.

Explanation:

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:
    if((c=(x+=" ".repeat(r+2))   //   Append trailing spaces to the line if necessary
          .charAt(r))            //   Get the character at the current index of this line
       !=46                      //   If this is NOT the first line (the char isn't a dot):
       &&(r+=c<33?               //    If the current char is a space:
              0                  //     Index `r` remains the same
             :c<48?              //    Else-if it's a '/':
              -1                 //     Index `r` is decreased by 1
             :x.charAt(r+1)==47? //    Else-if we're stuck in a `\/`:
              r/0                //     Divide by 0 to exit with an error
             :                   //    Else (it's a '\'):
              1)                 //     Index `r` is increased by 1
         <0)                     //    If `r` is now -1:
      return 0;                  //     Return 0
  return++r;}                    //  After the loop: return the index `r` + 1
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I don't know Java at all, but wouldn't causing an error be shorter than returning -1? \$\endgroup\$
    – EdgyNerd
    Commented Oct 8, 2019 at 14:23
  • \$\begingroup\$ @EdgyNerd Thanks, that indeed saves 5 bytes. :) \$\endgroup\$ Commented Oct 8, 2019 at 14:47
  • \$\begingroup\$ @ceilingcat Thanks. And been able to save a few more bytes by getting rid of the brackets by putting everything inside the ifs. \$\endgroup\$ Commented Dec 27, 2022 at 8:21
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

JavaScript (Node.js), 123 bytes

x=>(g=(i,c)=>y[j++][i]==c?g:y[j]+1?(k=y[j][i])=='/'?g(i-1,'\\'):k=='\\'?g(i+1,'/'):g(i,g):i)(x.indexOf`.`,j=0,y=x.split`
`)

Try it online!

0-index, output g if stucked

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.