Brainf * ckish directions


14

Votre tâche - si vous choisissez de l'accepter - est de créer un programme qui analyse et évalue une chaîne (de gauche à droite et de longueur arbitraire) de jetons qui donnent des directions - à gauche ou à droite. Voici les quatre jetons possibles et leurs significations:

>  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

Il y a cependant un hic - les jetons des directions que votre programme devrait être en mesure d'analyser seront présentés sous cette forme:

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

... en d'autres termes, ils sont concaténés, et c'est la tâche de votre programme de déterminer la priorité correcte des directions et la quantité de mesures à prendre (en regardant vers l'avenir). L'ordre de priorité est le suivant (de la priorité la plus élevée à la plus faible):

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

Si vous rencontrez <-alors qu'aucune étape vers la gauche n'avait été effectuée depuis le début ou depuis la dernière réinitialisation, faites un pas vers la gauche. La même règle s'applique à ->, mais ensuite pour aller à droite.

Votre programme doit commencer à 0 et son résultat doit être un entier signé représentant la position finale finale.

Vous pouvez vous attendre à ce que l'entrée soit toujours valide (donc rien de tel <--->>--<, par exemple).

Exemple d'entrée:

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

Étapes dans cet exemple:

 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  

Pour plus de précision: la sortie du programme ne doit être que la position finale finale sous forme d'entier signé. Le tableau ci-dessus est juste là pour illustrer les étapes de mon exemple. Pas besoin de sortir un tel tableau, une ligne de tableau ou même simplement les positions finales des étapes. Seule la position finale finale, sous forme d'entier signé, est requise.

Le code le plus court, après une semaine, gagne.


4
Si je comprends bien les règles de priorité, la seule fois que vous pouvez invoquer <-est si elle est immédiatement suivie d'un <ou d'un ->. Il n'y a aucun moyen dans ce langage de représenter la séquence <-alors >- ce qui le serait go left the total amount of single steps that you've gone left, plus one, then go right one single step. Est-ce correct et par conception?
Adam Davis

@AdamDavis Vous avez raison. C'était un peu inattentif pour moi, malheureusement.
Decent Dabbler

Réponses:


6

GolfScript, 46 caractères

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

C'est l'un des programmes GolfScript les plus linéaires que j'ai jamais écrits - il n'y a pas une seule boucle, affectation conditionnelle ou variable. Tout se fait en utilisant la manipulation de chaînes:

  • Tout d'abord, je remplace chaque occurrence de ->par ). Puisque l'entrée est garantie pour être valide, cela garantit que toute occurrence restante de -doit faire partie de <-.

  • Ensuite, je fais deux copies de la chaîne. Dès la première copie, je retire les caractères <et -, ne laissant que >et ). Je duplique ensuite le résultat, supprime tous les )s et tous les >suivants du dernier )de la deuxième copie, les concatène et compte les caractères. Ainsi, en effet, je compte:

    • +1 pour chacun ),
    • +1 pour chacun >après le dernier ), et
    • +2 pour chacun >avant le dernier ).
  • Ensuite, je fais de même pour l'autre copie, sauf cette fois en comptant <et <-au lieu de >et ), et en supprimant les -s avant le décompte final des caractères. Ainsi, je compte:

    • +1 pour chacun <-,
    • +1 pour chacun <après le dernier <-, et
    • +2 pour chacun <avant le dernier <-.
  • Enfin, je soustrais le deuxième décompte du premier et affiche le résultat.


6

Python 2,7 - 154 147 134 128 octets

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

De sérieux changements ont été apportés au fonctionnement de ce programme. J'ai supprimé l'ancienne explication, qui se trouve toujours dans l'historique des modifications de cette réponse.

Celui-ci est dégoûtant.

Cela fonctionne à peu près de la même manière que les autres réponses à cette question, en remplaçant les caractères dans l'entrée par des instructions valides dans cette langue et en les exécutant. Il y a cependant une différence majeure: replacec'est un long mot. Vis ça.

@ProgrammerDan dans le chat a eu l'idée d'utiliser un tuple avec la chaîne ;').replace('4 fois, pour utiliser la pré- str.format()méthode de formatage du texte. Quatre instances de %ssont dans la chaîne sur la deuxième ligne, chacune tirant sa valeur de l'élément associé du tuple à la fin. Comme ils sont tous identiques, chacun %sest remplacé par ;').replace('. Lorsque vous effectuez les opérations, vous obtenez cette chaîne:

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

C'est maintenant du code python valide qui peut être exécuté avec exec. C'est vrai, bébé: les imbriqués execme permettent d'utiliser des opérations de chaîne sur du code qui doit effectuer des opérations de chaîne sur du code . Quelqu'un, s'il vous plaît, tuez-moi.

Le reste est assez simple: chaque commande est remplacée par du code qui garde la trace de trois variables: la position actuelle, le nombre de droits depuis la dernière ->, et la même chose pour les gauches et les <-. Le tout est exécuté et la position est imprimée.

Vous remarquerez que je fais raw_input(';'), en utilisant ';' comme une invite, plutôt que raw_input()qui n'a pas d'invite. Cela permet d'économiser des caractères d'une manière peu intuitive: si je le faisais raw_input(), je devrais avoir le tuple rempli ).replace(', et chaque instance de %saurait '; \' 'devant, sauf la première . Avoir une invite crée plus de redondance afin que je puisse enregistrer plus de caractères dans l'ensemble.


2
" list.index()retourne -1quand il ne trouve pas le personnage" .. erm no. Cela soulève un IndexError. Vous l'avez peut-être confondu avec str.find. En fait, vous pourriez remplacer [list('><rl').index(c)]par ['><rl'.find(c)].
Bakuriu

... Huh, je l'ai regardé dans les documents et j'aurais juré qu'il était revenu -1. C'était spécifiquement la page des listes, donc je n'ai aucune idée de ce que j'ai lu. Quoi qu'il en soit, merci pour l'aide, je vais modifier cela dans la réponse.
undergroundmonorail

5

Perl, 134 131 ... 99 95 octets

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

Prend l'entrée en une seule ligne sur stdin, par exemple:

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

ou:

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

J'ai divisé les instructions en opérateurs "à droite" (">" et "->") et en opérateurs "gauche" ("<" et "<-"). Les avantages de ceci sont qu'il est plus facile d'exploiter le parallélisme entre les opérateurs gauche et droit, et nous n'avons rien à faire de fantaisie pour symboliser la chaîne. Chaque "direction" est traitée comme une opération de substitution où nous ajustons le total cumulé par le nombre de pas effectués dans cette direction, en ignorant la direction inverse qui est prise en charge par l'autre opération de substitution. Voici un ancêtre moins golfé de ce code comme une sorte de documentation:

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

Dans une itération antérieure de ce code, les substitutions étaient toutes effectuées en un seul passage. Cela avait l'avantage de conserver un mappage direct entre $ p / $ pos et la position qui serait retournée à un moment donné, mais prenait plus d'octets de code.

Si vous souhaitez utiliser () 5.10.0, vous pouvez s / print / say / pour raser 2 autres caractères du décompte, mais ce n'est pas vraiment mon style.


4

Perl, 88 77 octets

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

L'entrée est attendue via STDIN, par exemple:

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

Mise à jour

Il n'est pas nécessaire de convertir la chaîne en une somme, car cela s//compte déjà. :-)

Première version

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

L'entrée est attendue via STDIN, exemple:

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

Explication:

L'idée est de convertir la chaîne de direction en une somme de sorte que le résultat soit sorti par un simple print eval.

>avant que chacun ne ->prenne deux mesures, l'une à la fois et l'autre à la suivante ->. Peu importe, lequel de ->temps il suit au moins l'un d'entre eux. Le compteur interne est remis à zéro après le suivant ->, >ne provoque donc pas d'autres étapes, le maximum est de deux étapes. ->Ajoute ensuite une étape pour lui-même et tout autre reste >après la dernière ->.

Il en va de même pour la direction arrière avec un nombre de pas négatif plutôt que positif.

Par exemple: ><->><-<-><-<>>->

s/->/+1/: Commencez par la direction avant, car ->a la priorité la plus élevée.
Par exemple:><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: Le modèle d'anticipation garantit que seuls les éléments >avant ->sont convertis.
Par exemple:+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: Maintenant, les autres >sont couverts.
Par exemple:+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: Analogique vers l'arrière.
Par exemple:+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: Dans le modèle d'anticipation, -1le premier <-n'est pas nécessaire, car il ne reste aucun -symbole de direction.
Par exemple:+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: Les restants <après le dernier <-sont convertis.
Par exemple:+2-2+1+2-1-2+1-1-1+2+2+1

print eval: Calculer et sortir le résultat.
Par exemple:4


Bon. J'ai essayé ce concept hier soir, mais je n'ai pas pu essayer de le mettre en œuvre jusqu'à aujourd'hui. Heureusement que j'ai vérifié le message et j'ai vu que vous aviez déjà eu =)
skibrianski

@skibrianski: Merci d'avoir corrigé l'erreur de copier-coller.
Heiko Oberdiek

Peut être golfed un peu plus: 65 octets Ou, sans utiliser -p: 74 octets J'ai changé votre s/>//gpour y/>//sauver un octet dans chaque cas qui a permis également pour le retrait des parens dans l'expression.
Xcali

2

Rubis, 141 octets

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

Non golfé:

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

Quelques gains rapides: l=1;r=1peuvent être l=r=1et $><<opeuvent être p o. Je pense que vous pourriez vous raser beaucoup en remplaçant cette déclaration de cas par quelque chose de moins volumineux, peut-être quelque chose dans le sens deeval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge

En fait, avec l'approche eval, vous pouvez retirer certains préfixes / suffixes pour économiser encore plus. Il s'agit de 98 caractères: l=r=1;o=0;gets.gsub('->',??).scan(/<-|./){eval"o+=#{%w[-1;l+ -l;l 1;r+ r;r][$&[-1].ord%4]}=1"};p ovous pouvez descendre à 94 en utilisantruby -p
Paul Prestidge

1

D - 243

Golfé :

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

Non golfé :

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

La sortie requise était à l'origine dans la question. Je l'ai mis en évidence maintenant et j'ai ajouté des précisions.
Decent Dabbler

Bon, j'ai édité ma réponse pour produire le résultat maintenant.
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;}

Avec espace:

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

Probablement beaucoup plus d'espace pour jouer au golf. J'ai surtout renoncé à essayer de manipuler 4 variables dans les ternaires qui capturaient les valeurs (cela continuait de sortir plus longtemps et de plus en plus tard), mais ce n'était pas une mauvaise première passe. Passage de tableau assez simple. Prend l'entrée comme argument de ligne de commande, les sorties via la valeur de retour.

Vous aurez besoin du -std=c99drapeau pour le compiler avec gcc.

EDIT: Oui, il est tard - j'ai raté des choses évidentes.


Vous pouvez supprimer deux espaces dans la liste des arguments de main: main(char*x,char**v). Ensuite, vous avez 138 au lieu de 140.
Heiko Oberdiek

Il y a un bug: >><-donne 0 au lieu de 1 ou ><->donne 0 au lieu de 2.
Heiko Oberdiek

Vous pouvez enregistrer 4 octets si vous supprimez des espaces entre charet *, et remplacez (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)par (*++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)

Non minifié:

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)

Comment ça fonctionne

Étant donné une chaîne entrée scomme ceci:

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

Il utilise une Regex pour remplacer chaque commande par un ensemble d'instructions qui modifient z(la position finale), l(les mouvements de gauche stockés) et rles mouvements de droite stockés. Chaque Regex est effectuée par ordre de priorité.

Pour l'entrée ci-dessus, cela se convertit sen:

"++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;"

Joli, n'est-ce pas.

Enfin, nous devons eval(s)exécuter les instructions et l'alerte zqui contient la position finale.


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

0

JavaScript [217 octets]

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)

Elle pourrait probablement être raccourcie un peu plus ...


0

PHP, 284 282

Aucun 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;

Non golfé:

$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;

Vous pouvez gagner 2 caractères avec str_split($i)( 1est la valeur par défaut pour le deuxième argument.) Et $idevrait probablement l'être $c, n'est -ce pas?
Decent Dabbler

La première ligne était fausse (elle l'était $i): P Fixe!
Vereos

0

Une autre solution Perl, 113 caractères

Il y a déjà deux réponses qui ont battu cela, c'est juste pour des rires. Il utilise une approche basée sur l'observation d'Ilmari sur la valeur des jetons:

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

Explosé un peu:

$_=<>;
chomp;
s/->/#/g;
s/<-/%/g;
s/>(?=.*#)/?/g;
s/<(?=.*%)/;/g;
s/#/>/g;
s/%/</g;
$t+=ord for split//;
print$t-61*length
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.