Mở rộng flak não nén


26

Thử thách này đã được đăng trong khuôn khổ thử thách LotM tháng 4 năm 2018 , cũng như cho sinh nhật lần thứ 2 của Brain-flak


Tôi đã suy nghĩ về cách hiệu quả nhất để mã hóa các chương trình não bộ sẽ là gì. Điều rõ ràng phải làm, vì chỉ có 8 ký tự hợp lệ, là ánh xạ mỗi ký tự thành một chuỗi 3 bit. Điều này chắc chắn rất hiệu quả, nhưng nó vẫn rất dư thừa. Có một số tính năng của mã não bộ mà chúng ta có thể tận dụng để rút ngắn mã hóa.

  • Các nilad, tất cả được biểu thị bằng 2 dấu ngoặc khớp, thực sự hoạt động như một đơn vị thông tin chứ không phải 2. Nếu chúng ta thay thế mỗi dấu ngoặc đơn bằng một ký tự byte, điều này sẽ làm cho mã hóa nhỏ hơn nhiều mà không mất dữ liệu.

  • Điều này là ít rõ ràng, nhưng các byte đóng của các đơn vị cũng là dư thừa. Hãy nghĩ rằng bạn có thể đoán những gì các '?'nhân vật đại diện trong đoạn trích sau đây?

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

    Nếu chúng ta giả sử đầu vào là mã flak não hợp lệ, thì chỉ có một tùy chọn cho mỗi dấu hỏi đó. Điều này có nghĩa là chúng ta có thể sử dụng rõ ràng một ký tự đơn nguyên gần gũi để thể hiện mọi dấu ngoặc đóng. Điều này có thêm lợi ích của việc giữ cho bộ ký tự nhỏ, sẽ giúp ích rất nhiều nếu chúng ta muốn sử dụng mã hóa huffman. Vì nhân vật đơn nguyên gần như rất có thể là nhân vật phổ biến nhất bởi lề rộng, nên nó có thể được biểu thị bằng một bit duy nhất, rất hiệu quả.

Hai thủ thuật này sẽ cho phép chúng tôi nén mã não thông qua thuật toán sau:

  1. Thay thế mọi khung đóng của một đơn nguyên bằng |. Hay nói cách khác, thay thế mọi khung đóng không có trước trận đấu mở của nó bằng một thanh. Vì thế...

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

    sẽ trở thành

    (({}|<(()()()||{}|
    
  2. Thay thế mọi nilad bằng khung đóng của nó. Do đó, dấu ngoặc phù hợp không có gì trong đó sử dụng ánh xạ sau:

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

    Bây giờ ví dụ cuối cùng của chúng tôi trở thành:

    ((}|<()))||}|
    
  3. Xóa các |ký tự dấu . Bởi vì chúng ta biết rằng tổng số thanh phải bằng tổng số ({[<ký tự, nếu thiếu thanh ở cuối, chúng ta có thể suy ra chúng. Vì vậy, một ví dụ như:

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

    sẽ trở thành

    ({(}|(}[)
    

Thách thức của bạn cho ngày hôm nay là đảo ngược quá trình này.

Đưa ra một chuỗi flak não nén chỉ chứa các ký tự (){}[]<>|, mở rộng nó thành mã flak não ban đầu. Bạn có thể giả định rằng đầu vào sẽ luôn mở rộng thành flak não hợp lệ. Điều này có nghĩa là không có tiền tố của đầu vào sẽ chứa nhiều |hơn các ({[<ký tự.

Đầu vào sẽ không chứa các |ký tự dấu . Chúng phải được suy ra từ bối cảnh.

Như thường lệ, bạn có thể gửi một chương trình đầy đủ hoặc một chức năng và các định dạng đầu vào / đầu ra được cho phép. Và vì đây là , mã của bạn sẽ được tính theo độ dài của mã nguồn tính bằng byte, điểm càng nhỏ thì càng tốt.

Các trường hợp thử nghiệm

Dưới đây là một số trường hợp thử nghiệm. Nếu bạn muốn nhiều hơn nữa, bạn có thể tạo các trường hợp thử nghiệm của riêng mình với tập lệnh python nàyBrain-Flak Wiki , nơi mà phần lớn các trường hợp thử nghiệm này đến từ.

#Compressed code
#Original code

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


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

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


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

4
Thiên tài. hoàn toàn thiên tài. Bạn nên làm một ngôn ngữ phái sinh.
NH.

8
@NH. Cá nhân, tôi cảm thấy như các ngôn ngữ chỉ khác nhau về mã hóa thực sự nhàm chán.
DJMcMayhem

1
@dj nhưng cái này sẽ chiếm ít byte hơn và do đó sẽ tốt hơn cho việc chơi golf.
NH.

5
Brain-Flak không được thiết kế để chơi golf.
DJMcMayhem

Câu trả lời:


32

Brain-Flak , 952 916 818 byte

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

Đã lưu 360 byte bằng cách tính toán các dấu ngoặc đối lập tương đối thay vì từ đầu (ví dụ ')'= '(' + 1thay vì (((5 * 2) * 2) * 2) + 1)

Đã lưu 34 byte với một số thay thế trực tiếp từ DJMcMayhem

Đã lưu 10 byte bằng cách chồng >]}mã xử lý

Đã lưu 118 byte bằng cách lặp lại cuộn

Đã lưu 40 byte bằng cách tận dụng ngăn xếp trống để đơn giản hóa cuộn đầu tiên

Đã lưu 48 byte bằng cách đánh dấu EOF bằng -1, cho phép mã cuộn ngắn gọn hơn

Đã lưu 36 byte bằng cách sử dụng stock bằng logic thay vì của riêng tôi

Đã lưu 98 byte nhờ Jo King tìm ra cách hiệu quả hơn để xây dựng đầu ra

Hãy thử trực tuyến!

Lần đầu tiên chơi golf trong Brain-Flak, vì vậy có lẽ có một số cải tiến thực sự lớn, nhưng nó hoạt động. Rất nhiều bản sao / dán để xử lý từng loại khung và lớn nhờ vào trình tạo số nguyên tự động và đoạn trích cuộn từ đây .

Giải thích ở đây , định dạng TIO dễ dàng hơn

Phần thưởng trả lời:

Brain-Flak 583 byte được nén

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

Hãy thử trực tuyến!

(Lưu ý rằng liên kết ở trên không chạy vì TIO không có trình thông dịch Brain-Flak được nén. Bạn có thể tìm thấy bộ chuyển đổi sang Brain-Flak tại đây )

Tôi đã kiểm tra xem điều này có hợp lệ hay không bằng cách dịch mã sang Brain-Flak bằng công cụ này , bây giờ đủ hiệu quả để việc hết thời gian là không thể.


4
Lần đầu tiên chơi golf trong Brain-Flak, và kết quả là đây? Ồ
Erik the Outgolfer

Bạn luôn có thể thay thế <>(<()>)bằng (<>). Ngoài ra, bạn có thể đổi (<>{}<>)(<()>)thành(<(<>{}<>)>)
DJMcMayhem

1
@JoKing Tôi không biết làm thế nào, tôi hầu như không thể giải nén Roll ở cuối vòng thay vì có thêm một trong mỗi khối If
Kamil Drakari

1
Điều này vượt ra ngoài việc chơi golf .. Đây là sự điên rồ thuần túy. Xin chúc mừng !
Arthur Attout

1
@JoKing Sự thay đổi vừa dễ dàng vừa hiệu quả hơn tôi mong đợi, và giờ đã có trong câu trả lời
Kamil Drakari

7

Võng mạc 0.8.2 , 103 98 byte

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

Hãy thử trực tuyến! Liên kết bao gồm các trường hợp thử nghiệm. Chỉnh sửa: Đã lưu 5 byte với cảm hứng từ @MartinEnder. Giải trình:

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

Đặt ;sau mỗi khung đóng và thay đổi tất cả thành dấu ngoặc mở và cũng thay đổi |s thành ;s.

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

Đếm số lượng dấu ngoặc mở chưa từng có và thêm nhiều ;s.

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

Sao chép từng khung mở để khớp với nó ;.

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

Lật các dấu ngoặc đã sao chép và xóa ;s.


1
Bạn có thể tránh tất cả các thanh thoát nếu bạn dịch |sang một cái gì đó như !. Nó thậm chí sẽ không tốn byte nếu bạn dịch >-}sang <-{(mà tôi nghĩ là zcho |).
Martin Ender

@MartinEnder Không chắc tôi hiểu quan điểm của bạn về vấn đề này znhưng tôi đã nghĩ ra cách cạo thêm vài byte nữa.
Neil

5

TIS , 670 666 byte

-4 byte để nhảy về phía trước để nhảy trở lại

Mã số:

@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

Bố trí:

6 3
CCCCCCCCCCCCCCCCSC
I0 ASCII -
O0 ASCII -

Hãy thử trực tuyến!

Tôi nghi ngờ đây là nhỏ nhất, nhưng tôi không thấy cách nào làm cho nó nhỏ hơn. Thật không may, tất cả các NOPs dường như cần thiết cho thời gian và tôi không thể đặt ngăn xếp @14hiện tại là do đọc từ ANYtrong @11.

Cấu trúc của giải pháp này như sau:

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

Khi nhìn thấy một dấu ngoặc mở, mở được gửi dọc theo cột bên trái để xuất ra và đóng được gửi dọc theo cột bên phải vào ngăn xếp.

Khi nhìn thấy một dấu ngoặc nhọn, cả mở và đóng đều được gửi dọc theo cột bên trái để xuất ra.

Khi nhìn thấy một đường ống, ngăn xếp được bật lên và gửi đến đầu ra.

Khi EOF, @1sẽ bắt đầu đọc từ @2, thay vì luồng đầu vào từ @0. @2tạo ra một dòng ống vô tận, vì vậy ngăn xếp sẽ bị rút cạn.

Khi cả đầu vào và ngăn xếp đã hết, chương trình sẽ dừng lại.

Cảnh báo: do các giới hạn của TIS, kích thước ngăn xếp bị giới hạn ở mức 15. Nếu bất cứ điều gì được lồng sâu hơn thế, việc triển khai này sẽ tạo ra kết quả không chính xác.


4

JavaScript (ES6), 107 byte

Đưa đầu vào như một mảng các ký tự. Trả về một chuỗi.

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``

Hãy thử trực tuyến!


102 byte bằng cách trả về một mảng ký tự, quá.
Shaggy

@Shaggy Cảm ơn! Nhưng nó có thực sự được phép trả lại các chuỗi 1 ký tự và 2 ký tự được trộn với nhau không?
Arnauld

Hmm ... vâng, có lẽ điều đó đang đẩy nó lên đầu ra "cho phép".
Shaggy

@DJMcMayhem Bạn vui lòng xem định dạng đầu ra mới và cho chúng tôi biết nếu điều đó được chấp nhận?
Arnauld

1
@arnauld Huh, vì một số lý do không ping tôi. Tôi nghĩ tôi sẽ nói không. Một mảng các ký tự hoặc một chuỗi đều là các định dạng tiêu chuẩn, nhưng một mảng các chuỗi dường như không hợp lệ đối với tôi
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

Đây là một chương trình đầy đủ xuất ra giao diện điều khiển. (i<5?a:$>)<<r[-i]đã trở thành một trong những sân golf tuyệt vời nhất tôi từng làm.

Hãy thử trực tuyến!

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}

Đây là giải pháp đầu tiên của tôi. Một hàm lambda ẩn danh nhận và trả về chuỗi.

Hãy thử trực tuyến!


3

Brain-Flak , 606 548 496 418 394 390 byte

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

Hãy thử trực tuyến!

Tôi đã bắt đầu điều này bằng cách đánh golf câu trả lời của Kamil Drakari , nhưng nó đã đi xa đến mức tôi quyết định đăng nó như một câu trả lời riêng biệt.

Giải trình:

{ #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

Và tất nhiên...

Brain-Flak được nén, 285 byte:

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

1
Chơi golf rất ấn tượng! Tôi thất vọng về bản thân mình vì đã không nhận ra điều này sớm hơn, tôi sẽ phải nghiên cứu kỹ về nó sau để hiểu cách thức hoạt động của nó.
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;}

Nó khá dài, nhưng tôi không thể tìm ra cách rút ngắn hơn nữa. Đây là một thử thách tốt.

Hãy thử trực tuyến tại đây .

Phiên bản bị đánh cắp:

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
}

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

Đã lưu 4 byte nhờ DJMcMayhem.
Hãy thử trực tuyến!



168 byte bằng cách làm rối với dòng thứ 2 đến dòng cuối cùng
DJMcMayhem

@DJMcMayhem Điều đó chỉ hoạt động nếu skết thúc trống. Nếu không, bạn kết thúc với các ký tự phụ ở cuối sai.



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

Hãy thử trực tuyến!

Phải mất hơn một hoặc hai giờ để hoạt động này ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.