圧縮されたBrain-Flakを展開する


26

このチャレンジは、2018年4月のLotMチャレンジの一部として、およびBrain-flakの2回目の誕生日に投稿されました


Brain-Flakプログラムをエンコードする最も効率的な方法は何かを考えていました。有効な文字は8つしかないため、行うべき明らかなことは、各文字を3ビットシーケンスにマップすることです。これは確かに非常に効果的ですが、それでも非常に冗長です。Brain-flakコードには、エンコードを短縮するために利用できる機能がいくつかあります。

  • ニラッドはすべて2つの一致するブラケットで表され、実際には2ではなく単一の情報単位として機能します。各ブラケットを1バイト文字に置き換えると、データを失うことなくエンコードがはるかに小さくなります。

  • これはそれほど明白ではありませんが、モナドの終了バイトも冗長です。'?'次のスニペットで文字が何を表すか推測できると思いますか?

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

    入力が有効なbrain-flakコードであると仮定した場合、それらの疑問符ごとに1つのオプションしかありません。これは、閉じるモナド文字を明確に使用して、すべての閉じ括弧を表すことができることを意味します。これには、文字セットを小さく保つという追加の利点があります。これは、ハフマンエンコーディングを使用する場合に非常に役立ちます。以来近いモナドの文字が最も可能性の高いワイドマージンによって最も一般的な文字になります、非常効率的である、単一ビットで表現することができます。

これらの2つのトリックにより、次のアルゴリズムを介してbrain-flakコードを圧縮できます。

  1. モナドのすべての閉じ括弧をに置き換え|ます。または、言い換えると、開始一致の前にないすべての閉じ括弧をバーに置き換えます。そう...

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

    になるだろう

    (({}|<(()()()||{}|
    
  2. すべてのニラッドを閉じブラケットで置き換えます。したがって、何も含まれていない一致した括弧は、次のマッピングを使用します。

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

    これで最後の例は次のようになります。

    ((}|<()))||}|
    
  3. 末尾の|文字を削除します。バーの総数は({[<文字の総数と等しくなければならないことがわかっているため、最後にバーがない場合は推測できます。次のような例:

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

    になるだろう

    ({(}|(}[)
    

今日の課題は、このプロセスを逆にすることです。

文字のみを含む圧縮されたbrain-flakの文字列が与えられた(){}[]<>|場合、元のbrain-flakコードに展開します。入力は常に有効なブレインフラックに拡張されると想定できます。これは、入力のプレフィックスに文字を|超える({[<文字が含まれないことを意味します。

入力には末尾の|文字は含まれません。これらはコンテキストから推測する必要があります。

通常どおり、完全なプログラムまたは関数のいずれかを送信でき、入出力形式は許容されます。また、これはであるため、ソースコードの長さ(バイト単位)によってコードがスコアリングされます。スコアが小さいほど優れています。

テストケース

ここにいくつかのテストケースがあります。さらに必要な場合は、このpythonスクリプトBrain-Flak Wikiを使用して独自のテストケースを生成できます。これは、これらのテストケースの大部分が由来する場所です。

#Compressed code
#Original code

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


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

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


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

4
天才。絶対天才。派生言語を作成する必要があります。
NH。

8
@NH。個人的には、エンコーディングのみが異なる言語は本当に退屈だと感じています。
DJMcMayhem

1
@djですが、これはバイト数が少ないため、ゴルフに向いています。
NH。

5
Brain-Flakはゴルフが得意なようには設計されていません。
DJMcMayhem

回答:


32

Brain-Flak952 916 818バイト

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

ゼロからではなく相対ブラケットを計算することで360バイトを節約しました(例')'=の'(' + 1代わりに(((5 * 2) * 2) * 2) + 1

DJMcMayhemからのいくつかの直接置換で34バイトを保存

>]}処理コードをオーバーラップして10バイトを節約しました

ロールの重複排除により118バイトを節約

空のスタックを利用して最初のロールを簡素化することにより、40バイトを節約しました

EOFに-1をマークして48バイトを節約し、より簡潔なロールコードを有効にしました

私自身の代わりにストックイコールロジックを使用して36バイトを節約しました

Jo Kingが出力を構築するより効率的な方法を見つけたおかげで98バイトを節約

オンラインでお試しください!

Brain-Flakで初めてゴルフをするので、おそらくいくつかの本当に大きな改善がありますが、うまくいきます。各ブラケットタイプを処理するためのコピー/貼り付けがたくさんあります。自動整数ジェネレーターここからのロールスニペットに感謝します

ここでの説明、TIOはより簡単にフォーマットします

ボーナス回答:

Brain-Flak 583バイトの圧縮

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

オンラインでお試しください!

(TIOには圧縮されたBrain-Flakインタープリターがないため、上記のリンクは実行されないことに注意してください。Brain-Flakへのトランスパイラーはここで見つけることができます)

このツールを使用してBrain-Flakにトランスパイリングすることで、これが有効であることを確認しました。現在は十分に効率的で、タイムアウトは発生しません。


4
Brain-Flakでの初めてのゴルフ、そして結果はこれですか?ワオ。
エリックアウトゴルファー

あなたはいつも置き換えることができ<>(<()>)(<>)。また、あなたは変更することができます(<>{}<>)(<()>)(<(<>{}<>)>)
DJMcMayhem

1
@JoKing方法はわかりませんが、Ifブロックごとに余分なロールを作成するのではなく、ループの最後でロールを抽出することができませんでした
Kamil Drakari

1
これはゴルフを超えています..これは純粋な狂気です。おめでとうございます!
アーサーAttout

1
@JoKingこの変更は、予想よりも簡単で効果的でしたが、今では答えに含まれています
カミルドラカリ

7

網膜0.8.2103の 98バイト

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

オンラインでお試しください!リンクにはテストケースが含まれます。編集:@MartinEnderからインスピレーションを得て5バイトを保存しました。説明:

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

;すべての閉じ括弧の後にa を置き、それらをすべて開き括弧に変更し、sも|sに変更し;ます。

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

一致しない開き括弧の数をカウントし、その数を追加し;ます。

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

各開き括弧を対応するにコピーします;

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

コピーした角かっこを反転し、;s を削除します。


1
|ようなものに翻訳する場合、すべてのエスケープされたバーを避けることができます!。あなたが翻訳した場合にそれもバイトを要しないだろう>-}<-{(私が与えると考えているzため|)。
マーティンエンダー

@MartinEnderについてあなたのポイントを理解しているのは確かではありませんzが、とにかくさらに数バイトを削る方法を思いつきました。
ニール

5

TIS670 666バイト

前方にジャンプして後方にジャンプするには-4バイト

コード:

@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

レイアウト:

6 3
CCCCCCCCCCCCCCCCSC
I0 ASCII -
O0 ASCII -

オンラインでお試しください!

これは最小だとは思わないが、小さくする方法は見当たらない。残念ながら、NOPタイミングにはすべてのが必要と思わ@14ANY、in からの読み取りのために現在の場所にスタックを配置することはできません@11

このソリューションの構造は次のとおりです。

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

左中かっこが表示されると、左の列に沿って開きが送信されて出力され、右の列に沿って閉じがスタックに送信されます。

中かっこが表示されると、左の列に沿って開きと閉じの両方が送信され、出力されます。

パイプが表示されると、スタックがポップされ、出力に送信されます。

EOF @1が発生する@2と、からの入力ストリームではなくからの読み取りを開始し@0ます。@2パイプの無限ストリームを生成するため、スタックは排出されます。

入力とスタックの両方が使い果たされると、プログラムは停止します。

警告:TISの制限により、スタックサイズは15に制限されます。それよりも深くネストされている場合、この実装は誤った結果を生成します。


4

JavaScript(ES6)、107バイト

入力を文字の配列として受け取ります。文字列を返します。

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

オンラインでお試しください!


文字配列を返すことにより102バイト
シャギー

@Shaggyありがとう!しかし、1文字と2文字の文字列を混ぜて返すことは本当に許可されていますか?
アーナウルド

うーん...ええ、多分それは「許容」出力にそれをプッシュしています。
シャギー

@DJMcMayhem 新しい出力フォーマットを見て、それが受け入れられるかどうか教えてください。
アーナウルド

1
@arnauld Huh、何らかの理由で私にpingしませんでした。私はノーと言うと思います。文字の配列または1つの文字列はどちらも標準形式ですが、文字列の配列は有効ではないようです
DJMcMayhem


3

ルビー、104バイト

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

これは、コンソールに出力する完全なプログラムです。(i<5?a:$>)<<r[-i]今までで一番クールなゴルフの一つにならなければなりません。

オンラインでお試しください!

ルビー、106バイト

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

これが私の最初の解決策です。文字列を受け取って返す匿名のラムダ関数。

オンラインでお試しください!


3

Brain-Flak606 548 496 418 394 390バイト

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

オンラインでお試しください!

カミル・ドラカリの答えをゴルフで始めたのですが、別の答えとして投稿することになりました。

説明:

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

そしてもちろん...

圧縮されたBrain-Flak、285バイト:

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

1
非常に印象的なゴルフ!これに早く気づかないことに失望しました。それがどのように機能するかを理解するために、後で掘り下げなければなりません。
カミルドラカリ

2

Java 10、424バイト

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

ちょっと長いですが、さらに短くする方法がわかりませんでした。しかし、これは素晴らしい挑戦です。

こちらからオンラインでお試しください。

ゴルフされていないバージョン:

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

パイソン2、188の 184 180 177 174 173バイト

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

DJMcMayhemのおかげで4バイト節約されました。
オンラインでお試しください!



2行目から最終行をいじって168バイト
DJMcMayhem

@DJMcMayhemこれsは、空になった場合にのみ機能します。そうしないと、余分な文字が間違った端になってしまいます。


1

Haskell、152バイト

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)

オンラインでお試しください!または、すべてのテストケースを確認しますp再帰的なパーサーを実装します。これは、単純な文法では過剰に削除される可能性があります。


1
m一致するブラケットを見つけるための素敵な関数。
-nimi

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.