Brainf * arah ckish

14

Tugas Anda - jika Anda memilih untuk menerimanya - adalah membangun sebuah program yang mem-parsing dan mengevaluasi string (dari kiri ke kanan dan panjang sewenang-wenang) dari token yang memberikan arahan - baik kiri atau kanan. Berikut adalah empat token yang mungkin dan artinya:

>  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

Namun ada kendala - token arah yang harus diurai oleh program Anda akan disajikan dalam formulir ini:

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

... dengan kata lain, mereka digabungkan, dan itu adalah tugas program Anda untuk menentukan prioritas yang benar dari arah dan jumlah langkah yang harus diambil (dengan melihat ke depan). Urutan prioritas adalah sebagai berikut (dari prioritas tertinggi ke terendah):

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

Jika Anda menemukan <-ketika tidak ada langkah ke kiri yang telah dilakukan sejak awal atau sejak reset terakhir, ambil satu langkah tunggal ke kiri. Aturan yang sama berlaku untuk ->, tetapi kemudian untuk ke kanan.

Program Anda harus mulai dari 0 dan hasilnya harus berupa bilangan bulat bertanda tangan yang mewakili posisi akhir.

Anda mungkin berharap input selalu valid (jadi, tidak seperti <--->>--<, misalnya).

Input contoh:

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

Langkah-langkah dalam contoh ini:

 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  

Untuk klarifikasi: output dari program hanya harus menjadi posisi akhir sebagai integer yang ditandatangani. Tabel di atas hanya ada untuk menggambarkan langkah-langkah yang diambil contoh saya. Tidak perlu menampilkan tabel seperti itu, baris tabel, atau bahkan hanya posisi akhir langkah. Hanya posisi akhir akhir, sebagai bilangan bulat yang ditandatangani, yang diperlukan.

Kode terpendek, setelah satu minggu, menang.

Dabbler yang Layak
sumber
4
Jika saya memahami aturan presedensi dengan benar, satu-satunya waktu Anda dapat meminta <-adalah jika segera diikuti oleh a <atau a ->. Tidak ada cara dalam bahasa ini untuk mewakili urutan <-itu >- yang akan terjadi go left the total amount of single steps that you've gone left, plus one, then go right one single step. Apakah ini benar dan sesuai desain?
Adam Davis
@AdamDavis Anda benar. Sayangnya, itu agak lalai bagi saya.
Decent Dabbler

Jawaban:

6

GolfScript, 46 karakter

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

Ini adalah salah satu program GolfScript paling linier yang pernah saya tulis - tidak ada satu pun loop, kondisional atau penugasan variabel di dalamnya. Semuanya dilakukan dengan menggunakan manipulasi string:

  • Pertama, saya mengganti setiap kemunculan ->oleh ). Karena input dijamin valid, ini memastikan bahwa setiap kejadian yang tersisa -harus menjadi bagian dari <-.

  • Selanjutnya, saya membuat dua salinan string. Dari salinan pertama, saya menghapus karakter <dan -, hanya menyisakan >dan ). Saya kemudian menduplikasi hasilnya, menghapus semua )dan setiap >mengikuti yang terakhir )dari salinan kedua, menggabungkan mereka dan menghitung karakter. Jadi, pada dasarnya, saya menghitung:

    • +1 untuk masing-masing ),
    • +1 untuk masing-masing >setelah yang terakhir ), dan
    • +2 untuk masing-masing >sebelum yang terakhir ).
  • Selanjutnya, saya melakukan hal yang sama untuk salinan lain, kecuali kali ini menghitung <dan <-bukannya >dan ), dan menghapus -s sebelum penghitungan karakter akhir. Jadi, saya hitung:

    • +1 untuk masing-masing <-,
    • +1 untuk masing-masing <setelah yang terakhir <-, dan
    • +2 untuk masing-masing <sebelum yang terakhir <-.
  • Akhirnya, saya kurangi jumlah kedua dari yang pertama, dan hasilkan hasilnya.

Ilmari Karonen
sumber
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

Perubahan serius telah dilakukan terhadap cara kerja program ini. Saya telah menghapus penjelasan lama, yang masih dapat ditemukan di riwayat edit jawaban ini.

Yang ini kotor.

Cara kerjanya hampir sama dengan jawaban lain untuk pertanyaan ini, mengganti karakter dalam input dengan pernyataan yang valid dalam bahasa itu dan menjalankannya. Namun, ada satu perbedaan utama: replacekata yang panjang. Persetan dengan itu.

@ProgrammerDan dalam obrolan muncul dengan gagasan menggunakan tuple dengan string ;').replace('di dalamnya 4 kali, untuk menggunakan str.format()metode pra -format teks. Empat contoh %sberada di string pada baris kedua, masing-masing mengambil nilainya dari elemen terkait tuple di akhir. Karena semuanya sama, masing %s- masing diganti ;').replace('. Saat Anda melakukan operasi, Anda mendapatkan string ini:

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

Ini sekarang kode python yang valid yang dapat dieksekusi dengan exec. Benar, sayang: Sarang execsaya gunakan operasi string pada kode yang perlu melakukan operasi string pada kode . Seseorang tolong bunuh aku.

Sisanya cukup mudah: Setiap perintah diganti dengan kode yang melacak tiga variabel: Posisi saat ini, jumlah hak sejak terakhir ->, dan yang sama untuk kiri dan <-. Semuanya dijalankan dan posisinya dicetak.

Anda akan melihat bahwa saya melakukannya raw_input(';'), menggunakan ';' sebagai prompt, daripada raw_input()yang tidak memiliki prompt. Ini menyimpan karakter dengan cara yang tidak intuitif: Jika saya melakukannya raw_input(), saya harus mengisi tuple ).replace(', dan setiap instance %sakan memiliki '; \' 'sebelum itu kecuali yang pertama . Memiliki prompt menciptakan lebih banyak redundansi sehingga saya dapat menyimpan lebih banyak karakter secara keseluruhan.

monmon bawah tanah
sumber
2
" list.index()kembali -1ketika gagal menemukan karakter" .. erm no. Itu menimbulkan IndexError. Anda mungkin bingung dengan itu str.find. Bahkan Anda bisa menggantinya [list('><rl').index(c)]dengan ['><rl'.find(c)].
Bakuriu
... Huh, saya mencarinya di dokumen dan bisa bersumpah katanya kembali -1. Itu khusus halaman untuk daftar, jadi saya tidak tahu apa yang saya baca. Bagaimanapun, terima kasih atas bantuannya, saya akan mengeditnya menjadi jawabannya.
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

Mengambil input sebagai satu baris di stdin, misalnya:

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

atau:

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

Saya membagi instruksi menjadi operator "kanan" (">" dan "->") dan "kiri" ("<" dan "<-"). Keuntungan dari hal ini adalah bahwa lebih mudah untuk mengeksploitasi paralelisme antara operator kiri dan kanan, dan kita tidak perlu melakukan hal-hal lain untuk mengubah token string. Setiap "arah" ditangani sebagai operasi substitusi di mana kami menyesuaikan total running dengan jumlah langkah yang diambil ke arah itu, mengabaikan arah sebaliknya yang ditangani oleh operasi substitusi lainnya. Berikut adalah leluhur yang kurang golf dari kode ini sebagai semacam dokumentasi:

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

Dalam iterasi sebelumnya dari kode ini, semua penggantian dilakukan dalam satu pass. Ini memiliki keuntungan menjaga pemetaan langsung antara $ p / $ pos dan posisi yang akan dikembalikan pada titik waktu tertentu, tetapi mengambil lebih banyak byte kode.

Jika Anda ingin menggunakan () 5.10.0, Anda dapat s / print / say / untuk mencukur 2 karakter lainnya, tetapi itu bukan gaya saya.

skibrianski
sumber
4

Perl, 88 77 byte

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

Masukan diharapkan melalui STDIN, misalnya:

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

Memperbarui

Tidak perlu mengubah string ke penjumlahan, karena s//sudah menghitung. :-)

Versi pertama

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

Masukan diharapkan melalui STDIN, contoh:

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

Penjelasan:

Idenya adalah untuk mengubah string arah menjadi penjumlahan sehingga hasilnya adalah keluaran dengan sederhana print eval.

>sebelum apa pun ->mengambil dua langkah, satu sekaligus dan yang lainnya di berikutnya ->. Tidak masalah, yang mana dari ->saat itu mengikuti setidaknya satu dari mereka. Penghitung internal diatur ulang setelah yang berikutnya ->, sehingga >tidak menyebabkan langkah lebih lanjut, maksimumnya adalah dua langkah. Kemudian ->tambahkan satu langkah untuk dirinya sendiri dan begitu juga yang tersisa >setelah yang terakhir ->.

Hal yang sama berlaku untuk arah mundur dengan jumlah langkah negatif bukannya positif.

Misalnya: ><->><-<-><-<>>->

s/->/+1/: Mulai dengan arah maju, karena ->memiliki prioritas tertinggi.
Misalnya:><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: Pola lihat-depan memastikan bahwa hanya yang >sebelum ->dikonversi.
Misalnya:+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: Sekarang sisanya >tertutup.
Misalnya:+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: Analog dengan arah mundur.
Misalnya:+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: Dalam pola melihat-depan penuh -1dari mantan <-tidak diperlukan, karena tidak ada -satu simbol arah kiri.
Misalnya:+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: Sisa <setelah yang terakhir <-dikonversi.
Misalnya:+2-2+1+2-1-2+1-1-1+2+2+1

print eval: Hitung dan keluarkan hasilnya.
Misalnya:4

Heiko Oberdiek
sumber
Bagus Saya menendang konsep ini tadi malam tetapi tidak memiliki kesempatan untuk mencoba menerapkannya sampai hari ini. Untung saya memeriksa posting dan melihat Anda sudah =)
skibrianski
@skibrianski: Terima kasih telah memperbaiki kesalahan salin & tempel.
Heiko Oberdiek
Dapat golfed sedikit lebih: 65 bytes Atau, tanpa menggunakan -p: 74 byte saya mengubah Anda s/>//guntuk y/>//menyimpan byte dalam setiap kasus yang juga memungkinkan untuk penghapusan parens dalam ekspresi.
Xcali
2

Ruby, 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

Tidak Disatukan:

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.
sumber
Beberapa kemenangan cepat: l=1;r=1bisa l=r=1dan $><<obisa p o. Saya pikir Anda bisa mencukur banyak dengan mengganti pernyataan kasus dengan sesuatu yang kurang besar, mungkin sesuatu di sepanjang gariseval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge
Bahkan dengan pendekatan eval Anda dapat menarik beberapa awalan / sufiks untuk menyimpan lebih banyak lagi. Ini adalah 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 oAnda bisa turun ke 94 menggunakanruby -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;}}

Tidak 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;
}
Tony Ellis
sumber
Output yang dibutuhkan awalnya dalam pertanyaan. Saya sudah menyorotnya sekarang, dan menambahkan klarifikasi lebih lanjut.
Decent Dabbler
Benar, saya sudah mengedit jawaban saya untuk menampilkan hasilnya sekarang.
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;}

Dengan spasi putih:

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

Mungkin lebih banyak ruang untuk bermain golf ini. Sebagian besar saya menyerah untuk mencoba memanipulasi 4 variabel di terner yang menangkap nilai-nilai (itu terus keluar lebih lama dan semakin belakangan), tetapi tidak lulus pertama yang buruk. Pass array yang cukup lurus ke depan. Mengambil input sebagai argumen baris perintah, menghasilkan melalui nilai balik.

Anda perlu -std=c99bendera untuk mengompilasinya dengan gcc.

EDIT: Ya, sudah terlambat - melewatkan beberapa hal yang jelas.

Komintern
sumber
Anda dapat menghapus dua ruang dalam daftar argumen main: main(char*x,char**v). Maka Anda memiliki 138 bukannya 140.
Heiko Oberdiek
Ada bug: >><-memberi 0 bukannya 1 atau ><->memberi 0 bukannya 2.
Heiko Oberdiek
Anda dapat menyimpan 4 byte jika Anda menghapus spasi di antara chardan *, dan menggantinya (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)dengan (*++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)

Tidak dijinakkan:

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)

Bagaimana itu bekerja

Diberikan input string sseperti ini:

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

Ia menggunakan Regex untuk mengganti setiap perintah dengan satu set instruksi yang memodifikasi z(posisi akhir), l(gerakan kiri tersimpan) dan rgerakan kanan tersimpan. Setiap Regex dilakukan dalam urutan prioritas.

Untuk input di atas ini dikonversi ske:

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

Cantik, bukan?

Akhirnya kita eval(s)melakukan instruksi dan peringatan zyang berisi posisi akhir.

George Reith
sumber
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
sumber
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)

Mungkin bisa dipersingkat sedikit lebih ...

Penglihatan
sumber
0

PHP, 284 282

Tidak ada 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;

Tidak Disatukan:

$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
sumber
Anda dapat memenangkan 2 karakter dengan str_split($i)( 1apakah default untuk argumen kedua.) Dan $imungkin seharusnya $c, benar?
Decent Dabbler
Baris pertama salah (benar $i): P Memperbaikinya!
Vereos
0

Solusi perl lain, 113 karakter

Sudah ada dua jawaban yang mengalahkan ini, hanya untuk cekikikan. Ini menggunakan pendekatan berdasarkan pengamatan Ilmari tentang nilai token:

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

Meledak sedikit:

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