Does the fishy road have an end?

13

1

I love ><>, ><> is life! 2D langages are amazing! In this challenge, you will have to say if a "fishy" road has an end, while code-golfing.

Definition

A fishy road is constructed with tiles, including the following ones:

v (go down)
> (go right)
^ (go up)
< (go left)
/ (mirror)
\ (mirror)

Any other character (except -|+) may be considered as a distraction, like some flowers (or fish heads) on the border of the road.

A road always start on the upper-left corner of a rectangular grid, delimited by -|+symbols. The road has an end if, by following it, you end up on a border, else, you'll be trapped in an infinite path.

Finding your way on the road is accomplished by following directions given by v>^<and mirrors. A mirror will reflect by 90° depending on where you came from. Here's how it works (using v>^<to show directions):

 ^    ^
>/<  >\<
 v    v
</>  <\>
 ^    ^

A road might be looking like this if it ends:

+--------------------+
|>\/  this way >\/>  | this one ends here
| v^            \/   |
| v^   ^.^           |
| \/\         >v     |
| /\/         ^<     |
+--------------------+

An infinite loop :

+--------+
|>>\ This|
|\\   is |
|  \\ a  |
| \ /trap| 
+--------+

Specifics

A road doesn't necessarily consist only of instructions. Spaces or letters can be used to complete it. This means you have to continue moving in the same direction except if you cross a character in <v^>-|.

There will always be one of v>^< in the upper-left corner, < or ^ implies this road ends.

You may submit a function taking a string as parameter, or a standalone program using STDIN/whatever is the closest alternative in your language.

Your submission must return or print on STDOUT truthy/falsy values when it's done. Truthy values meaning the road has an end, while falsy means it is an infinite loop.

Test cases

+--------------------+
|>\/  this way >\/>  | this one ends here
| v^            \/   |
| v^   ^.^           |
| \/\         >v     |
| /\/ ><>     ^<     |
+--------------------+
    True

+--------+
|>>\ This|
|\\   is |
|  \\ a  |
| \ /trap| 
+--------+
    False

+--+
|<v|
|^<|
+--+
    True

+--+
|>v|
|^<|
+--+
    False

+----------+
|v Hello \ |
|\\/\/   / |
| \/\\   \ |
|/  // >\  |
|  ^/\>\\/ |
|\  /\/\/  |
+----------+
    False

+-----+
|>\/\\|
|//\\/|
|\/\\\|
|//\//|
|\/\/ |
+-----+
    True

2 test cases added as suggested by @MartinBüttner
+----+
|v   |
|\\  |
|//\ |
|\\v |
| \/ |
+----+
    False

+----+
|v   |
|\\  |
|//\ |
|\\^ |
| \/ |
+----+
    False

Test case inspired by @ETHproductions
+-------------------------+
|><>                      |
|something smells fishy...|
+-------------------------+
    False

Standard loopholes are forbidden (as always).

The winner will be the one with the shortest code in bytes. (it would be amazing to see a ><> answer :))

Katenkyo

Posted 2015-12-02T14:55:03.150

Reputation: 2 857

1This better get a ><> answer... – clap – 2015-12-02T16:37:49.183

@ConfusedMr_C Would put on myself if I knew this langage :/. Maybe if I find time ^^' – Katenkyo – 2015-12-02T16:42:10.723

I guess transforming the input into ><> and then calling the ><> interpreter (without including the code of that in the count) would be a loophole? – Paŭlo Ebermann – 2015-12-02T17:22:05.980

1@PaŭloEbermann For it to not be a loophole, you would need to count the character in the interpreter, or using a langage with a built-in ><> interpreter, and I don't think it exists ^^. – Katenkyo – 2015-12-03T20:44:36.053

Answers

4

JavaScript, ES6, 177 161 145 bytes

f=(s,i=1,M=[],D)=>D==5||!~M[O="indexOf"](D+i)&&f(s,i-[M.push(D+i),L=s[O]('|'),-L,1,-1][D=`431255${5-D+'X3412'[D]}`['><^v-|/\\'[O](s[i+L])]||D],M,D)

We can detect a cycle by traversing the path and detecting a repeat of the tuple

  • location
  • coming-from direction

That is, if we are entering some position (x,y) coming from some direction D for the second time, we know that this cycle will repeat forever. Therefore, the code keeps track of all locations that were visited, and from what direction, and checks against that record each time a new space is visited.

The directions up, down, left, and right are assigned the numbers 1, 2, 3, and 4. The code considers the current symbol being visited (s[i+L]) and changes the current direction (D), then the new direction is used to recursively call the function and evaluate the next space. 5 as a direction indicates a wall, and a true termination of the program.

Here is an explanation of less-golfed code:

f=
(s,     // input string
 i=1,   // current location as offset string index
 M=[],  // record of previously visited spaces
 D      // current direction
  )=>(
    L=s[O="indexOf"]('|'), // find arena width `L` by index of first `|`

    // if D is 5, return true, or...
    D==5 ||

    // if direction + position is not new, return false
    !~M[O](D+i) &&

    // otherwise, save this direction + position
    M.push(D+i) &&

    // recursively call `f` with new direction and position
    f(s,
      i-[,L,-L,1,-1][D=            // modify position based on active direction
        `431255${5-D+'X3412'[D]}`  // from these possible directions...
          [                        // chose the one at the index...
            '><^v-|/\\'[O](        // based on the index of the symbol 
                           s[i+L]  // of the current character
                                 )
          ]
        ||D     // or preserve old D if symbol is not directional
      ],
      M,D)

The template string `431255${5-D+'X3412'[D]}` has a nested expression that handles the mirrors: because the directions are numbers, they can also be used as indexes. The expression 'X3412'[D], evaluates to the 8th character in the possible-direction string, and so corresponds to \, the 8th character in the symbol string '><^v-|/\\'). The expression says,

  • If current direction D is 1 (up), then the new direction on hitting a \ mirror will be 3 (left)
  • If current direction D is 2 (down), then the new direction on hitting a \ mirror will be 4 (right)
  • etc.

The other mirror / would use the expression 'X4321'[D], but since that's simply an ordered count-down from 4, we can express it more simply as 5-D.

apsillers

Posted 2015-12-02T14:55:03.150

Reputation: 3 632

5

Non-compliant ><> answer

You wanted ><>, I give you ><> !

I believe the only sane way to do this in ><> is by copying the input in the codespace and letting the interpreter decide by itself if the input leads somewhere. Since ><> doesn't implement threading anymore, that leaves us with a big problem : if the input has a loop, we'll get stuck into it.

These considerations taken into account, I decided to make a solution compatible with ><> online interpreter so that it would be possible to assert if the interpreter is stuck in the input or just taking ages to do everything. I also had to add trailing lines to the code so the online interpreter shows the added code and doesn't crash when trying to write to it.

Oh and since I'm clearly disqualified by now, I didn't bother with golfing the code.

Without further ado, the code in all its glory :

50i:0(?v   :"^"=?v:"v"=?v:">"=?v:"<"=?v:"/"=?v:"\"=?v:"|"=?v:"-"=?va=?v1+10.
>.!603f<         v"."~                                     <      <   >~1+010.
>.!01+1p}:$}:}v! <      <      <      <      <      <
  ;oooo"true" <<
              ^

To use it, copy it in the online interpreter, add enough trailing lines to handle your input, submit the code, give it the input as ;-separated lines and enjoy the ride.

A few tests :

With

+--------------------+
|>\/  this way >\/>  | this one ends here
| v^            \/   |
| v^   ^.^           |
| \/\         >v     |
| /\/         ^<     |
+--------------------+` 

Final codespace :

50i:0(?v   :"^"=?v:"v"=?v:">"=?v:"<"=?v:"/"=?v:"\"=?v:"|"=?v:"-"=?va=?v1+10.
>.!603f<         v"."~                                     <      <   >~1+010.
>.!01+1p}:$}:}v! <      <      <      <      <      <
  ;oooo"true" <<
            ^
 ....................
.>\/           >\/>  .                   
. v^            \/   .
. v^   ^ ^           .
. \/\         >v     .
. /\/         ^<     .
 ....................

Outputs "true" and stops.


With

+--------+
|>>\ This|
|\\   is |
|  \\ a  |
| \ /trap| 
+--------+

Final codespace :

50i:0(?v   :"^"=?v:"v"=?v:">"=?v:"<"=?v:"/"=?v:"\"=?v:"|"=?v:"-"=?va=?v1+10.
>.!603f<         v"."~                                     <      <   >~1+010.
>.!01+1p}:$}:}v! <      <      <      <      <      <
  ;oooo"true" <<
            ^
 ........ 
.>>\     .
.\\      .
.  \\    .
. \ /    .
 ........

Loops forever.

Aaron

Posted 2015-12-02T14:55:03.150

Reputation: 3 689

Even if it isn't compliant, I love your source ! Thanks for this entry ! It is sad that it loops forever when the it should be falthy, but good job anyway ^^. – Katenkyo – 2015-12-03T20:48:40.460

I updated the online fish interpreter. It now supports multiline input – Suppen – 2015-12-05T18:46:48.097

@Suppen Hey, nice ! Thanks for the increased max speed too ! – Aaron – 2015-12-07T14:02:30.280