Brainf * ckish Richtungen

14

Ihre Aufgabe besteht darin, ein Programm zu erstellen, das eine Zeichenfolge (von links nach rechts und von beliebiger Länge) von Token analysiert und auswertet, die Anweisungen geben - entweder nach links oder nach rechts. Hier sind die vier möglichen Token und ihre Bedeutungen:

>  go right one single step
<  go left one single step
-> go right the total amount of single steps that you've gone right, plus one,
   before you previously encountered this token and reset this counter to zero
<- go left the total amount of single steps that you've gone left, plus one,
   before you previously encountered this token and reset this counter to zero

Es gibt jedoch einen Haken: Die Token für Anweisungen, die Ihr Programm analysieren kann, werden in der folgenden Form angezeigt:

<<->-><<->->>->>->

... mit anderen Worten, sie sind verkettet, und es ist die Aufgabe Ihres Programms, den korrekten Vorrang der Anweisungen und die Anzahl der zu treffenden Schritte herauszufinden (indem Sie nach vorne schauen). Die Rangfolge ist wie folgt (von der höchsten zur niedrigsten Rangfolge):

  1. ->
  2. <-
  3. >
  4. <

Wenn Sie feststellen, <-dass seit dem Start oder seit dem letzten Zurücksetzen noch keine Schritte nach links ausgeführt wurden, gehen Sie einen einzelnen Schritt nach links. Gleiches gilt für ->, dann aber für rechts.

Ihr Programm sollte bei 0 beginnen und das Ergebnis sollte eine Ganzzahl mit Vorzeichen sein, die die endgültige Endposition darstellt.

Sie können erwarten, dass die Eingabe immer gültig ist (also <--->>--<zum Beispiel nichts dergleichen ).

Beispiel Eingabe:

><->><-<-><-<>>->

Schritte in diesem Beispiel:

 step | token | amount | end position
------+-------+--------+--------------
   1. |   >   |     +1 |           1  
   2. |   <   |     -1 |           0  
   3. |  ->   |     +2 |           2  
   4. |   >   |     +1 |           3  
   5. |   <-  |     -2 |           1  
   6. |   <   |     -1 |           0  
   7. |  ->   |     +2 |           2  
   8. |   <-  |     -2 |           0  
   9. |   <   |     -1 |          -1  
  10. |   >   |     +1 |           0  
  11. |   >   |     +1 |           1  
  12. |  ->   |     +3 |           4  

Zur Verdeutlichung: Die Ausgabe des Programms sollte nur die endgültige Endposition als vorzeichenbehaftete Ganzzahl sein. Die obige Tabelle soll nur die Schritte veranschaulichen, die mein Beispiel unternommen hat. Es ist nicht erforderlich, eine solche Tabelle, Tabellenzeile oder auch nur die Endpositionen der Schritte auszugeben. Es ist nur die letzte Endposition als vorzeichenbehaftete Ganzzahl erforderlich.

Kürzester Code nach einer Woche gewinnt.

Anständiger Dabbler
quelle
4
Wenn ich die Vorrangregeln richtig verstehe, können Sie nur aufrufen, <-wenn unmittelbar danach ein <oder ein folgt ->. Es gibt keine Möglichkeit , in dieser Sprache , die Sequenz zu repräsentieren <-dann >- das wäre go left the total amount of single steps that you've gone left, plus one, then go right one single step. Ist das richtig und beabsichtigt?
Adam Davis
@AdamDavis Sie haben recht. Das war leider etwas unaufmerksam von mir.
Decent Dabbler

Antworten:

6

GolfScript, 46 Zeichen

'->'/')'*.'<-'-.')'/);+,\'>)'-.'<-'/);\'-'-+,-

Dies ist eines der linearsten GolfScript-Programme, die ich je geschrieben habe - es gibt keine einzige Schleife, bedingte oder variable Zuweisung. Alles wird mit String-Manipulation gemacht:

  • Erstens ersetze ich jedes Vorkommen von ->durch ). Da die Gültigkeit der Eingabe garantiert ist, muss das verbleibende Vorkommen von -ein Teil von sein <-.

  • Als nächstes mache ich zwei Kopien der Zeichenfolge. Von der ersten Kopie entferne ich die Zeichen <und -und lasse nur >und ). Ich dupliziere dann das Ergebnis, entferne alle )s und alle >folgenden letzten )aus der zweiten Kopie, verkette sie und zähle die Zeichen. Tatsächlich zähle ich also:

    • +1 für jeden ),
    • +1 für jeden >nach dem letzten )und
    • +2 für jeden >vor dem letzten ).
  • Als nächstes mache ich dasselbe für die andere Kopie, mit der Ausnahme, dass diesmal <und <-anstelle von >und )und das -s vor der letzten Zeichenanzahl entfernt wird. Also zähle ich:

    • +1 für jeden <-,
    • +1 für jeden <nach dem letzten <-und
    • +2 für jeden <vor dem letzten <-.
  • Schließlich subtrahiere ich die zweite Zählung von der ersten und gebe das Ergebnis aus.

Ilmari Karonen
quelle
6

Python 2.7 - 154 147 134 128 Bytes

l=r=p=0
exec"exec raw_input('%s->','p+=r+1;r=0%s<-','p-=l+1;l=0%s>','r+=1;p+=1%s<','l+=1;p-=1;')"%((";').replace('",)*4)
print p

Es wurden ernsthafte Änderungen an der Funktionsweise dieses Programms vorgenommen. Ich habe die alte Erklärung entfernt, die immer noch im Bearbeitungsverlauf dieser Antwort zu finden ist.

Dieser ist eklig.

Es funktioniert so ziemlich genauso wie die anderen Antworten auf diese Frage, indem die Zeichen in der Eingabe durch gültige Anweisungen in dieser Sprache ersetzt und ausgeführt werden. Es gibt jedoch einen großen Unterschied: Es replaceist ein langes Wort. Scheiß drauf.

@ProgrammerDan im Chat hatte die Idee, ein Tupel mit der Zeichenfolge ;').replace('viermal zu verwenden, um die Vorformatierungsmethode str.format()für Text zu verwenden. Vier Instanzen von %sbefinden sich in der Zeichenfolge in der zweiten Zeile, wobei jede Instanz ihren Wert vom zugehörigen Element des Tupels am Ende erhält. Da sie alle gleich sind, wird jeder %sdurch ersetzt ;').replace('. Wenn Sie die Operationen ausführen, erhalten Sie folgende Zeichenfolge:

exec raw_input(';').replace('->','p+=r+1;r=0;').replace('<-','p-=l+1;l=0;').replace('>','r+=1;p+=1;').replace('<','l+=1;p-=1;')

Dies ist jetzt gültiger Python-Code, mit dem ausgeführt werden kann exec. Das ist richtig, Baby: Verschachtelte execs lassen mich Zeichenfolgenoperationen für Code verwenden, die Zeichenfolgenoperationen für Code ausführen müssen . Jemand, bitte töte mich.

Der Rest ist ziemlich einfach: Jeder Befehl wird durch Code ersetzt, der drei Variablen verfolgt: Die aktuelle Position, die Anzahl der Rechte seit dem letzten ->und dieselbe für lefts und <-. Das Ganze wird ausgeführt und die Position gedruckt.

Sie werden bemerken, dass ich raw_input(';')mit ';' als Aufforderung, anstatt raw_input()die keine Aufforderung hat. Dies speichert Zeichen auf eine nicht intuitive Art und Weise: Wenn dies raw_input()der ).replace('Fall %swäre , müsste das Tupel mit gefüllt werden , und jede Instanz von hätte '; \' 'davor, mit Ausnahme der ersten . Eine Eingabeaufforderung schafft mehr Redundanz, sodass ich insgesamt mehr Zeichen speichern kann.

untergrundbahn
quelle
2
msgstr " list.index()kehrt zurück, -1wenn das Zeichen nicht gefunden wird". Es wirft ein IndexError. Sie haben es vielleicht verwechselt mit str.find. In der Tat könnten Sie ersetzen [list('><rl').index(c)]mit ['><rl'.find(c)].
Bakuriu
Ich habe es in den Dokumenten nachgeschlagen und hätte schwören können, dass es -1 zurückgegeben hat. Es war speziell die Seite für Listen, daher habe ich keine Ahnung, was ich lese. Trotzdem, danke für die Hilfe, ich werde das in die Antwort ändern.
Undergroundmonorail
5

Perl, 134 131 ... 99 95 Bytes

sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p

Nimmt die Eingabe als einzelne Zeile auf stdin, zB:

ski@anito:~$ perl -le 'sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p'
><->><-<-><-<>>->
4

oder:

ski@anito:~$ echo "><->><-<-><-<>>->" | perl -le 'sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p'
4

Ich habe die Anweisungen in die Operatoren "right" (">" und "->") und "left" ("<" und "<-") aufgeteilt. Die Vorteile davon sind, dass es einfacher ist, die Parallelität zwischen linken und rechten Operatoren auszunutzen, und dass wir nichts Besonderes tun müssen, um die Zeichenfolge zu kennzeichnen. Jede "Richtung" wird als Substitutionsoperation behandelt, bei der die laufende Summe um die Anzahl der Schritte in dieser Richtung angepasst wird, wobei die umgekehrte Richtung, die von der anderen Substitutionsoperation berücksichtigt wird, ignoriert wird. Hier ist ein weniger erfolgreicher Vorfahr dieses Codes als eine Art Dokumentation:

sub f {
  $dir=shift;
  if($1 =~ /-/) {
    $pos+=$side+$dir;
    $side=0;
  } else {
    $pos+=$dir;
    $side+=$dir;
  }
}

$_=<>;

s/(-?>)/f(1)/eg;
$side=0;
s/(<-?)/f(-1)/eg;

print $pos

In einer vorherigen Iteration dieses Codes wurden die Ersetzungen alle in einem Durchgang durchgeführt. Dies hatte den Vorteil, dass eine direkte Zuordnung zwischen $ p / $ pos und der Position beibehalten wurde, die zu einem bestimmten Zeitpunkt zurückgegeben wurde, jedoch mehr Code-Bytes benötigte.

Wenn Sie () 5.10.0 verwenden möchten, können Sie zwei weitere Zeichen abseits der Zählung mit s / print / say / rasieren, aber das ist nicht wirklich mein Stil.

Skibrianski
quelle
4

Perl, 88 77 Bytes

$_=<>;print s/->/F/g+2*s/>(?=.*F)//g+s/>//g-(s/<-/B/g+2*s/<(?=.*B)//g+s/<//g)

Die Eingabe wird über STDIN erwartet, zum Beispiel:

echo '><->><-<-><-<>>->'|perl -e '$_=<>;print s/->/F/g+2*s/>(?=.*F)//g+s/>//g-(s/<-/B/g+2*s/<(?=.*B)//g+s/<//g)'
4

Aktualisieren

Die Zeichenfolge muss nicht in eine Summe konvertiert werden, da s// bereits gezählt wird. :-)

Erste Version

$_=<>;s/->/+1/g;s/>(?=.*1)/+2/g;s/>/+1/g;s/<-/-1/g;s/<(?=.*-)/-2/g;s/</-1/g;print eval

Die Eingabe wird über STDIN erwartet, Beispiel:

echo '><->><-<-><-<>>->'|perl -e '$_=<>;s/->/+1/g;s/>(?=.*1)/+2/g;s/>/+1/g;s/<-/-1/g;s/<(?=.*-)/-2/g;s/</-1/g;print eval'
4

Erläuterung:

Die Idee ist, den Richtungsstring in eine Summe umzuwandeln, so dass das Ergebnis von einem einfachen ausgegeben wird print eval.

>bevor einer ->zwei Schritte macht, einen auf einmal und den anderen auf den nächsten ->. Es spielt keine Rolle, welcher ->der beiden dabei folgt. Der interne Zähler wird nach dem nächsten zurückgesetzt ->, verursacht also >keine weiteren Schritte, das Maximum sind zwei Schritte. Dann ->fügt einen Schritt für mich und so noch verbleibenden jeder >nach dem letzten ->.

Gleiches gilt für die Rückwärtsrichtung mit negativen statt positiven Schrittzahlen.

Z.B: ><->><-<-><-<>>->

s/->/+1/: Beginnen Sie mit der Vorwärtsrichtung, da diese ->die höchste Priorität hat.
Z.B:><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: Das Look-Ahead-Muster stellt sicher, dass nur die >vorherigen ->konvertiert werden.
Z.B:+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: Jetzt sind die restlichen >abgedeckt.
Z.B:+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: Analog die Rückwärtsrichtung.
Z.B:+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: Im Look-Ahead-Muster wird das Vollbild -1des Ersteren <-nicht benötigt, da keine -Richtungssymbole mehr vorhanden sind.
Z.B:+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: Die <nach dem letzten verbleibenden <-werden konvertiert.
Z.B:+2-2+1+2-1-2+1-1-1+2+2+1

print eval: Das Ergebnis berechnen und ausgeben.
Z.B:4

Heiko Oberdiek
quelle
Gut Ich habe gestern Abend mit diesem Konzept herumgespielt, hatte aber bis heute keine Gelegenheit, es umzusetzen. Gut, dass ich den Beitrag überprüft und
festgestellt
@skibrianski: Danke, dass du den Copy & Paste-Fehler behoben hast.
Heiko Oberdiek
Kann ein bisschen mehr golfed werden: 65 Bytes oder ohne Verwendung von -p: 74 Bytes ich Ihre geändert , s/>//gum y/>//ein Byte in jedem Fall zu speichern , die auch für die Entfernung des Pars im Ausdruck erlaubt.
Xcali
2

Ruby, 141 Bytes

l=1;r=1;o=0
gets.gsub('->',?R).gsub('<-',?L).chars{|c|case c
when'<';o-=1;l+=1
when'>';o+=1;r+=1
when'L';o-=l;l=1
when'R';o+=r;r=1
end}
$><<o

Ungolfed:

parsed = gets.gsub('->', 'R')
             .gsub('<-', 'L')
countL = 1
countR = 1
result = 0
parsed.each_char do |c|
    case c
    when '<'
        result -= 1
        countL += 1
    when '>'
        result += 1
        countR += 1
    when 'L'
        result -= countL
        countL = 1
    when 'R'
        result += countR
        countR = 1
    end
end
puts result
Tim S.
quelle
Ein paar schnelle Siege: l=1;r=1Kann sein l=r=1und $><<okann sein p o. Ich denke, Sie könnten sich viel rasieren, wenn Sie diese case-Anweisung durch etwas weniger sperriges ersetzen, vielleicht in der Art voneval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge
Tatsächlich können Sie mit dem Eval-Ansatz einige Präfixe / Suffixe herausziehen, um noch mehr zu sparen. Dies ist 98 Zeichen: l=r=1;o=0;gets.gsub('->',??).scan(/<-|./){eval"o+=#{%w[-1;l+ -l;l 1;r+ r;r][$&[-1].ord%4]}=1"};p oSie könnten mitruby -p
Paul Prestidge
1

D - 243

Golf gespielt :

import std.regex,std.stdio;void main(string[]a){int s,c,v;auto t=a[1].matchAll("->|<-(?!>)|>|<".regex);foreach(m;t){auto r=m.hit;if(r=="->"){s+=c+1;c=0;}else if(r=="<-"){s-=v+1;v=0;}else if(r==">"){++s;++c;}else if(r=="<"){--s;++v;}}s.write;}}

Nicht golfen :

import std.regex, std.stdio;

void main( string[] a )
{
    int s, c, v;
    auto t = a[1].matchAll( "->|<-(?!>)|>|<".regex );

    foreach( m; t )
    {
        auto r = m.hit;

        if( r == "->" )
        {
            s += c + 1;
            c = 0;
        }
        else if( r == "<-" )
        {
            s -= v + 1;
            v = 0;
        }
        else if( r == ">" )
        {
            ++s;
            ++c;
        }
        else if( r == "<" )
        {
            --s;
            ++v;
        }
    }

    s.write;
}
Tony Ellis
quelle
Die gewünschte Ausgabe war ursprünglich in der Frage. Ich habe es jetzt hervorgehoben und weitere Erläuterungen hinzugefügt.
Decent Dabbler
Richtig, ich habe meine Antwort bearbeitet, um das Ergebnis jetzt auszugeben.
Tony Ellis
1

C 148, 141 140

140

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++)(*x^45)?(*x^60)?(r++,o++):(*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++):(o+=r+1,r=0,x++);return o;}

141

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++)(*x^45)?(*x^60)?(r++,o++):(*(x+1)==45)?(x++,o=o-l-2,l=0):(o--,l++):(o+=r+1,r=0,x++);return o;}

148

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++){if(*x^45){if(*x^60)r++,o++;else{o--,l++;if(*(x+1)==45)x++,o-=l,l=0;}}else o+=r+1,r=0,x++;}return o;}

Mit Leerzeichen:

r,l,o;
main(char *x,char **v) 
{
    for(x=v[1];*x;x++)
    (*x^45) ?
        (*x^60) ?
            (r++,o++)
            :
            (*(x+1)==45) ?
                (x++,o-=l+2,l=0)
            :(o--,l++)
        :(o+=r+1,r=0,x++);
    return o;
}

Wahrscheinlich viel mehr Platz zum Golfen. Ich habe es größtenteils aufgegeben, 4 Variablen in Ternären zu manipulieren, die l-Werte erfasst haben (es kam immer länger heraus und wurde später), aber kein schlechter erster Durchgang. Ziemlich unkomplizierter Array-Pass. Übernimmt die Eingabe als Befehlszeilenargument und gibt sie über den Rückgabewert aus.

Sie benötigen das -std=c99Flag, um es mit gcc zu kompilieren.

EDIT: Ja, es ist spät - einige offensichtliche Dinge verpasst.

Komintern
quelle
Sie können zwei Räume in der Argument - Liste entfernen main: main(char*x,char**v). Dann haben Sie 138 statt 140.
Heiko Oberdiek
Es gibt einen Fehler: >><-Gibt 0 anstelle von 1 oder ><->gibt 0 anstelle von 2.
Heiko Oberdiek
Sie können 4 Bytes speichern , wenn Ihre entfernen Räume zwischen charund *, und ersetzen (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)mit (*++x==45)?(o-=l+2,l=0):(x--,o--,l++).
Mathieu Rodic
1

JavaScript, 136

z=0;l=r=1;c=["--z;++l;",/</g,"++z;++r;",/>/g,"z-=l;l=1;",/<-/g,"z+=r;r=1;",/->/g];for(a=8;a--;s=s.replace(c[a--],c[a]));eval(s);alert(z)

Nicht abgeschlossen:

s="><->><-<-><-<>>->";
z=0;
l=r=1;
c=[
    "--z;++l;", /</g,
    "++z;++r;", />/g,
    "z-=l;l=1;", /<-/g,
    "z+=r;r=1;", /->/g
];
for(a=8;a--;s=s.replace(c[a--],c[a]));
eval(s);
alert(z) // Output (4)

Wie es funktioniert

Wenn Sie einen String wie sfolgt eingeben:

s="><->><-<-><-<>>->";

Es wird ein Regex verwendet, um jeden Befehl durch eine Reihe von Anweisungen zu ersetzen, die z(die Endposition), l(gespeicherte Linksbewegungen) und ändernr gespeicherte Rechtsbewegungen . Jeder Regex wird in der Rangfolge ausgeführt.

Für die Eingabe oben wird dies in Folgendes konvertiert s:

"++z;++r;--z;++l;z+=r;r=1;++z;++r;z-=l;l=1;--z;++l;z+=r;r=1;z-=l;l=1;--z;++l;++z;++r;++z;++r;z+=r;r=1;"

Schön, nicht wahr?

Schließlich müssen wir eval(s)die Anweisungen und Warnungen ausführen, zdie die Endposition enthalten.

George Reith
quelle
1

Javascript (116, 122 , 130 )

116

for(l=r=p=i=0;c='<>-0'.indexOf(a.replace(/->/g,0)[i++])+1;p--)c-4?c-3?c-2?l++:(r++,p+=2):(p-=l-2,l=0):(p+=r+2,r=0);p

122

for(l=r=p=i=0,a=a.replace(/->/g,0);c='<>-0'.indexOf(a[i])+1;i++,p--)c-4?c-3?c-2?l++:(r++,p+=2):(p-=l-2,l=0):(p+=r+2,r=0);p

130

for(l=r=p=i=0;c='<>-'.indexOf(a[i])+1;i++,p--)c-3?c-1?(r++,p+=2):a[i+1]=='-'?a[i+2]=='>'?l++:(p-=l,l=0,i++):l++:(p+=r+2,r=0,i++);p
mowwwalker
quelle
0

JavaScript [217 Bytes]

prompt(x=l=r=0,z='replace',f='$1 $2 ')[z](/(>.*?)(->)/g,f)[z](/(<.*?)(<-)/g,f)[z](/(<|>)(<|>)/g,f)[z](/<-?|-?>/g,function(c){c=='>'&&(x++,r++),c=='<'&&(x--,l++),c=='->'&&(x+=++r,r*=0),c=='<-'&&(x-=++l,l*=0)}),alert(x)

Wahrscheinlich kann es etwas mehr verkürzt werden ...

Vision
quelle
0

PHP, 284 282

Kein Regex.

$i=fgets(STDIN);$c=$a=0;$s=str_split($i);while($c<count($s)){switch($s[$c]){case"<":if($s[$c+1]=="-"){if($s[$c+2]==">"){$c+=3;$a+=$rr;$rr=0;$ll++;}else{$c+=2;$a+=-($ll+1);$ll=0;}}else{$c++;$a--;$ll++;}break;case">":$c++;$a++;$rr++;break;case"-":$c+=2;$a+=$rr+1;$rr=0;break;}}echo$a;

Ungolfed:

$i=fgets(STDIN);
$c=$a=0;
$s=str_split($i);
while($c<count($s)){
    switch($s[$c]){
    case "<":
        if($s[$c+1]=="-"){
            if($s[$c+2]==">"){
                $c+=3;$a+=$rr;$rr=0;$ll++;
            }
            else{
                $c+=2;$a+=-($ll+1);$ll=0;
            }
        }
        else{
            $c++;$a--;$ll++;
        }
    break;
    case ">":
        $c++;$a++;$rr++;
        break;
    case "-":
        $c+=2;$a+=$rr+1;$rr=0;
        break;
    }
}
echo $a;
Vereos
quelle
Sie können 2 Zeichen mit gewinnen str_split($i)( 1ist die Standardeinstellung für das zweite Argument.) Und $isollte es wahrscheinlich sein $c, richtig?
Decent Dabbler
Erste Zeile war falsch (es war $i): P Reparierte es!
Vereos
0

Eine andere Perl-Lösung, 113 Zeichen

Es gibt bereits zwei Antworten, die dies schlagen, es ist nur für Kichern. Es verwendet einen Ansatz, der auf Ilmaris Beobachtung über den Wert von Token basiert:

$_=<>;chomp;s/->/#/g;s/<-/%/g;s/>(?=.*#)/?/g;s/<(?=.*%)/;/g;s/#/>/g;s/%/</g;$t+=ord for split//;print$t-61*length

Ein bisschen explodiert:

$_=<>;
chomp;
s/->/#/g;
s/<-/%/g;
s/>(?=.*#)/?/g;
s/<(?=.*%)/;/g;
s/#/>/g;
s/%/</g;
$t+=ord for split//;
print$t-61*length
Skibrianski
quelle