Perluas otak terkompresi

26

Tantangan ini diposting sebagai bagian dari tantangan LotM April 2018 , serta untuk ulang tahun 2nd Brain-flak


Saya sedang berpikir tentang apa cara paling efisien untuk menyandikan program brain-flak. Hal yang jelas harus dilakukan, karena hanya ada 8 karakter yang valid, adalah memetakan setiap karakter ke urutan 3-bit. Ini tentu sangat efektif, tetapi masih sangat berlebihan. Ada beberapa fitur kode brain-flak yang dapat kita manfaatkan untuk mempersingkat pengodean.

  • Nilad, yang semuanya diwakili oleh 2 tanda kurung yang cocok, benar-benar bertindak sebagai satu unit informasi daripada 2. Jika kita mengganti setiap braket dengan karakter byte tunggal, ini akan membuat pengkodean jauh lebih kecil tanpa kehilangan data.

  • Yang ini kurang jelas, tetapi byte penutup dari monad juga berlebihan. Pikirkan Anda dapat menebak apa yang '?'dilambangkan karakter dalam cuplikan berikut?

     {(({}?<>?<>?
    

    Jika kita asumsikan inputnya adalah kode anti-otak yang valid, maka hanya ada satu opsi untuk masing-masing tanda tanya itu. Ini berarti bahwa kita dapat menggunakan karakter close monad untuk mewakili setiap braket penutup. Ini memiliki manfaat tambahan menjaga karakter tetap kecil, yang akan sangat membantu jika kita ingin menggunakan pengodean huffman. Karena karakter monad dekat kemungkinan besar akan menjadi karakter paling umum dengan margin lebar, itu bisa diwakili oleh bit tunggal, yang sangat efisien.

Dua trik ini akan memungkinkan kita memampatkan kode brain-flak melalui algoritma berikut:

  1. Ganti setiap braket penutup dari monad dengan |. Atau dengan kata lain, ganti setiap braket penutup yang tidak didahului dengan pertandingan pembuka dengan bilah. Begitu...

    (({})<(()()())>{})
    

    akan menjadi

    (({}|<(()()()||{}|
    
  2. Ganti setiap nilad dengan braket penutupnya. Karenanya, kurung yang cocok dengan tidak ada di dalamnya menggunakan pemetaan berikut:

    () --> )
    {} --> }
    [] --> ]
    <> --> >
    

    Sekarang contoh terakhir kita menjadi:

    ((}|<()))||}|
    
  3. Hapus |karakter tambahan. Karena kita tahu bahwa jumlah total bar harus sama dengan jumlah ({[<karakter, jika ada bar pada akhirnya hilang, kita dapat menyimpulkannya. Jadi contohnya seperti:

    ({({})({}[()])})
    

    akan menjadi

    ({(}|(}[)
    

Tantangan Anda untuk hari ini adalah membalikkan proses ini.

Diberikan string brain-flak terkompresi yang hanya berisi karakter (){}[]<>|, memperluasnya ke kode brain-flak asli. Anda dapat mengasumsikan bahwa input akan selalu berkembang menjadi brain-flak yang valid. Ini berarti bahwa tidak ada awalan input yang akan mengandung lebih |dari ({[<karakter.

Input tidak akan mengandung |karakter tambahan. Ini harus disimpulkan dari konteks.

Seperti biasa, Anda dapat mengirimkan program atau fungsi lengkap, dan format input / output permisif. Dan karena ini adalah , kode Anda akan dinilai oleh panjang kode sumber dalam byte, semakin kecil skor semakin baik.

Uji kasus

Berikut ini beberapa test case. Jika Anda menginginkan lebih, Anda dapat membuat kotak uji Anda sendiri dengan skrip python ini dan Brain-Flak Wiki , yang merupakan asal sebagian besar kotak uji ini.

#Compressed code
#Original code

())))
(()()()())


([([}()||||(>||{(})|>|}{((<}|||>}|}>}
([([{}(())])](<>)){({}())<>}{}{((<{}>))<>{}}{}<>{}

({(}|(}[)|||}
({({})({}[()])}{})


(((()))||(](((}}||(}([(((}))||||(]((}}|}|}}|||]||]|[))||(}))|}(}|(}]]|}
((((()()()))([]((({}{}))({}([((({}()())))]([](({}{}){}){}{})))[]))[])[()()])({}()()){}({})({}[][]){}
DJMcMayhem
sumber
4
jenius. sangat jenius. Anda harus membuat bahasa turunan.
NH.
8
@NH. Secara pribadi, saya merasa bahasa yang hanya berbeda dalam pengodeannya benar-benar membosankan.
DJMcMayhem
1
@ Dj tetapi yang ini akan memakan waktu lebih sedikit byte dan karenanya lebih baik untuk bermain golf.
NH.
5
Brain-Flak tidak dirancang untuk menjadi pandai golf.
DJMcMayhem

Jawaban:

32

Brain-Flak , 952 916 818 byte

{(({})[(((()()()()()){}){}){}])((){[()](<{}>)}{}){{}(({})()<>)(<>)}{}(<>)<>(({})[(((()()()){}){}()){({}[()])}{}])((){[()](<{}>)}{})({}<>{})<>(({})[((((()()()()()){}){})){}{}])((){[()](<{}>)}{})({}<>{})<>(({})[(((((()()()()()){}){}){}())){}{}])((){[()](<{}>)}{})({}<>{}){{}(<(<>({})()()<>)>)}{}<>(({})[(((()()()()()){}){}){}()])((){[()](<{}>)}{}){{}(({})[()])(<>)<>(<({}<{({}<>)<>}{}>)>)<>{({}<>)<>}{}(<>)}{}(<>)<>(({})[(((((()()()()()){})){}{}())){}{}])((){[()](<{}>)}{})({}<>{})<>(({})[((((()()()()()){}){})()){}{}])((){[()](<{}>)}{})({}<>{})<>(({})[(((((()()()()()){}){}){}())()){}{}])((){[()](<{}>)}{})({}<>{}){{}<>(<(({})[()()])(<>)<>(<({}<{({}<>)<>}{}>)>)<>{({}<>)<>}{}>)}{}<>(({})[(((((()()()()()){}){})()){}{}){}])((){[()](<{}>)}{}){{}{}(<(<>{}<>)>)}{}(<>)<>(<({}<{({}<>)<>}{}>)>)<>{({}<>)<>}{}<>}{}{({}<>)<>}<>

Disimpan 360 byte dengan menghitung kurung berlawanan secara relatif daripada dari awal (mis ')'= '(' + 1bukan (((5 * 2) * 2) * 2) + 1)

Disimpan 34 byte dengan beberapa penggantian langsung dari DJMcMayhem

Disimpan 10 byte dengan tumpang tindih >]}kode penanganan

Disimpan 118 byte dengan gulungan deduplicating

Disimpan 40 byte dengan memanfaatkan tumpukan kosong untuk menyederhanakan gulungan pertama

Disimpan 48 byte dengan menandai EOF dengan -1, memungkinkan kode roll lebih ringkas

Disimpan 36 byte dengan menggunakan logika sama dengan saham bukan milikku

Disimpan 98 byte berkat Jo King menemukan cara yang lebih efisien untuk membangun output

Cobalah online!

Pertama kali bermain golf di Brain-Flak, jadi mungkin ada beberapa peningkatan yang sangat besar, tetapi berhasil. Banyak salinan / tempel untuk menangani setiap jenis braket, dan terima kasih banyak untuk generator integer otomatis dan cuplikan Roll dari sini .

Penjelasan di sini , format TIO lebih mudah

Jawaban bonus:

Brain-Flak Terkompresi 583 byte

{((}|[((()))))|}|}|}||(){[)|(<}|||}|{}((}|)>|(>||}(>|>((}|[((()))|}|})|{(}[)|||}||(){[)|(<}|||}|(}>}|>((}|[(((()))))|}|}||}}||(){[)|(<}|||}|(}>}|>((}|[((((()))))|}|}|})||}}||(){[)|(<}|||}|(}>}|{}(<(>(}|))>||||}>((}|[((()))))|}|}|})||(){[)|(<}|||}|{}((}|[)||(>|>(<(}<{(}>|>|}||||>{(}>|>|}(>||}(>|>((}|[((((()))))|}||}})||}}||(){[)|(<}|||}|(}>}|>((}|[(((()))))|}|}|)|}}||(){[)|(<}|||}|(}>}|>((}|[((((()))))|}|}|})|)|}}||(){[)|(<}|||}|(}>}|{}>(<((}|[))||(>|>(<(}<{(}>|>|}||||>{(}>|>|}|||}>((}|[((((()))))|}|}|)|}}|}||(){[)|(<}|||}|{}}(<(>}>||||}(>|>(<(}<{(}>|>|}||||>{(}>|>|}>|}{(}>|>|>

Cobalah online!

(Perhatikan bahwa tautan di atas tidak berjalan karena TIO tidak memiliki penerjemah Brain-Flak Terkompresi. Anda dapat menemukan transpiler ke Brain-Flak di sini )

Saya telah memeriksa bahwa ini valid dengan mentransformasikan ke Brain-Flak menggunakan alat ini , sekarang cukup efisien sehingga pengaturan waktu tidak memungkinkan.

Kamil Drakari
sumber
4
Pertama kali bermain golf di Brain-Flak, dan hasilnya adalah ini? Wow.
Erik the Outgolfer
Anda selalu dapat menggantinya <>(<()>)dengan (<>). Anda juga dapat mengubah (<>{}<>)(<()>)ke(<(<>{}<>)>)
DJMcMayhem
1
@JoKing Saya tidak tahu caranya, saya hampir tidak berhasil mengekstraksi Roll pada akhir loop daripada memiliki satu ekstra di setiap blok If
Kamil Drakari
1
Ini di luar golf .. Ini benar-benar kegilaan. Selamat!
Arthur Attout
1
@JoKing Perubahan itu lebih mudah dan lebih efektif dari yang saya harapkan, dan sekarang termasuk dalam jawabannya
Kamil Drakari
7

Retina 0.8.2 , 103 98 byte

[])}>]
$&;
T`])}>|`[({<;
r`(.*)((;)|(?<-3>.))*
$&$.1$*;
(?<=(.)((;)|(?<-3>.))*);
;$1
T`;-{`_>-}`;.

Cobalah online! Tautan termasuk kasus uji. Sunting: Disimpan 5 byte dengan inspirasi dari @MartinEnder. Penjelasan:

[])}>]
$&;
T`])}>|`[({<;

Letakkan ;setelah setiap braket dekat dan mengubah mereka semua untuk kurung terbuka, dan mengubah |s untuk ;s juga.

r`(.*)((;)|(?<-3>.))*
$&$.1$*;

Hitung jumlah tanda kurung terbuka yang tidak cocok dan tambahkan banyak ;.

(?<=(.)((;)|(?<-3>.))*);
;$1

Salin setiap braket pembuka ke pencocokannya ;.

T`;-{`_>-}`;.

Balikkan kurung yang disalin dan hapus ;s.

Neil
sumber
1
Anda dapat menghindari semua bilah yang lolos jika menerjemahkan |ke sesuatu seperti !. Itu tidak akan bahkan byte biaya jika Anda menerjemahkan >-}ke <-{(yang saya pikir memberikan zuntuk |).
Martin Ender
@ MartinEnder Tidak yakin saya mengerti maksud Anda tentang ztetapi saya datang dengan cara mencukur beberapa byte lagi.
Neil
5

TIS , 670 666 byte

-4 byte untuk melompat maju untuk melompat kembali

Kode:

@0
MOV UP RIGHT
@1
MOV ANY ACC
SUB 41
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
MOV ACC DOWN
@2
NOP
MOV 124 LEFT
@3
MOV ANY DOWN
@4
MOV UP ACC
JGZ O
MOV 40 LEFT
JLZ (
MOV 41 LEFT
JRO 3
O:SUB 21
MOV ACC DOWN
JRO -8
(:MOV 41 RIGHT
@5
MOV ANY DOWN
@6
MOV ANY DOWN
@7
MOV UP ACC
JGZ O
MOV 60 LEFT
JLZ <
MOV 62 LEFT
JRO 3
O:SUB 31
MOV ACC DOWN
JRO -8
<:MOV 62 RIGHT
@8
MOV ANY DOWN
@9
MOV ANY DOWN
@10
S:MOV UP ACC
JGZ O
MOV 91 LEFT
JLZ [
MOV 93 LEFT
JRO 3
O:SUB 31
MOV ACC DOWN
JRO -8
[:MOV 93 RIGHT
@11
MOV ANY DOWN
@12
MOV ANY DOWN
@13
MOV UP ACC
JEZ |
MOV 123 LEFT
JLZ {
MOV 125 LEFT
JRO 2
|:MOV DOWN LEFT
JRO -7
{:MOV 125 RIGHT
@14
MOV ANY DOWN
@15
MOV UP DOWN
@16
MOV UP LEFT

Tata ruang:

6 3
CCCCCCCCCCCCCCCCSC
I0 ASCII -
O0 ASCII -

Cobalah online!

Saya ragu ini terkecil, tapi saya tidak melihat cara untuk membuatnya lebih kecil. Sayangnya, semua NOPtampaknya perlu untuk menentukan waktu, dan saya tidak bisa meletakkan tumpukan di mana @14saat ini karena membaca dari ANYdalam @11.

Struktur solusi ini adalah sebagai berikut:

Input
  |
  V
  0    1:synchro  2:EOF
  3    4:parens     5
  6    7:angles     8
  9   10:squares   11
 12   13:curlies   14
 15      stack     16
  |
  V
Output

Setelah melihat penjepit terbuka, buka dikirim sepanjang kolom kiri untuk menjadi output, dan tutup dikirim sepanjang kolom kanan ke tumpukan.

Setelah melihat penjepit dekat, buka dan tutup keduanya dikirim di sepanjang kolom kiri untuk menjadi output.

Setelah melihat pipa, tumpukan muncul dan dikirim ke keluaran.

Setelah EOF, @1akan mulai membaca dari @2, bukannya input stream dari @0. @2menghasilkan aliran pipa tanpa akhir, sehingga tumpukan akan dikeringkan.

Setelah input dan tumpukan habis, program berhenti.

Peringatan: karena keterbatasan TIS, ukuran tumpukan dibatasi hingga 15. Jika ada yang bersarang lebih dalam dari itu, implementasi ini akan menghasilkan hasil yang salah.

Phlarx
sumber
4

JavaScript (ES6), 107 byte

Mengambil input sebagai array karakter. Mengembalikan string.

a=>a.map(c=>(n=(S='|()[]{}<>').indexOf(c))?n&1?(s=[S[n+1],...s],c):S[n-1]+c:s.shift(),s=[]).join``+s.join``

Cobalah online!

Arnauld
sumber
102 byte dengan mengembalikan array karakter juga.
Shaggy
@Shaggy Terima kasih! Tetapi apakah benar-benar diperbolehkan untuk mengembalikan string 1-karakter dan 2-karakter dicampur bersama?
Arnauld
Hmm ... ya, mungkin itu mendorongnya pada output "permisif".
Shaggy
@DJMcMayhem Bisakah Anda melihat format output baru dan beri tahu kami apakah itu dapat diterima?
Arnauld
1
@arnauld Huh, untuk beberapa alasan itu tidak mem-ping saya. Saya pikir saya akan mengatakan tidak. Array karakter atau satu string keduanya format standar, tetapi array string tampaknya tidak berlaku untuk saya
DJMcMayhem
3

Ruby , 104 byte

a=[];$<.chars{|c|r="|[{(<>)}]";i=r.index(c);i<1||(i<5?a:$>)<<r[-i];$>.<<i<1?a.pop: c};$><<a.reverse.join

Ini adalah program lengkap yang di-output ke konsol. (i<5?a:$>)<<r[-i]harus menjadi salah satu golf paling keren yang pernah saya lakukan.

Cobalah online!

Ruby , 106 byte

->s{a=[];(s.chars.map{|c|r="|>)}][{(<";d=r[-i=r.index(c)];i<5||a<<d;i<1?a.pop: i<5?d+c:c}+a.reverse).join}

Ini solusi pertama saya. Fungsi lambda anonim yang mengambil dan mengembalikan string.

Cobalah online!

MegaTom
sumber
3

Brain-Flak , 606 548 496 418 394 390 byte

{((({})))(<>)(((((((([(())()()()]){}){}){}())(()))(((())()())()){}{})){}[()])({<(({}<>{}[()]))>(){[()](<{}>)}{}<>}{}<><{}>){({}({})<>)(<>)}{}({}<>)(<>)(((((((([(())()()()]){}){}){}())(()))(((())()){}()){})){})({<(({}<>{}[()]))>[()]{()(<{}>)}{}<>}{}<>){(<({}(<()>)<>({})<{({}<>)<>}>)>)<>{({}<>)<>}}{}({}()<>){{}({}<>)((<>))}{}{}<>(<({}(<()>)<><{({}<>)<>}>)>)<>{({}<>)<>}{}<>}{}{({}{}<>)<>}<>

Cobalah online!

Saya memulai ini dengan memasukkan jawaban Kamil Drakari , tetapi itu menjauh dari saya sampai saya memutuskan untuk mempostingnya sebagai jawaban terpisah.

Penjelasan:

{ #While input on stack
	((({})))(<>)	#Preserve copy of the character
	(((((		#Push the differences between start bracket characters
	((([(())()()()]){}){}){}())	#Push -31, 1
	(()))				#Push -30, 1
	(((())()())()){}{})		#Push -19, 1
	){}[()])			#Push -39
	({<(({}<>{}[()]))>(){[()](<{}>)}{}<>}{}<><{}>)	#If the character is any of the start brackets
	{({}({})<>)(<>)}{}					#Push the current character + TOS to the other stack

	({}<>)(<>)
	(((((		#Push the differences between end bracket characters
	((([(())()()()]){}){}){}())	#Push -31, 1
	(()))				#Push -30, 1
	(((())()){}()){})		#Push -19, 1
	){})				#Push -40
	({<(({}<>{}[()]))>[()]{()(<{}>)}{}<>}{}<>)	#If the character is any of the end brackets
	{(<({}(<()>)<>({})<{({}<>)<>}>)>)<>{({}<>)<>}}{}	#Push the character + TOS to the output

	({}()<>)	#If the character is not a |
	{{}({}<>)((<>))}{}	#Move current character to the other stack and push a zero
	{}		#Pop the top value of the stack, either the | or a 0
	<>(<({}(<()>)<><{({}<>)<>}>)>)<>{({}<>)<>}{}<>	#And push top of other stack to the output
}{}
{({}{}<>)<>}<>	#Reverse output and append the excess end brackets

Dan tentu saja...

Brain-Flak Terkompresi, 285 byte:

{(((}|||(>|(((((((([()|)))||}|}|})|()||((()|))|)|}}||}[)||({<((}>}[)||||){[)|(<}|||}>|}><}||{(}(}|>|(>||}(}>|(>|(((((((([()|)))||}|}|})|()||((()|)|})|}||}|({<((}>}[)||||[)|{)(<}|||}>|}>|{(<(}(<)||>(}|<{(}>|>|||||>{(}>|>||}(})>|{}(}>|((>|||}}>(<(}(<)||><{(}>|>|||||>{(}>|>|}>|}{(}}>|>|>
Jo King
sumber
1
Golf yang sangat mengesankan! Saya kecewa pada diri sendiri karena tidak menyadari ini lebih cepat, saya harus menyelidiki nanti untuk memahami cara kerjanya.
Kamil Drakari
2

Java 10, 424 byte

s->{int i=0;for(var c:s.toCharArray()){if("(<[{".indexOf(c)>-1)i++;if(c=='|')i--;}for(;i-->0;)s+='|';s=s.replace(")","()").replace(">","<>").replace("]","[]").replace("}","{}");char[]c=s.toCharArray(),r=new char[124];r[40]=41;r[60]=62;r[91]=93;r['{']='}';var o="";for(;++i<c.length ;){if(c[i]=='|'){c[i]=o.charAt(0);o=o.substring(1);}if("(<[{".indexOf(c[i])>-1&")>]}".indexOf(i+1<c.length?c[i+1]:0)<0)o=r[c[i]]+o;}return c;}

Agak panjang, tapi saya tidak tahu bagaimana mempersingkatnya. Ini adalah tantangan yang bagus.

Cobalah online di sini .

Versi tidak disatukan:

s -> { // lambda taking a String argument and returning a char[]
    int i = 0; // used for counting the number of '|'s that have been removed at the end of the input
    for(var c : s.toCharArray()) { // look at every character
        if("(<[{".indexOf(c) > -1) // if it's an open monad character
            i++; // we will need one more '|'
        if(c == '|') // if it's a close monad character
            i--; // we will need one '|' less
    }
    for(; i-- > 0; ) // add as many '|'
        s += '|';    // as necessary
    s = s.replace(")", "()").replace(">", "<>").replace("]", "[]").replace("}", "{}"); // replace compressed nilads with their uncompressed versions
    char[] c = s.toCharArray(), // from now on working on a char[] is more efficient since we will only be comparing and replacing
    r = new char[124]; // map open monad characters to their counterparts:
    r[40] = 41;   // '(' to ')'
    r[60] = 62;   // '<' to '>'
    r[91] = 93;   // '[' to ']'
    r['{'] = '}'; // '{' to '}'
    var o = ""; // we use this String as a kind of stack to keep track of the last open monad character we saw
    for(; ++i < c.length ;) { // iterate over the length of the expanded code
        if(c[i] == '|') { // if the current character is a close monad character
            c[i] = o.charAt(0); // replace it with the top of the stack
            o = o.substring(1); // and pop the stack
        }
        if("(<[{".indexOf(c[i]) > -1 // if the current character is an open monad/nilad character
         & ")>]}".indexOf(i+1 < c.length ? c[i+1] : 0) < 0) // and it's not part of a nilad (we need to test for length here to avoid overshooting)
            o = r[c[i]]+o; // using the mapping we established, push the corresponding character onto the stack
    }
    return c; // return the uncompressed code
}
Ketidakseimbangan
sumber
2

Python 2, 188 184 180 177 174 173 byte

p,q='([{<',')]}>'
d,s,a=dict(zip(p,q)),[],''
for c in input():
 if c in d:a+=c;s+=[c]
 elif'|'==c:a+=d[s.pop()]
 else:a+=dict(zip(q,p))[c]+c
for c in s[::-1]:a+=d[c]
print a

Disimpan 4 byte berkat DJMcMayhem.
Cobalah online!


sumber
180
DJMcMayhem
168 byte dengan mengotak-atik baris 2 hingga terakhir
DJMcMayhem
@DJMcMayhem Itu hanya berfungsi jika sberakhir kosong. Jika tidak, Anda berakhir dengan karakter tambahan di ujung yang salah.
2

Python 3 , 122 byte

D='()<>[]{} '
def f(x):
 a=s=''
 for c in x:i=D.find(c);a+=i<0and s[0]or D[i-(i&1):i+1];s=D[i+1][i&1:]+s[i<0:]
 return a+s

Cobalah online!

RootTwo
sumber
1

Haskell , 152 byte

fst.p
m c="> < ] [)(} {"!!mod(fromEnum c-6)27
p(c:r)|elem c")]}>",(s,t)<-p r=(m c:c:s,t)|c/='|',(s,'|':t)<-p$r++"|",(u,v)<-p t=(c:s++m c:u,v)
p e=("",e)

Cobalah online! atau verifikasi semua kasus uji . pmengimplementasikan pengurai rekursif, yang mungkin lebih dari membunuh untuk tata bahasa sederhana.

Laikoni
sumber
1
Fungsi bagus muntuk menemukan braket yang cocok.
nimi
1

Python 2 , 244 byte

s=input()
B='([{<'
C=')]}>'
Z=zip(B,C)
P=sum(map(s.count,B))-s.count('|')
for i,j in Z:s=s.replace(j,i+j)
s+=P*'|'
b=[0]
for i in s:[b.pop()for j,k in Z if j==b[-1]<k==i];b+=[i][:i in B];s=i=='|'and s.replace(i,C[B.find(b.pop())],1)or s
print s

Cobalah online!

Butuh lebih dari satu atau dua jam untuk menyelesaikannya ...

Erik the Outgolfer
sumber