Walk the labyrinth

15

1

Or maybe it's not really a labyrinth, but still.

Rules:

  1. Input is a two-line string, consisting of *, 1, x and X. That string is a labyrinth to walk through. The lines have the equal length.

    You could take the input as a string with , (comma) or any convenient separator between these two lines. Or you could take both lines as separate arguments to your function.

  2. Output is the number of steps you have to take to exit the string (last step is the step which moves you out of the string).

  3. You start in the top left corner (the higher line), before the first symbol.

  4. For each step, you move forward by one symbol (from nth to (n+1)th position). Then, depending on the character you step on, the outcome is different. Here's what each char does:

    • * - nothing. You just step on it normally.
    • x - once you stepped on it, switch the line, but remain on the same horizontal distance from the beginning. For example, you stepped on the third position of the higher line, and met a lowercase x here. Then you immediately move to the lower line, but again at the third position.
    • X - switch the line and go to the next position. The example is the same there, but you also move from the third to the forth position (thus you're on the second line at the forth position).
    • 1 - just move forward by yet another position.

Once each character does its job, it's replaced with a space and no longer "works".

Examples follow.

  1. Input:

    x
    *
    

    As said before, you start before the first symbol of the first line. The first step moves you on letter x and this letter switches you to the second line. The letter x no longer functions as x, but replaced with *. This will be more relevant in the latter examples. You're now on an asterisk on the lower line, and it did nothing to you.

    The second step is moving you forward and you exit the string, so the labyrinth is completed, and it took 2 steps.

    Output 2.

  2. Input:

    xX*
    x1*
    

    1st step: you move on x, which moves you on the x of the lower line. Here comes the rule which says that the used character is replaced with asterisk. Then you move back on the first line, but it's no longer x there, since it has been used and became an asterisk. So you move safely on this asterisk and the step is completed (you are now on the first position of the first line).

    2nd step: you move on X, it pushes you to the lower line and then pushes you forward. You now reside on the third position of the second line (asterisk), having never visited the second position (which contains 1).

    3rd step: you move forward, exiting the string.

    Output: 3.

Test cases:

  1. Input:

    *1*
    xxx
    

    Output: 3. (because 1 makes you jump on the third position). There you never visit the second line, but it's required part of the input.

  2. Input:

    *X*1*x
    x*1xx*
    

    Output: 4.

  3. Input:

    1x1x
    ***X
    

    Output: 3.

  4. Input:

    1*x1xxx1*x
    x*x1*11X1x
    

    Output: 6.

  5. Input:

    xXXXxxx111*
    **xxx11*xxx
    

    Output: 6.

nicael

Posted 2016-07-11T19:17:36.510

Reputation: 4 585

An empty string should not be a valid input, as it's not a two line string – edc65 – 2016-07-12T10:15:18.907

@edc Haha, I'm contradicting myself. Yes, indeed. – nicael – 2016-07-12T10:22:04.720

"\n\n" is a two line string... – feersum – 2016-07-12T12:53:25.187

@feersum then I think output should be 1, as you start before the 1st line, then you move forward one step, and then you finish the labyrinth... – Amit Gold – 2016-07-18T10:58:53.343

Answers

5

Snails, 34 bytes

A^
\1r|\xud|\Xaa7},(\*|\xud=\x)r},

Expanded:

{
    {
        \1 r |
        \x ud |
        \X aa7
    },
    (\* | \x ud =\x)
    r
},

For a path that takes N steps, the program finds one successful match for each traversal of 0 steps, 1 steps, ..., N - 1 steps.

feersum

Posted 2016-07-11T19:17:36.510

Reputation: 29 566

3

Haskell, 68 66 65 bytes

(a:b)#l@(c:d)|a<'+'=1+b#d|a>'w'=l#('*':b)|a>'W'=d#b|1<2=b#d
_#_=1

Function # takes both lines as separate parameters. Usage example: "1x1x" # "***X" -> 3.

We just have to count the stars * we step on plus 1 for leaving.

(a:b)#l@(c:d)             -- bind: a -> first char of first line
                                   b -> rest of first line
                                   l -> whole second line
                                   c -> first char of second line (never used)
                                   d -> rest of second line
   |a < '+' = 1+b#d       -- stepped on a *, so add 1 and go on
   |a > 'w' = l#('*':b)   -- x switches lines and replaces the x with *
   |a > 'W' = d#b         -- X switch lines and go on
   |1<2     = b#d         -- the rest (-> 1) simply walks forward
_#_=1                     -- base case: the empty string counts 1 for leaving

Edit: @feersum saved a byte. Thanks!

nimi

Posted 2016-07-11T19:17:36.510

Reputation: 34 639

Could you probably provide a working demo (on http://ideone.com it would be convenient), I'm not a Haskell programmer but would like to play with it.

– nicael – 2016-07-11T20:41:46.187

1

@nicael: see here

– nimi – 2016-07-11T20:46:17.593

Could you use e.g. a>'a' instead of a=='x' ? – feersum – 2016-07-12T06:41:18.380

I haven't realized that, but actually empty string is invalid input (since I've stated myself that the input is a two-line string), so you could remove the validation for this edge case :) – nicael – 2016-07-12T10:26:59.467

@feersum: yes, that works. Thanks! – nimi – 2016-07-12T14:44:15.243

@nicael: checking the empty string is the base case (and therefore end) of my recursive function, so I cannot omit it. – nimi – 2016-07-12T14:45:22.560

Thanks for making me aware of the @ =) – flawr – 2016-07-12T20:33:26.283

2

JavaScript (ES6), 119

l=>{z=-~l.search`
`,l=[...l+' '];for(n=p=0;(c=l[p%=2*z])>' ';p+=c>'X'?z:c>'1'?z+1:c>'0'?1:(++n,1))l[p]='*';return-~n}

Less golfed

l=>{
  z=1+l.search`\n`;
  l=[...l+' '];
  for( n = p = 0; 
       (c=l[p%=2*z])>' '; 
       p += c>'X' ? z : c>'1' ? z+1 : c>'0'? 1 : (++n,1) )
    l[p] = '*';
  return 1+n
}

Test

f=l=>{z=-~l.search`
`,l=[...l+' '];for(n=p=0;(c=l[p%=2*z])>' ';p+=c>'X'?z:c>'1'?z+1:c>'0'?1:(++n,1))l[p]='*';return-~n}

[['x\n*',2]
,['xX*\nx1*',3]
,['*1*\nxxx',3]
,['*X*1*x\nx*1xx*',4]
,['1x1x\n***X',3]
,['1*x1xxx1*x\nx*x1*11X1x',6]
,['xXXXxxx111*\n**xxx11*xxx',6]
].forEach(t=>{
  var i=t[0],k=t[1],r=f(i) 
  console.log('Test result '+r+(r==k?' OK ':' KO (expected '+k+')')+'\n'+i)
})  
 

edc65

Posted 2016-07-11T19:17:36.510

Reputation: 31 086

2

TSQL(sqlserver 2012+), 276 bytes

Golfed:

DECLARE @i VARCHAR(99)=
'xXXXxxx111*'+CHAR(13)+CHAR(10)+
'**xxx11*xxx'

,@t BIT=0,@c INT=1,@ INT=1WHILE @<LEN(@i)/2SELECT @t-=IIF(a like'[1*]'or'xx'=a+b,0,1),@c+=IIF(a='*'or'xx'=a+b,1,0),@+=IIF(a='x'and'x'>b,0,1)FROM(SELECT SUBSTRING(d,@t*c+@,1)a,SUBSTRING(d,(1-@t)*c+@,1)b FROM(SELECT LEN(@i)/2+1c,REPLACE(@i,'X','q'COLLATE thai_bin)d)x)x PRINT @c

Ungolfed:

DECLARE @i VARCHAR(99)=
'xXXXxxx111*'+CHAR(13)+CHAR(10)+
'**xxx11*xxx'

,@t BIT=0,@c INT=1,@ INT=1
WHILE @<LEN(@i)/2
  SELECT
    @t-=IIF(a like'[1*]'or'xx'=a+b,0,1),
    @c+=IIF(a='*'or'xx'=a+b,1,0),
    @ +=IIF(a='x'and'x'>b,0,1)
  FROM
    (
      SELECT
        SUBSTRING(d,@t*c+@,1)a,
        SUBSTRING(d,(1-@t)*c+@,1)b
      FROM 
        (SELECT LEN(@i)/2+1c,REPLACE(@i,'X','q'COLLATE thai_bin)d)x
    )x

PRINT @c

Fiddle

t-clausen.dk

Posted 2016-07-11T19:17:36.510

Reputation: 2 874

1

JavaScript, 211 bytes

I'm thinking about making a version that shows each step played after each other, displayed on a webpage.

(x,y)=>{t=0;l=0;n=1;while(t<x.length){c=(l?x:y);if(c[t]=='x'){l=!l;if(l){x=x.slice(0,t-2)+'*'+x.slice(t-1);}else{y=y.slice(0,t-2)+'*'+y.slice(t-1);}}if(c[t]=='X'){l=!l;t++;}if(c[t]=='1'){return n}

Used more bytes than I'd hoped to when replacing x with * because of JS immutable Strings. Suggestions to improve are appreciated, especially with the replacement part.

charredgrass

Posted 2016-07-11T19:17:36.510

Reputation: 935