Mach einen BackFlip für ais523!

16

Diese Herausforderung ist ein Preis für ais523 für den Gewinn der Kategorie " Rookie of the Year " in " Best of PPCG 2016 ". Herzliche Glückwünsche!


BackFlip ist eine esoterische Programmiersprache des Benutzers ais523 , der weit über 30 weitere interessante Esolangs erstellt hat .

BackFlip ist eine 2D-Sprache wie Befunge oder > <>, bei der der Anweisungszeiger ein Textgitter (das Programm) durchläuft und sich je nach aktiviertem Zeichen nach oben, unten, links und rechts bewegt. Kritisch ist, dass sich das Raster in einem BackFlip-Programm beim Durchlaufen ändert, ähnlich wie bei Langton's Ant .

Bei dieser Herausforderung können Sie davon ausgehen, dass ein BackFlip-Programm immer ein rechteckiges Textgitter ist (alle Zeilen sind gleich lang), das mindestens 1 × 1 groß ist und nur die Zeichen enthält ./\<>^V. ( .dient eher der Sichtbarkeit als dem Raum.) Semantisch ist der hier verwendete BackFlip identisch mit der ursprünglichen Spezifikation .

Der Anweisungszeiger (IP) in BackFlip beginnt immer links von der oberen linken Ecke des Programms und zeigt nach rechts. Es gibt drei Arten von Befehlen:

  1. .ist ein No-Op. Die IP fährt in der Richtung fort, in die sie ging. Das No-Op bleibt ein No-Op.

  2. /und \sind Spiegel. Sie reflektieren die IP in der durch ihren Winkel angegebenen Richtung und wechseln dann in den anderen Spiegeltyp .

    • Wenn zum Beispiel die IP-Köpfe nach links in a zeigen \, bewegt sie sich nach oben anstatt nach links und \wird zu a /.
  3. <, >, ^, Und Vsind Pfeile. Sie leiten die IP in die Richtung um, in die sie zeigen, und verwandeln sich dann in einen Pfeil, der in die Richtung zeigt, aus der die IP stammt (entgegen der Richtung, in die sich die IP bewegt hat) .

    • Wenn sich die IP beispielsweise nach unten >bewegt, beginnt sie, sich nach rechts und nicht nach unten zu bewegen, und >wird zu einem, ^weil dies die Richtung ist, aus der die IP stammt.

Ein BackFlip-Programm wird beendet, wenn sich die IP außerhalb der Grenzen bewegt, dh das Raster verlässt. Es stellt sich heraus, dass alle BackFlip-Programme irgendwann enden, weil Endlosschleifen unmöglich sind. (Sie können davon ausgehen, dass dies der Fall ist.)

Ihr Ziel bei dieser Herausforderung ist es, ein Programm oder eine Funktion zu schreiben, die ein BackFlip-Programm aufnimmt und die Anzahl der Bewegungen ausgibt, die der Befehlszeiger ausführt, bevor das Programm beendet wird. Das heißt, wie viele Schritte unternimmt die IP, um ein Programm auszuführen? Dies beinhaltet den ersten Schritt auf das Gitter und den letzten Schritt davon.

Zum Beispiel macht der Befehlszeiger 5 Schritte im Trivialraster ....:

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

So die Ausgabe ....heißt 5.

Im komplexeren 4 × 2-Raster

\...
\.><

Die IP verlässt das Raster in ihrem neunten Schritt. Die Ausgabe lautet also 9:

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

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

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

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

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

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

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

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

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

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

Der kürzeste Code in Bytes gewinnt.

Falls gewünscht, können Sie Eingaben als ein Array von Zeilen oder eine Matrix von Zeichen anstelle einer mehrzeiligen Zeichenfolge verwenden, aber Sie müssen die Zeichen verwenden ./\<>^V(keine Ganzzahl-Opcodes). Sie können statt des .gewünschten Leerzeichens auch Leerzeichen verwenden . Es ist in Ordnung, wenn Zeichen wie \in der Eingabe maskiert werden müssen. Ausgabe ist immer eine ganze Zahl mehr als eins.

Testfälle

....
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
Calvins Hobbys
quelle
1
Es ist so schade, dass Sie keine BackFlip-Lösung für dieses
Problem finden
Verwirrt über die Spiegel ... dreht / dreht die Richtungen wie links => oben und oben => links?
Officialaimm
1
@officialaimm Wenn Sie von links nach oben /gehen, wird die IP nach oben /gehen, und wenn Sie nach oben gehen, wird die IP nach rechts gehen, als ob es ein Ball wäre, der von einer Wand abprallt. (Aber denken Sie an die /Änderungen an Backslash, nachdem die IP es berührt.)
Calvins Hobbys
warum ist '\\' <LF> '\ /' 7 statt 6?
Dienstag,

Antworten:

3

JavaScript (ES6), 158 Byte

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

Entwickelt unabhängig von @ tshs Antwort, obwohl auffallend ähnlich.

Die Zuordnung von Richtungen ^<v>zu Ganzzahlen 0-3 wird von der Tatsache bestimmt, dass .search('^')0 zurückgegeben wird, da ^es sich um ein reguläres Zeichen handelt.

Neil
quelle
Ich fühle mich so gut geschlagen. Ich war am Ende ziemlich verwirrt, bis mir klar wurde, dass x und y im Vergleich zu dem, was ich erwartet hatte, gedreht wurden.
Ørjan Johansen
@ ØrjanJohansen Das ist ein guter Punkt; Vielleicht sollte ich x mit y überall tauschen, um es einfacher zu verstehen.
Neil
2

Haskell , 333 325 Bytes

BEARBEITEN:

  • -8 Bytes: fPointfree gemacht und eingebunden in b.

bNimmt eine Liste von Strings und gibt ein zurück 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))

Probieren Sie es online!

Wie es funktioniert

  • C aDieser Datentyp wird verwendet, weil Haskell nicht zulässt, dass ein Typ rekursiv ist, ohne ihn explizit zu deklarieren. Cist auch ein Wrapping-Konstruktor und cdie entsprechende Unwrapping-Funktion. Es wird nur mit verwendet a=[Int].
    • Der Typ C [Int]repräsentiert einen Zellenbefehl als eine Funktion, die ein direction ( [Int]) - Argument annimmt und ein Paar aus einer neuen Richtung und einem neuen C [Int]Wert zurückgibt .
  • bist die Hauptfunktion. Es konvertiert jedes Zeichen in einen CWert und ruft dann auf #.
    • g ist das Gitter als Liste von Zeichenfolgen.
    • Da \escape-Zeichen und damit das längste zu erwähnende Zeichen sein müssen, wird dessen Ergebnis stattdessen als Standardwert für die Listensuche verwendet.
  • #Führt die Hauptsimulation aus, prüft Grenzen &und generiert neue Gitter mit ?. [y,x]ist die aktuelle Position, ddie aktuelle Richtung und gdas aktuelle Raster. [f,e]ist die nächste Richtung und nist ein Paar davon und das nächste Gitter.
  • l&iprüft, ob der Index ifür die Liste außerhalb der Grenzen liegt l. (Es kehrt Truefür außerhalb der Grenzen zurück, da dies eine Dummy-Guard-Bedingung in vermeidet #.)
  • Wenn f(l!!i)==(d,x), (f?i)l==(d,m)wo mdie Liste lmit dem ite Elemente ersetzt mit x.
    • Technisch gesehen (?i)handelt es sich um eine allgemeinere Linse, die sich auf das i-te Element einer Liste konzentriert und in diesem Fall mit der Funktionsinstanz verwendet wird (,) [Int].
  • n ist die Funktion, die einen Punkt darstellt.
  • a vist eine Funktion, die einen Pfeil in Richtung darstellt v.
  • m sist eine Funktion, die einen Spiegel darstellt; s==1für \\und s==-1für /.
Ørjan Johansen
quelle
1

JavaScript, 172 Byte

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

Aber ich kann den letzten Testfall nicht testen, da auf meinem Computer ein Stapelüberlauf aufgetreten ist. (sollte funktionieren, wenn es eine Maschine mit größerem RAM gibt)

Wir verwenden eine Nummer für die Richtung:

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

Sei ddie Richtungszahl ...

  • wenn wir ein '/' treffen, brauchen wir d = 3 - d;
  • wenn wir ein '\' treffen, brauchen wir d = d ^ 1;
  • Wenn wir ein '^ <V>' treffen, brauchen wir d = '^ <V>'. indexOf (note)

Lassen Sie (x, y)aktuelle Position sein, die nächste Position ist: x+(t&1&&t-2),y+(~t&1&&t-1)

Hinweis:

Die Funktion nimmt einen Parameter mit folgendem Format an:

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

Teste es hier

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>

tsh
quelle
Nur um zu dokumentieren, ich bekomme Uncaught RangeError: Maximum call stack size exceededmit 16GB RAM.
Zeb McCorkle
1
@ZebMcCorkle aha, finde heraus, dass "use strict" und einige varDeklarationen den letzten Testfall bestehen (js-Interpreter optimiert Tail Call im Strict-Modus)
tsh
1

C 232 221 Bytes

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);}

Übernimmt die Eingabe im ersten Argument und gibt das Ergebnis aus. Erfordert, dass die Eingabe mindestens eine neue Zeile enthält. (Wenn also nur eine Zeile vorhanden ist, muss diese mit einer neuen Zeile enden.)

Anwendungsbeispiel:

./backflip '....
';

Nervenzusammenbruch:

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
}
Dave
quelle
1

Python 3 , 286 Bytes

[f () nimmt Eingaben in der Form von an, {(0,0):'/',(0,1):'.'}daher habe ich auch eine Funktion g () geschrieben, um ein Array von Zeilen in diese Form umzuwandeln]

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

Probieren Sie es online!

officialaimm
quelle