为ais523做BackFlip!


16

这个挑战是奖ais523赢得了“ 年度最佳新秀类别”中的“ 最佳PPCG 2016 ”。恭喜你!


BackFlip是由ais523用户开发的一种深奥的编程语言,他已经创建了30多种其他有趣的esolang

BackFlip是一种2D语言,例如Befunge> <>,其中指令指针遍历文本网格(程序),上下移动,左右移动,并根据其所在的字符改变方向。至关重要的是,BackFlip程序中的网格在遍历时会发生变化,有点像Langton的Ant

对于此挑战,您可以假定BackFlip程序始终是文本的矩形网格(所有行的长度相同),最小大小为1×1,仅包含字符./\<>^V。(.用于可见性,而不是空间。)语义上,我们将在此处使用的BackFlip与原始规范相同。

BackFlip中的指令指针(IP)始终从程序左上角的左侧开始,一直向右移动。它可以遇到三种命令:

  1. .是无人操作。IP继续朝着前进的方向发展。无操作保持无操作。

  2. /并且\是镜子。它们沿其角度指示的方向反射IP,然后变为另一种类型的反射镜

    • 例如,如果IP头向左\移动,它将开始向上移动,而不是向左移动,然后\变为a /
  3. <>^,和V是箭头。他们将IP重定向到其指向的方向,然后变为箭头,指向IP的来源方向(与IP的移动方向相反)

    • 例如,如果IP向下进入>,则它开始向右移动而不是向下移动,并且>变为,^因为这就是IP的方向。

当IP超出范围(即脱离网格)时,BackFlip程序终止。事实证明,所有 BackFlip程序最终都会终止,因为不可能进行无限循环。(您可能认为这是真的。)

您在此挑战中的目标是编写一个程序或函数,该程序或函数接受BackFlip程序并输出指令指针在程序终止之前执行的移动次数。也就是说,IP在运行程序的过程中需要采取多少步骤?这包括进入网格的初始步骤和离开网格的最后一步。

例如,指令指针在平凡的网格中采用了5个步骤....

 ....  <- empty 4×1 grid
012345 <- step number of the IP

因此,输出....5

在更复杂的4×2网格中

\...
\.><

IP在第9步退出网格,因此输出为9

step  grid  IP position (@)
0     \...  @....
      \.><   ....

1     \...   @...
      \.><   ....

2     /...   ....
      \.><   @...

3     /...   ....
      /.><   .@..

4     /...   ....
      /.><   ..@.

5     /...   ....
      /.<<   ...@

6     /...   ....
      /.<<   ..@.

7     /...   ....
      /.><   .@..

8     /...   ....
      /.><   @...

9     /...   ....
      \.><   ....
             @

以字节为单位的最短代码获胜。

如果需要,您可以将输入作为行或字符矩阵的数组,而不是多行字符串,但是必须使用字符./\<>^V(而不是整数操作码)。您可以使用空格代替,.如果需要的话。如果\需要在输入中转义这样的字符,这很好。输出始终是一个大于1的整数。

测试用例

....
5

\...
\.><
9

.
2

..
3

.
.
2

\
2

^
2

.^.
3

<.
2

\\
\/
7

>V
^<
6

>\
>/
6

\><
2

\><
\><
7

\><
\><
\><
12

\.V.
\.\<
5

\.V.
\./<
9

V./\
V./\
>./<
..\/
14

\V..
.^..
\/><
.V..
.^..
20

\.V.V.
\./.\<
.>\<..
..^.^.
31

\.V.V.V.
\./>/.\<
.>\>\<..
..^.^.^.
69

\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.
145

\.V.V.V.V.V.V.V.V.V.V.
\./>/>/>/>/>/>/>/>/.\<
.>\>\>\>\>\>\>\>\>\<..
..^.^.^.^.^.^.^.^.^.^.
9721

1
真可惜,您不能为此提供BackFlip解决方案...
HyperNeutrino

对镜子感到困惑... /是否将方向翻转为left => up和up => left ,?
Officialaimm'4

1
@officialaimm从左侧进入/将使IP上升,而向上进入/将使IP正确,就好像它是从墙上弹起的球一样。(但请记住/IP接触到反斜杠后所做的更改。)
卡尔文的爱好

为什么'\\'<LF>'\ /'是7而不是6?
tsh

Answers:


3

JavaScript(ES6),158个字节

f=(a,x=0,y=0,d=3)=>a[x]&&(c=a[x][y])?(a[x][y]=c=='.'?c:c=='/'?(d^=3,'\\'):c=='\\'?(d^=1,'/'):'v>^<'[d][d='^<v>'.search(c),0],f(a,d<3?x+d-1:x,d?y+d-2:y,d)+1):1

尽管与@tsh的答案非常相似,但它们是独立开发的。

方向^<v>到整数0-3 的映射受以下事实支配:.search('^')由于^是正则表达式元字符,因此返回0 。


我感觉好厉害。最后我感到很困惑,直到我意识到x和y与我期望的相比被翻转了。
与Orjan约翰森

@ØrjanJohansen很好。也许我应该到处将x与y互换以使其更容易理解。
尼尔

2

Haskell333325字节

编辑:

  • -8个字节:f无点并合并为b

b接受Strings 的列表并返回Integer

data C a=C{c::a->(a,C a)}
b g=[0,0]#([0,1],map(maybe(C$m 1)C.(`lookup`zip"./^>V<"[n,m(-1),a[-1,0],a[0,1],a[1,0],a[0,-1]]))<$>g)
[y,x]#(d,g)|g&y||g!!0&x=1|n@([f,e],_)<-(($d).c)?x?y$g=1+[y+f,x+e]#n
l&i=i<0||i>=length l
(f?i)l|(p,a:r)<-splitAt i l=(p++).(:r)<$>f a
n d=(d,C n)
a v d=(v,C$a$(0-)<$>d)
m s[d,e]=([s*e,s*d],C$m(-s))

在线尝试!

怎么运行的

  • C a是使用的数据类型,因为Haskell不允许在未明确声明的情况下递归类型。C还是包装构造函数,并且c是其对应的展开函数。仅与一起使用a=[Int]
    • 类型C [Int]代表一个单元格命令,它是一个使用direction([Int])参数的函数,并返回一对新的方向和一个新的C [Int]值。
  • b是主要功能。它将每个字符转换为一个C值,然后调用#
    • g 是作为字符串列表的网格。
    • 以来 \需要转义,因此最长的字符也需要转义,因此将其结果用作列表查找的默认值。
  • #运行主要仿真,使用检查边界,&并使用生成新网格?[y,x]是当前位置d当前方向和g当前网格。[f,e]是下一个方向,n是一对方向和下一个网格。
  • l&i检查索引i是否超出列表的范围l。(它返回True超出范围,因为这避免了中的虚拟警卫条件#。)
  • 何时f(l!!i)==(d,x),列表(f?i)l==(d,m)在哪里mlith替换th元素x
    • 从技术上讲,它(?i)是一个更通用的镜头,着眼于列表的第i个元素,在这种情况下,与(,) [Int]函子实例一起使用。
  • n 是代表点的函数。
  • a v 是代表方向箭头的函数 v
  • m s是代表镜子的功能;s==1\\s==-1/

1

JavaScript,172个字节

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

但是我无法测试最后一个测试用例,因为我的机器上出现堆栈溢出。(如果有一台更大的滑枕的机器应该工作)

我们使用数字作为方向:

  • 0:^
  • 1:<
  • 2:V
  • 3:>

d是方向数...

  • 如果满足'/',则需要d = 3-d;
  • 如果遇到'\',则需要d = d ^ 1;
  • 如果遇到'^ <V>'我们需要d ='^ <V>'。indexOf(note)

(x, y)是当前位置,下一个位置是:x+(t&1&&t-2)y+(~t&1&&t-1)

注意:

该函数采用以下格式的一个参数:

[ [ '\\', '.', 'V', '.', 'V', '.', 'V', '.', 'V', '.' ],
  [ '\\', '.', '/', '>', '/', '>', '/', '.', '\\', '<' ],
  [ '.', '>', '\\', '>', '\\', '>', '\\', '<', '.', '.' ],
  [ '.', '.', '^', '.', '^', '.', '^', '.', '^', '.' ] ]

在这里测试

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

    ;k=x=>x.split('\n').map(t=>t.split(''));
<textarea id=v>\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.</textarea><br/><button onclick="r.textContent=f(k(v.value))">Solve</button>
<p>Result: <output id=r></output></p>


只是为了说明一下,我的Uncaught RangeError: Maximum call stack size exceeded内存为16GB。
Zeb McCorkle '04

1
@ZebMcCorkle啊哈,只是发现“使用严格”和一些var声明使其通过了最后一个测试用例(js解释器以严格模式进行了尾调用优化)
tsh

1

C,232个 221字节

d,n,t,m[4]={1,-1};char*w="><^V/\\.",*P;main(o,v)char**v;{for(P=v[1],m[2]=-(m[3]=strchr(P,10)-P+1);P>=v[1]&&P<strchr(v[1],0)&&*P^10;++n)*P=w[((o=d,t=strchr(w,*P)-w)<4)?d=t,o^1:(t<6)?d^=t-2,9-t:6],P+=m[d];printf("%d",n+1);}

在第一个参数中接受输入,打印结果。要求输入至少包含1个换行符(因此,如果只有1行,则必须以换行符结尾)

用法示例:

./backflip '....
';

分解:

d,                                          // Direction
n,                                          // Step counter
t,
m[4]={1,-1};                                // Movement offsets
char*w="><^V/\\.",                          // Command lookup
*P;                                         // Cursor location
main(o,v)char**v;{
    for(P=v[1],                             // Begin at 0,0
        m[2]=-(m[3]=strchr(P,10)-P+1);      // Find width of grid
        P>=v[1]&&P<strchr(v[1],0)&&*P^10;   // While inside grid:
        ++n)                                //  Increment step
        *P=w[                               //  Update the current cell
            ((o=d,t=strchr(w,*P)-w)         //  (store current direction & command)
              <4)?d=t,o^1:                  //   If <>^V, write backflip & set dir
            (t<6)?d^=t-2,9-t:               //   If / or \, write flip & bounce
            6],                             //   If ., write unchanged & continue
        P+=m[d];                            //  Move
    printf("%d",n+1);                       // Print result
}

1

Python 3,286字节

[f()以形式输入,{(0,0):'/',(0,1):'.'}所以我还写了一个函数g(),用于将线数组转换为该形式]

def f(r):
 x=y=0;d='>';s=1
 while 1:
  try:c=r[y,x];m='>^<V'.find(d)
  except:break
  if(c=="\\"):d='V<^>'[m];r[y,x]="/"
  elif(c=="/"):d='^>V<'[m];r[y,x]="\\"
  elif(c!="."):r[y,x]='<V>^'[m];d=c
  x+=1if(d=='>')else-1if(d=='<')else 0;y+=1if(d=='V')else-1if(d=='^')else 0;s+=1
 return s

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.