ais523のBackFlipを実行してください!


16

この課題は、のための賞であるais523のための勝利新人王」のカテゴリを「PPCG 2016のベスト」。おめでとう!


BackFlipは、ユーザーais523によって作成された難解なプログラミング言語です。ais523は、他にも30以上の興味深いesolangを作成してます。

BackFlipはBefunge> <>のような2D言語で、命令ポインターがテキストのグリッド(プログラム)を横断し、上、下、左、右に移動し、文字に応じて方向を変えます。重大なことに、BackFlipプログラムのグリッドは、ラングトンのAntのように、移動中に変化します。

この課題では、BackFlipプログラムは常にテキストの長方形のグリッド(すべての行が同じ長さ)で、サイズが少なくとも1×1で、文字のみを含むと想定できます./\<>^V。(.スペースではなく、可視性のために使用されます。)ここで使用するBackFlipは、意味的には元のspecと同じです。

BackFlipの命令ポインター(IP)は、常にプログラムの左上隅のすぐ右から始まります。遭遇する可能性のあるコマンドには3つのタイプがあります。

  1. .ノーオペレーションです。IPは、進行方向に進みます。ノーオペレーションはノーオペレーションのままです。

  2. /\ミラーです。それらは、角度で示される方向にIPを反射し、その後、他のタイプのミラーに変わります。

    • たとえば、IPが左に向かう場合、\左ではなく上方向に動き始め、はに\なります/
  3. <>^、およびV矢印です。IPを指し示す方向にリダイレクトし、IPが来た方向(IPが動いていた方向とは反対)を指す矢印に変わります。

    • たとえば、IPが下に向かう場合、IPは下>ではなく右に移動し始めます。これは、IPの方向で>ある^ためです。

BackFlipプログラムは、IPが範囲外に移動すると、つまりグリッドから外れると終了します。それは結局のところ、すべての無限ループが不可能であるため、バク転プログラムが最終的に終了します。(これは真実であると仮定できます。)

この課題の目標は、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(整数オペコードではなく)を使用する必要があります。.必要に応じてスペースを使用できます。\入力のような文字をエスケープする必要がある場合は問題ありません。出力は常に複数の整数です。

テストケース

....
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

ミラーについて混乱しています...方向を左=>上および上=>左として反転しますか?
officialaimm

1
@officialaimm左からヘディングで/IPを上げ、ヘッディングで/IPを右に動かします。まるで壁から跳ね返るボールのようです。(ただし/、IPに触れた後のバックスラッシュへの変更を思い出してください。)
カルビンの趣味

なぜ '\\' <LF> '\ /'は6ではなく7なのですか?
tsh

回答:


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 を返すという事実によって管理されます^


私はとてもbeatられたように感じます。私が予想したものと比較してxとyが反転していることに気付くまで、私はそこで最後にかなり混乱しました。
Ørjanヨハンセン

@ØrjanJohansenそれは良い点です。わかりやすくするために、どこでもxとyを交換する必要があるかもしれません。
ニール

2

Haskell333 325バイト

編集:

  • -8バイト:fポイントフリーにし、にマージしましたb

bのリストを取り、Stringを返します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 aHaskellは明示的に宣言せずに型を再帰的にすることを許可しないため、使用されるデータ型です。Cまた、ラッピングコンストラクターでcあり、対応するアンラッピング関数です。でのみ使用されa=[Int]ます。
    • このタイプC [Int]は、方向([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)どこmリストであるliに置き換え番目の要素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)

注意:

この関数は、次の形式の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 exceeded16GBのRAMで取得しています。
ゼブマコークル

1
@ZebMcCorkle aha、「use strict」といくつかのvar宣言が最後のテストケースをパスすることを確認してください(jsインタープリターはstrictモードで末尾呼び出しを最適化します)
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

オンラインでお試しください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.