Brainf * indicazioni stradali


14

Il tuo compito - se scegli di accettarlo - è quello di costruire un programma che analizza e valuta una stringa (da sinistra a destra e di lunghezza arbitraria) di token che danno indicazioni - sia a sinistra che a destra. Ecco i quattro possibili token e i loro significati:

>  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

Tuttavia, c'è un problema: i token di direzioni che il tuo programma dovrebbe essere in grado di analizzare saranno presentati in questo modulo:

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

... in altre parole, sono concatenati ed è compito del tuo programma capire la precedenza corretta delle direzioni e la quantità di passi da compiere (guardando avanti). L'ordine di precedenza è il seguente (dalla precedenza più alta alla più bassa):

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

Se si verifica <-quando in precedenza non sono stati effettuati passaggi a sinistra dall'avvio o dall'ultimo ripristino, eseguire un singolo passaggio a sinistra. La stessa regola si applica a ->, ma poi per andare a destra.

Il programma dovrebbe iniziare da 0 e il risultato dovrebbe essere un numero intero con segno che rappresenta la posizione finale finale.

Potresti aspettarti che l'input sia sempre valido (quindi, niente di simile <--->>--<, ad esempio).

Esempio di input:

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

Passaggi in questo esempio:

 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  

Per chiarimenti: l'output del programma dovrebbe essere solo la posizione finale finale come intero con segno. La tabella sopra è proprio lì per illustrare i passi del mio esempio. Non è necessario generare una tabella di questo tipo, una riga di tabella o anche solo le posizioni finali dei passaggi. È richiesta solo la posizione finale finale, come intero con segno.

Il codice più breve, dopo una settimana, vince.


4
Se capisco correttamente le regole di precedenza, l'unica volta che potresti invocare <-è se è immediatamente seguito da a <o a ->. In questo linguaggio non c'è modo di rappresentare la sequenza <-allora >- quale sarebbe go left the total amount of single steps that you've gone left, plus one, then go right one single step. È corretto e di progettazione?
Adam Davis,

@AdamDavis Hai ragione. Questo è stato un po 'distratto da me, sfortunatamente.
Dabbler decente,

Risposte:


6

GolfScript, 46 caratteri

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

Questo è uno dei programmi GolfScript più lineari che io abbia mai scritto: non c'è un singolo loop, assegnazione condizionale o variabile in esso. Tutto viene fatto usando la manipolazione di stringhe:

  • In primo luogo, ho sostituire ogni occorrenza di ->by ). Poiché l'input è garantito per essere valido, ciò garantisce che qualsiasi occorrenza rimanente di -deve far parte di <-.

  • Successivamente, realizzo due copie della stringa. Dalla prima copia, rimuovo i caratteri <e- , lasciando solo >e ). Quindi duplico il risultato, rimuovo tutti )i se e >l'ultimo seguito )dalla seconda copia, li concateno e conto i caratteri. Quindi, in effetti, sto contando:

    • +1 per ciascuno ),
    • +1 per ciascuno >dopo l'ultimo ), e
    • +2 per ciascuno > prima dell'ultimo ).
  • Successivamente, faccio lo stesso per l'altra copia, tranne che per questo conteggio <e <-invece di> e ), e rimuovendo le -s prima del conteggio finale dei caratteri. Quindi, conto:

    • +1 per ciascuno <-,
    • +1 per ciascuno <dopo l'ultimo <-, e
    • +2 per ciascuno < prima dell'ultimo <-.
  • Infine, sottraggo il secondo conteggio dal primo e produco il risultato.


6

Python 2.7 - 154 147 134 128 byte

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

Sono state apportate gravi modifiche al funzionamento di questo programma. Ho rimosso la vecchia spiegazione, che può ancora essere trovata nella cronologia delle modifiche di questa risposta.

Questo è disgustoso.

Funziona più o meno allo stesso modo delle altre risposte a questa domanda, sostituendo i caratteri nell'input con dichiarazioni valide in quella lingua ed eseguendoli. C'è una grande differenza, però:replace è una parola lunga. Fanculo.

@ProgrammerDan in chat ha avuto l'idea di utilizzare una tupla con la stringa ;').replace('in essa 4 volte, per usare il pre str.format()metodo di formattazione del testo. %sNella seconda riga sono presenti quattro istanze di , ognuna delle quali prende il suo valore dall'elemento associato della tupla alla fine. Dal momento che sono tutti uguali, ognuno %sviene sostituito con ;').replace('. Quando si eseguono le operazioni, si ottiene questa stringa:

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

Questo è ora un codice Python valido che può essere eseguito con exec. Esatto, piccola: i nidificati execmi permettono di usare le operazioni di stringa sul codice che deve eseguire operazioni di stringa sul codice . Qualcuno per favore mi uccida.

Il resto è piuttosto semplice: ogni comando viene sostituito con un codice che tiene traccia di tre variabili: la posizione corrente, il numero di diritti dall'ultima -> e lo stesso per le sinistre e <-. Il tutto viene eseguito e la posizione viene stampata.

Noterai che lo faccio raw_input(';'), usando ';' come prompt, piuttosto che raw_input()quale non ha prompt. Questo salva i personaggi in modo non intuitivo: se lo facessi raw_input(), dovrei riempire la tupla ).replace('e ogni istanza di %sdovrebbe avere '; \' 'prima di essa tranne la prima . Avere un prompt crea più ridondanza in modo da poter salvare più personaggi in generale.


2
" list.index()ritorna -1quando non riesce a trovare il personaggio" .. erm no. Solleva un IndexError. Potresti averlo confuso con str.find. In effetti potresti sostituirlo [list('><rl').index(c)]con ['><rl'.find(c)].
Bakuriu,

... Huh, l'ho cercato nei documenti e avrei giurato che mi ha restituito -1. Era specificamente la pagina per gli elenchi, quindi non ho idea di cosa ho letto. Comunque, grazie per l'aiuto, lo modificherò nella risposta.
undergroundmonorail,

5

Perl, 134 131 ... 99 95 byte

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

Accetta input come una riga singola su stdin, ad esempio:

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

o:

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

Ho diviso le istruzioni in operatori "a destra" (">" e "->") e "a sinistra" ("<" e "<-"). I vantaggi di questo sono che è più facile sfruttare il parallelismo tra operatori di destra e di sinistra e non dobbiamo fare nulla di speciale per tokenizzare la stringa. Ogni "direzione" viene gestita come un'operazione di sostituzione in cui regoliamo il totale parziale in base al numero di passi effettuati in quella direzione, ignorando la direzione inversa di cui si occupa l'altra operazione di sostituzione. Ecco un antenato meno esperto di questo codice come una sorta di documentazione:

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 una precedente iterazione di questo codice, le sostituzioni sono state tutte eseguite in un unico passaggio. Ciò ha avuto il vantaggio di mantenere una mappatura diretta tra $ p / $ pos e la posizione che sarebbe stata restituita in un dato momento, ma ha richiesto più byte di codice.

Se vuoi usare () 5.10.0, puoi s / stampare / dire / per radere altri 2 caratteri fuori dal conteggio, ma non è proprio il mio stile.


4

Perl, 88 77 byte

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

L'ingresso è previsto tramite STDIN, ad esempio:

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

Aggiornare

Non è necessario convertire la stringa in una somma, perché s//sta già contando. :-)

Prima versione

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

L'ingresso è previsto tramite STDIN, esempio:

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

Spiegazione:

L'idea è di convertire la stringa di direzione in una somma in modo che il risultato sia emesso da un semplice print eval.

>prima che uno ->compia due passaggi, uno alla volta e l'altro al successivo ->. Non importa quale dei due ->ne segua almeno uno. Il contatore interno viene ripristinato dopo il successivo ->, quindi >non provoca ulteriori passaggi, il massimo è due passaggi. Quindi ->aggiunge un passaggio per se stesso e quindi fare qualsiasi rimanente >dopo l'ultimo ->.

Lo stesso vale per la direzione all'indietro con conteggi di passi negativi anziché positivi.

Per esempio: ><->><-<-><-<>>->

s/->/+1/: Inizia con la direzione in avanti, poiché ->ha la massima precedenza.
Per esempio:><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: Il modello di verifica assicura che solo i >precedenti ->vengano convertiti.
Per esempio:+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: Ora i restanti >sono coperti.
Per esempio:+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: Analogico all'indietro.
Per esempio:+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: Nel modello -1di prospettiva <-non è necessario il pieno del primo , poiché non sono -rimasti simboli di direzione.
Per esempio:+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: I restanti <dopo l'ultimo <-vengono convertiti.
Per esempio:+2-2+1+2-1-2+1-1-1+2+2+1

print eval: Calcola e genera il risultato.
Per esempio:4


Buona Ieri sera stavo dando un'occhiata a questo concetto, ma non ho avuto la possibilità di provare ad implementarlo fino ad oggi.
Meno male

@skibrianski: grazie per aver corretto l'errore di copia e incolla.
Heiko Oberdiek,

Può essere giocato a golf un po 'di più: 65 byte Oppure, senza l'utilizzo di -p: 74 byte ho cambiato il tuo s/>//gper y/>//salvare un byte in ogni caso che ha permesso anche per la rimozione delle parentesi nell'espressione.
Xcali,

2

Rubino, 141 byte

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

Un paio di vittorie veloci: l=1;r=1può essere l=r=1e $><<opuò essere p o. Penso che potresti raderti molto sostituendo quella dichiarazione del caso con qualcosa di meno voluminoso, forse qualcosa del genereeval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge,

In effetti con l'approccio eval è possibile estrarre alcuni prefissi / suffissi per risparmiare ancora di più. Sono 98 caratteri: l=r=1;o=0;gets.gsub('->',??).scan(/<-|./){eval"o+=#{%w[-1;l+ -l;l 1;r+ r;r][$&[-1].ord%4]}=1"};p opotresti scendere a 94 usandoruby -p
Paul Prestidge il

1

D - 243

Golfato :

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 golfato :

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

L'output richiesto era originariamente nella domanda. L'ho evidenziato ora e ho aggiunto ulteriori chiarimenti.
Dabbler decente,

Bene, ho modificato la mia risposta per produrre il risultato ora.
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;}

Con spazi bianchi:

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

Probabilmente molto più spazio per giocare a golf. Per lo più ho rinunciato a provare a manipolare 4 variabili nei ternari che hanno catturato i valori (continuava a uscire più a lungo e ad arrivare più tardi), ma non è stato un brutto primo passaggio. Passaggio di array abbastanza diretto. Accetta input come argomento della riga di comando, output tramite il valore restituito.

Avrai bisogno della -std=c99bandiera per compilarla con gcc.

EDIT: Sì, è tardi - ho perso alcune cose ovvie.


È possibile rimuovere due spazi nella lista degli argomenti di main: main(char*x,char**v). Quindi hai 138 invece di 140.
Heiko Oberdiek,

C'è un bug: >><-dà 0 invece di 1 o ><->dà 0 invece di 2.
Heiko Oberdiek

È possibile salvare 4 byte se si rimuovono gli spazi tra chare *e si sostituisce (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)con (*++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)

Unminified:

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)

Come funziona

Dato un input di stringa in questo smodo:

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

Usa un Regex per sostituire ogni comando con una serie di istruzioni che modificano z(la posizione finale), l(movimenti a sinistra memorizzati) e rmovimenti a destra memorizzati. Ogni Regex viene eseguito in ordine di precedenza.

Per l'input sopra questo converte sin:

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

Piuttosto, non è così.

Infine, eval(s)eseguiamo le istruzioni e l'avviso zche contiene la posizione 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 byte]

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)

Probabilmente potrebbe essere abbreviato un po 'di più ...


0

PHP, 284 282

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

Puoi vincere 2 caratteri con str_split($i)( 1è il valore predefinito per il secondo argomento.) E $iprobabilmente dovrebbe essere $ccorretto?
Dabbler decente,

La prima riga era sbagliata (era $i): P risolto!
Vereos,

0

Un'altra soluzione perl, 113 caratteri

Ci sono già due risposte che battono questo, è solo per le risatine. Utilizza un approccio basato sull'osservazione di Ilmari sul valore dei token:

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

Un po 'esploso:

$_=<>;
chomp;
s/->/#/g;
s/<-/%/g;
s/>(?=.*#)/?/g;
s/<(?=.*%)/;/g;
s/#/>/g;
s/%/</g;
$t+=ord for split//;
print$t-61*length
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.