압축 뇌파 편 확장


26

이 챌린지는 2018 년 4 월 LotM 챌린지 의 일부로 , Brain-flak의 2 번째 생일을 위해 게시되었습니다.


나는 뇌-플래그 프로그램을 인코딩하는 가장 효율적인 방법이 무엇인지 생각하고있었습니다. 유효한 문자는 8 개뿐이므로 각 문자를 3 비트 시퀀스에 매핑해야합니다. 이것은 확실히 효과적이지만 여전히 매우 중복 적입니다. 인코딩 시간을 단축하기 위해 이용할 수있는 뇌 플랙 코드의 일부 기능이 있습니다.

  • 모두 2 개의 일치하는 대괄호로 표시되는 nilads는 실제로 2가 아닌 단일 정보 단위로 작동합니다. 각 대괄호를 단일 바이트 문자로 바꾸면 데이터 손실없이 인코딩이 훨씬 작아집니다.

  • 이것은 명확하지 않지만 모나드 의 닫는 바이트 도 중복됩니다. '?'다음 스 니펫에서 캐릭터가 무엇을 나타내는 지 추측 할 수 있다고 생각 하십니까?

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

    입력이 유효한 뇌-플래 크 코드라고 가정하면, 각 물음표마다 하나의 옵션 만 있습니다. 즉, 닫기 모나드 문자를 모호하게 사용하여 모든 닫는 괄호를 나타낼 수 있습니다 . 이것은 문자 집합을 작게 유지하는 이점이 있으며 허프만 인코딩을 사용하려는 경우 큰 도움이됩니다. 때문에 가까운 모나드의 캐릭터가 가장 가능성이 넓은 여백에 의해 가장 일반적인 문자 될 것입니다, 그것은 상당히 효율적인 단일 비트에 의해 표현 될 수있다.

이 두 가지 트릭을 통해 다음 알고리즘을 통해 뇌-플래 크 코드를 압축 할 수 있습니다.

  1. 모나드의 모든 닫는 브래킷을로 교체하십시오 |. 즉, 앞에 여는 일치 항목 이없는 모든 닫는 괄호를 막대와 바꿉니다. 그래서...

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

    될 것이다

    (({}|<(()()()||{}|
    
  2. 모든 nilad를 닫는 브래킷으로 교체하십시오. 따라서 일치하지 않는 대괄호에는 다음과 같은 매핑이 사용됩니다.

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

    이제 우리의 마지막 예는 다음과 같습니다.

    ((}|<()))||}|
    
  3. 후행 |문자를 제거하십시오 . 우리는 총 막대 수가 총 ({[<문자 수와 같아야한다는 것을 알고 있으므로 누락 된 막대가 있으면이를 유추 할 수 있습니다. 따라서 예를 들면 다음과 같습니다.

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

    될 것이다

    ({(}|(}[)
    

오늘 당신의 도전은이 과정을 뒤집는 것입니다.

문자 만 포함 된 압축 된 뇌-플래 크 문자열이 주어지면 (){}[]<>|, 그것을 원래의 뇌-플래 크 코드로 확장하십시오. 입력이 항상 유효한 뇌-플랙으로 확장 될 것이라고 가정 할 수 있습니다. 이는 입력의 접두어에 문자 |이상을 포함하지 않음을 의미합니다 ({[<.

입력에는 후행 |문자가 포함되지 않습니다 . 이들은 맥락에서 유추되어야합니다.

평소와 같이 전체 프로그램 또는 기능을 제출할 수 있으며 입력 / 출력 형식이 허용됩니다. 그리고 이것은 이므로 소스 코드의 길이에 따라 코드의 점수가 매겨지며 점수가 작을수록 좋습니다.

테스트 사례

다음은 몇 가지 테스트 사례입니다. 더 많은 것을 원한다면 이 파이썬 스크립트Brain-Flak Wiki를 사용하여 자체 테스트 사례를 생성 할 수 있습니다 .이 테스트 사례는 대부분 테스트 사례에서 비롯됩니다.

#Compressed code
#Original code

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


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

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


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

4
천재. 절대적으로 천재. 파생 언어를 만들어야합니다.
NH.

8
@NH. 개인적으로 인코딩이 다른 언어는 정말 지루하다고 생각합니다.
DJMcMayhem

1
@dj 그러나 이것은 적은 바이트를 차지하므로 골프에 더 좋습니다.
NH.

5
Brain-Flak은 골프를 잘하도록 설계되지 않았습니다.
DJMcMayhem

답변:


32

Brain-Flak , 952 916818 바이트

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

처음부터 상대적으로 반대쪽 대괄호를 계산하여 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 때문에 실행되지 않습니다. 당신은 두뇌 플랙에 transpiler을 찾을 수 있습니다 여기에 )

도구를 사용하여 Brain-Flak으로 변환하여 유효하다는 것을 확인했습니다 . 이제 시간 초과가 거의 없을 정도로 효율적입니다.


4
Brain-Flak에서 처음으로 골프를 쳤는데 그 결과는 무엇입니까? 와우.
Outgolfer Erik

당신은 항상 대체 할 수 있습니다 <>(<()>)(<>). 또한, 당신은 변경할 수 있습니다 (<>{}<>)(<()>)(<(<>{}<>)>)
DJMcMayhem

1
@JoKing 어떻게 알지 모르겠지만, 모든 If 블록에 여분의 롤을 추가하는 대신 루프 끝에서 롤을 추출하지 못했습니다.
Kamil Drakari

1
이것은 골프를 넘어선 것입니다. 이것은 순수한 광기입니다. 축하합니다!
Arthur Attout

1
@JoKing 변경이 예상보다 쉽고 효과적이었으며 이제 답변에 포함되었습니다
Kamil Drakari

7

레티 나 0.8.2 , 103 98 바이트

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

온라인으로 사용해보십시오! 링크에는 테스트 사례가 포함됩니다. 편집 : @MartinEnder에서 영감을 얻어 5 바이트를 저장했습니다. 설명:

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

을 넣어 ;모든 대괄호 후 오픈 브라켓에 그들 모두를 변경하고 변경 |에의 ;너무들.

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

일치하지 않는 열린 괄호 수를 세고 그 수를 더하십시오 ;.

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

각 여는 브래킷을 해당하는 위치로 복사하십시오 ;.

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

복사 된 대괄호를 뒤집고 ;s를 삭제합니다 .


1
|와 같은 것으로 번역하면 모든 탈출 막대를 피할 수 있습니다 !. 당신이 번역 경우에도 바이트를 요하지 않을 것이다 >-}<-{(I주는 생각하는 z대한 |).
Martin Ender

@MartinEnder 나는 당신의 요점을 이해하지 못하지만 z어쨌든 몇 바이트 더 면도하는 방법을 생각해 냈습니다.
Neil

5

TIS , 670 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는 타이밍에 필요한 것처럼 보이며 in @14의 읽기로 인해 현재 위치에 스택을 넣을 수 없습니다 .ANY@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

자바 스크립트 (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

@Shaggy 감사합니다! 그러나 실제로 1 문자와 2 문자 문자열을 혼합하여 반환 할 수 있습니까?
Arnauld

흠 ... 그래, 아마도 "허용되는"출력으로 밀고있을 것이다.
얽히고 설킨

@DJMcMayhem 새로운 출력 형식을 보고 허용 가능한지 알려주시겠습니까?
Arnauld

1
@arnauld Huh, 어떤 이유로 나를 핑하지 않았습니다. 내가 아니라고 생각합니다. 문자 배열 또는 하나의 문자열은 모두 표준 형식이지만 문자열 배열은 나에게 유효하지 않습니다.
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

뇌 플랙 , 606 548 496 418 394 390 바이트

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

온라인으로 사용해보십시오!

나는 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
매우 인상적인 골프! 나는 이것을 더 빨리 알지 못해서 실망했다. 나는 그것이 어떻게 작동하는지 이해하기 위해 나중에 그것을 조사해야 할 것이다.
Kamil Drakari

2

자바 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 번째 줄까지
DJMcMayhem

@DJMcMayhem s빈 상태 일 때만 작동합니다 . 그렇지 않으면 잘못된 문자가 추가 문자로 끝납니다.



1

파이썬 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

온라인으로 사용해보십시오!

이 작업을 수행하는 데 1 ~ 2 시간 이상이 걸렸습니다 ...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.