扩大压缩的脑裂


26

此挑战是2018年4月LotM挑战以及Brain-flak 2岁生日的一部分


我在考虑编码Flask程序的最有效方法是什么。由于只有8个有效字符,因此显而易见的事情是将每个字符映射到3位序列。这肯定是非常有效的,但是仍然很多余。我们可以利用脑剥落代码的某些功能来缩短编码。

  • 全部由2个匹配的方括号表示的nilads实际上充当单个信息单元,而不是2。如果我们用单个字节字符替换每个方括号,这将使编码小得多而不会丢失任何数据。

  • 这个不太明显,但是monad 的结束字节也是多余的。您认为您可以猜出'?'以下代码段中的字符代表什么吗?

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

    如果我们假设输入的内容是有效的大脑标志,那么每个问号只有一个选项。这意味着我们可以明确地使用close monad字符来表示每个结束括号。这具有使字符集保持较小的附加好处,如果我们想使用霍夫曼编码,这将大有帮助。由于接近的monad字符很可能会成为最常见的字符,因此可以用一点来表示,这非常有效。

这两个技巧将使我们通过以下算法来压缩脑筋代码:

  1. 用替换monad的每个右括号|。换句话讲,将每个在开头匹配之前的右方括号替换为小节。所以...

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

    会成为

    (({}|<(()()()||{}|
    
  2. 用它的封闭支架替换所有的尼拉丁。因此,其中没有任何内容的匹配方括号将使用以下映射:

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

    现在我们的最后一个示例变为:

    ((}|<()))||}|
    
  3. 删除尾随|字符。因为我们知道小节的总数应等于({[<字符总数,所以如果末尾缺少小节,我们可以推断出它们。因此,例如:

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

    会成为

    ({(}|(}[)
    

今天的挑战是逆转这一过程。

给定一串只包含字符的压缩后的Flask,将其(){}[]<>|扩展为原始的Flak代码。您可以假设输入将始终扩展为有效的大脑标志。这意味着输入的前缀中|最多不会包含({[<字符。

输入将不包含结尾|字符。这些必须从上下文中推断出来。

与往常一样,您可以提交完整的程序或函数,并且输入/输出格式是允许的。并且由于这是一个,因此您的代码将按源代码的长度(以字节为单位)进行评分,分数越小越好。

测试用例

这是一些测试用例。如果您想要更多,可以使用此python脚本Brain-Flak Wiki生成自己的测试用例,这是大多数测试用例的来源。

#Compressed code
#Original code

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


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

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


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

4
天才。绝对是天才。您应该使用派生语言。
NH。

8
@NH。就个人而言,我觉得仅在编码方面有所不同的语言真的很无聊。
DJMcMayhem

1
@dj,但是这个会占用较少的字节,因此更适合打高尔夫球。
NH。

5
Brain-Flak并非旨在打高尔夫球。
DJMcMayhem

Answers:


32

Brain-Flak952916818字节

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

通过相对地而不是从头算起相对的方括号来节省360字节(例如')'= '(' + 1代替(((5 * 2) * 2) * 2) + 1

通过直接替换DJMcMayhem保存了34个字节

通过重叠>]}处理代码节省了10个字节

通过对卷进行重复数据删除节省了118个字节

利用空堆栈节省了40个字节,以简化第一卷

通过将EOF标记为-1,节省了48个字节,从而实现了更简洁的滚动代码

使用股票等于逻辑而不是我自己的逻辑节省了36个字节

由于Jo King找到了一种更有效的方式来构建输出,因此节省了98个字节

在线尝试!

第一次在Brain-Flak打高尔夫球,因此可能会有一些真正的大改进,但确实有效。大量的复制/粘贴处理每种括号类型,这要归功于自动整数生成器此处的Roll片段。

在这里解释,TIO格式化起来更容易

奖励答案:

压缩的Brain-Flak 583字节

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

在线尝试!

(请注意,由于TIO没有压缩的Brain-Flak解释器,因此上述链接无法运行。您可以在此处找到Brain-Flak的转译器)

我已经通过使用工具转换到Brain-Flak来检查这是否合法,它现在已经足够有效,以至于不太可能超时。


4
第一次在Brain-Flak打高尔夫球,结果是这样吗?哇。
暴民埃里克(Erik the Outgolfer)'18年

您可以随时替换<>(<()>)(<>)。此外,您可以更改(<>{}<>)(<()>)(<(<>{}<>)>)
DJMcMayhem

1
@JoKing我不知道怎么做,我几乎没有设法在循环结束时提取掷骰,而不是在每个If区块中都有一个额外的
掷骰

1
这超出了打高尔夫球的范围。恭喜你!
亚瑟·阿特

1
@JoKing更改比我预期的更轻松,更有效,现在已包含在答案中
Kamil Drakari

7

视网膜0.8.2103个 98字节

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

在线尝试!链接包括测试用例。编辑:从@MartinEnder获得灵感,保存了5个字节。说明:

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

;在每个右方括号之后放置一个,并将它们全部更改为大括号,并将s也更改|;s。

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

计算不匹配的方括号个数,然后加上多个;

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

将每个左括号复制到其匹配的位置;

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

翻转复制的括号并删除;


1
如果翻译|成,您可以避免所有转义的小节!。如果你翻译它甚至不会花费字节>-}<-{(我认为给z|)。
Martin Ender '18

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

在线尝试!

我怀疑这是最小的,但我看不出缩小它的方法。不幸的是,所有的NOPs似乎都是定时的必要条件,由于无法@14读取ANYin ,所以我无法将堆栈放在当前位置@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个字节
毛茸茸的

@粗野的谢谢!但是,是否真的允许返回混合在一起的1个字符和2个字符的字符串?
Arnauld

嗯...是的,也许是把它推到“允许的”输出上。
毛茸茸的

@DJMcMayhem您能否看一下新的输出格式,并让我们知道是否可以接受?
Arnauld

1
@arnauld Huh,由于某种原因无法对我执行ping操作。我想我不会。字符数组或一个字符串都是标准格式,但是字符串数组对我而言似乎无效
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}

这是我的第一个解决方案。一个匿名lambda函数,它接收并返回字符串。

在线尝试!


3

Brain-Flak606548496496418394390字节

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

在线尝试!

我从打高尔夫球Kamil Drakari的答案开始,但是直到我决定将其发布为单独的答案为止。

说明:

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

Python 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个字节。
在线尝试!



通过弄乱第二到最后一行来
读取

@DJMcMayhem仅在s结尾为空时才有效。否则,您将在错误的结尾处得到多余的字符。

2

Python 3,122字节

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

在线尝试!


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

1

Python 2,244字节

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

在线尝试!

花了一个多小时或两个小时才能使它工作...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.