Brainf * ckish yol tarifi


14

Göreviniz - kabul etmeyi seçerseniz -, sola veya sağa yön veren tokenlerden oluşan bir dizeyi (soldan sağa ve keyfi uzunlukta) ayrıştıran ve değerlendiren bir program oluşturmaktır. İşte dört olası belirteç ve anlamları:

>  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

Gerçi bir yakalama var - programınızın ayrıştırması gereken yön belirteçleri bu formda sunulacak:

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

başka bir deyişle, bunlar birleştirilir ve yönlerinizin doğru önceliğini ve atılacak adımların miktarını (ileriye bakarak) anlamak programınızın görevidir. Öncelik sırası aşağıdaki gibidir (en yüksekten en düşüğe önceliğe):

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

<-Başlangıçtan bu yana ya da son sıfırlamadan bu yana daha önce solda hiçbir adım yapılmadığında karşılaşırsanız , sola bir adım atın. Aynı kural geçerlidir ->, ancak daha sonra sağa gitmek için.

Programınız 0'dan başlamalı ve sonucu, son son konumu temsil eden işaretli bir tam sayı olmalıdır.

Girdinin her zaman geçerli olmasını bekleyebilirsiniz ( <--->>--<örneğin, örneğin hiçbir şey ).

Örnek girdi:

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

Bu örnekteki adımlar:

 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  

Açıklığa kavuşturmak için: programın çıktısı yalnızca işaretli bir tamsayı olarak son son konum olmalıdır. Yukarıdaki tablo, örneğimin attığı adımları göstermek için sadece orada. Böyle bir tablo, tablo satırı veya hatta adımların bitiş konumlarını çıkarmaya gerek yoktur. İşaretli bir tam sayı olarak yalnızca son son konum gereklidir.

Bir hafta sonra en kısa kod kazanır.


4
Öncelik kurallarını doğru bir şekilde anlarsam <-, çağırabileceğiniz tek zaman , hemen ardından a <veya a gelirse ->. Bu dilde diziyi temsil etmenin bir yolu yoktur - <-o zaman >olurdu go left the total amount of single steps that you've gone left, plus one, then go right one single step. Bu doğru ve tasarım gereği mi?
Adam Davis

@AdamDavis Haklısın. Maalesef bu biraz dikkatsizdi.
Terbiyeli Dabbler

Yanıtlar:


6

GolfScript, 46 karakter

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

Bu şimdiye kadar yazdığım en doğrusal GolfScript programlarından biridir - içinde tek bir döngü, koşullu veya değişken atama yoktur. Her şey dize manipülasyonu kullanılarak yapılır:

  • Birincisi, her geçtiği yerini ->tarafından ). Girişin geçerli olacağı garanti edildiğinden, kalan tüm oluşumların -bir parçası olması gerekir <-.

  • Sonra dizenin iki kopyasını yapıyorum. İlk kopyadan karakterleri kaldırıyorum <ve -sadece >ve ). Sonra, sonuç yinelenen kaldırmak )s ve her >geçen aşağıdaki )ikinci kopyasından, onları birleştirir ve karakterleri sayar. Böylece, aslında, sayıyorum:

    • Her biri için +1 ),
    • Sonuncudan >sonra her biri için +1 )ve
    • Sondan >önce her biri için +2 ).
  • Sonra, diğer zaman için de aynısını yapıyorum, bu süre sayım hariç ve son karakter sayımından önce <ve <-yerine >ve s'yi )kaldırarak -. Böylece, sayıyorum:

    • Her biri için +1 <-,
    • Sonuncudan <sonra her biri için +1 <-ve
    • Sondan <önce her biri için +2 <-.
  • Son olarak, ikinci sayımı birinciden çıkarıyorum ve sonucu çıkarıyorum.


6

Python 2.7 - 154 147 134 128 bayt

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

Bu programın çalışmasında ciddi değişiklikler yapılmıştır. Bu cevabın düzenleme geçmişinde hala bulunabilen eski açıklamayı kaldırdım.

Bu iğrenç.

Bu sorudaki diğer cevaplarla hemen hemen aynı şekilde çalışır, girişteki karakterleri o dildeki geçerli ifadelerle değiştirir ve yürütür. Yine de büyük bir fark var: replaceuzun bir kelime. Siktir et.

@ProgrammerDan sohbetinde ;').replace(', str.format()metni biçimlendirme ön yöntemini kullanmak için, içinde dize bulunan bir demet kullanma 4 kez ortaya çıktı. %sİkinci satırdaki dizgide dört örnek vardır, her biri değerini sondaki demetin ilişkili öğesinden alır. Hepsi aynı olduklarından, her biri %sile değiştirilir ;').replace('. İşlemleri gerçekleştirdiğinizde şu dizeyi alırsınız:

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

Bu, artık yürütülebilen geçerli bir python kodudur exec. Bu doğru, bebeğim: Nested execs, kod üzerinde dize işlemleri gerçekleştirmek için gereken dize işlemlerini kullanmama izin verin . Birisi lütfen beni öldür.

Geri kalanı oldukça basittir: Her komut üç değişkenin kaydını tutan kodla değiştirilir: Geçerli konum, sondan bu yana hak sayısı ->ve sol ve için aynı <-. Her şey çalıştırılır ve konum yazdırılır.

raw_input(';')';' Kullanarak yaptığımı fark edeceksiniz. istem olarak değil raw_input(), istem olarak. Bu, karakterleri sezgisel olmayan bir şekilde kaydeder: Eğer olsaydım raw_input(), tuple ile dolu olmalıydım ).replace('ve her örneğinin birincisi dışında%s '; \' 'olması gerekirdi . Bir bilgi istemi daha fazla yedeklilik yaratır, böylece genel olarak daha fazla karakter kaydedebilirim.


2
" karakteri bulamadığında list.index()geri döner -1" .. erm no. Bir yükseltir IndexError. Onunla karıştırmış olabilirsiniz str.find. Aslında [list('><rl').index(c)]ile değiştirebilirsiniz ['><rl'.find(c)].
Şubat'ta Bakuriu

... Ha, doktora baktım ve -1 döndürdüğüne yemin edebilirdim. Özellikle listelerin sayfasıydı, bu yüzden ne okuduğum hakkında hiçbir fikrim yok. Her neyse, yardım için teşekkürler, cevabı düzenleyeceğim.
undergroundmonorail

5

Perl, 134 131 ... 99 95 bayt

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

Girişi stdin'de tek bir satır olarak alır, örneğin:

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

veya:

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

Talimatları "sağ" operatörlere (">" ve "->") ve "sol" operatörlere ("<" ve "<-") böldüm. Bunun avantajları, sol ve sağ operatörler arasındaki paralellikten faydalanmanın daha kolay olmasıdır ve ipi tokenize etmek için fantezi bir şey yapmamız gerekmiyor. Her bir "yön", ikame işlemi olarak ele alınır; burada, toplam toplamı, bu yönde atılan adım sayısına göre ayarlar, diğer ikame işlemi tarafından halledilen ters yönü göz ardı eder. İşte bir tür dokümantasyon olarak bu kodun daha az golf oynayan bir atası:

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

Bu kodun önceki bir yinelemesinde, sübstitüsyonların hepsi bir geçişte yapıldı. Bu, $ p / $ pos ile belirli bir zamanda döndürülecek konum arasında doğrudan bir eşleme tutma avantajına sahipti, ancak daha fazla bayt kod aldı.

() 5.10.0 kullanmak istiyorsanız, sayıdan başka 2 karakter daha tıraş etmek için s / print / say / kullanabilirsiniz, ancak bu benim tarzım değil.


4

Perl, 88 77 bayt

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

Giriş STDIN üzerinden bekleniyor, örneğin:

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

Güncelleme

Dizeyi bir toplamaya dönüştürmeye gerek yoktur, çünkü s//zaten sayılmaktadır. :-)

İlk versiyon

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

Giriş STDIN üzerinden bekleniyor, örnek:

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

Açıklama:

Fikir, yön dizesini bir sonuca dönüştürerek sonucun basit bir çıktıyla dönüştürülmesidir print eval.

>herhangi ->biri önce biri diğeri diğeri olmak üzere iki adım alır ->. Hangisinin ->en az birini takip ettiği önemli değil . Dahili sayaç bir sonraki adımdan sonra sıfırlanır ->, bu nedenle >başka adımlara neden olmaz, maksimum iki adımdır. Sonra ->kendisi için bir adım ekler >ve sondan sonra kalanları da ekleyin ->.

Aynısı, pozitif adım sayıları yerine negatif olan geriye doğru yönde geçerlidir.

Örneğin: ><->><-<-><-<>>->

s/->/+1/: İleri yönde başlayın, çünkü ->en yüksek önceliğe sahiptir.
Örneğin:><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: Sadece ileriye bakma desen güvence veriyor >herhangi önce ->dönüştürülür.
Örneğin:+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: Şimdi kalanlar >kapsanıyor.
Örneğin:+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: Geriye doğru yön analog.
Örneğin:+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: İleriye bakma desen olarak tam -1birincisinin <-hiçbir olduğundan, gerekli değildir -sol yön sembolleri.
Örneğin:+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: Sonuncudan <sonra kalanlar <-dönüştürülür.
Örneğin:+2-2+1+2-1-2+1-1-1+2+2+1

print eval: Sonucu hesaplayın ve çıktı alın.
Örneğin:4


İyi bir. Dün gece bu kavramın etrafında dolaşıyordum ama bugüne kadar uygulamayı denemek için bir şansım yoktu. İyi bir şey ben yazı kontrol ve zaten vardı gördüm =)
skibrianski

@skibrianski: Kopyala ve yapıştır hatasını düzelttiğiniz için teşekkür ederiz.
Heiko Oberdiek

: Biraz daha golfed edilebilir 65 bayt kullanmadan, Ya -p: 74 bayt Seninkini değişti s/>//getmek y/>//de ifadesinde Pars uzaklaştırılması için izin her durumda bir byte kaydedin.
Xcali

2

Ruby, 141 bayt

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

Birkaç hızlı kazanç: l=1;r=1olabilir l=r=1ve $><<oolabilir p o. Sanırım bu dava ifadesini daha az hantal bir şeyle, belki de çizgiler boyunca bir şeyle değiştirerek çok fazla tıraş olabilirsinizeval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge

Aslında eval yaklaşımıyla daha da fazla tasarruf etmek için bazı önekleri / sonekleri çıkarabilirsiniz. Bu 98 karakter:, l=r=1;o=0;gets.gsub('->',??).scan(/<-|./){eval"o+=#{%w[-1;l+ -l;l 1;r+ r;r][$&[-1].ord%4]}=1"};p o94 kullanarak aşağı gidebilirsinizruby -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;}}

Golf hariç :

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

Gerekli çıktı başlangıçta söz konusuydu. Şimdi vurguladım ve daha fazla açıklama ekledim.
Terbiyeli Dabbler

Tamam, şimdi sonucu çıkarmak için cevabımı düzenledim.
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;}

Boşluk ile:

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

Muhtemelen bu golf için çok daha fazla yer. Çoğunlukla lvalues ​​(daha uzun çıkıp daha sonra çıkmaya devam etti) yakalayan üçlülerde 4 değişkeni manipüle etmeye çalışmaktan vazgeçtim, ama kötü bir ilk geçiş değil. Oldukça düz ileri dizi geçişi. Komut satırı bağımsız değişkeni olarak girdi alır, dönüş değeri üzerinden çıktı alır.

-std=c99Gcc ile derlemek için bayrağa ihtiyacınız olacak.

EDIT: Evet, geç oldu - bazı açık şeyler kaçırdı.


Sen argüman listesinde iki boşluk kaldırabilirsiniz main: main(char*x,char**v). Sonra 140 yerine 138 var.
Heiko Oberdiek

Bir hata var: >><-1 yerine 0 verir veya ><->2 yerine 0 verir
Heiko Oberdiek

Arasında kaldır boşluk varsa 4 bayt kaydedebilir charve *, ve değiştirme (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)ile (*++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)

Nasıl çalışır

Aşağıdaki gibi bir dize girdisi verildi s:

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

Her komutu, z(son konum), l(soldaki hareketleri rsaklar ) ve kaydedilen sağ hareketleri değiştiren bir dizi talimatla değiştirmek için bir Regex kullanır . Her Regex öncelik sırasına göre gerçekleştirilir.

Yukarıdaki giriş için bu, şuna dönüştürülür 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;"

Güzel, değil mi?

Son olarak , son konumu içeren eval(s)talimatları ve uyarıyı gerçekleştiririz z.


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 bayt]

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)

Muhtemelen biraz daha kısaltılabilir ...


0

PHP, 284 282

Normal ifade yok.

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

İle 2 karakter kazanabilirsiniz str_split($i)( 1ikinci argüman için varsayılan değerdir.) Ve $imuhtemelen $cdoğru mu?
Terbiyeli Dabbler

İlk satır yanlıştı (öyleydi $i): P Çözüldü!
Vereos

0

Başka bir perl çözümü, 113 karakter

Bunu yenen iki cevap zaten var, sadece kıkırdamalar için. Ilmari'nin tokenlerin değeri hakkındaki gözlemine dayanan bir yaklaşım kullanır:

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

Biraz patladı:

$_=<>;
chomp;
s/->/#/g;
s/<-/%/g;
s/>(?=.*#)/?/g;
s/<(?=.*%)/;/g;
s/#/>/g;
s/%/</g;
$t+=ord for split//;
print$t-61*length
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.