Розгорніть стислий мозок-колбу


26

Цей виклик було розміщено як частина виклику LotM у квітні 2018 року , а також 2-го дня народження Brain-Flak


Я замислювався над тим, який би найефективніший спосіб кодування програм із заповненням мозку. Очевидно, що потрібно зробити, оскільки існує лише 8 дійсних символів, - це зіставлення кожного символу в 3-бітній послідовності. Це, звичайно, дуже ефективно, але все-таки дуже зайве. Існують деякі особливості кодового мозку, яким ми могли б скористатися, щоб скоротити кодування.

  • Нілади, які представлені двома відповідніми дужками, дійсно виступають як одна одиниця інформації, а не 2. Якби ми замінили кожну дужку одним байтовим символом, це зробить кодування значно меншими, не втрачаючи жодних даних.

  • Цей спосіб менш очевидний, але байти монад , що закриваються, також зайві. Думаєте, ви могли здогадатися, що '?'символи представляють у наступному фрагменті?

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

    Якщо ми вважаємо, що вхідний код є дійсним кодовим моментом, то для кожного з цих знаків питання існує лише один варіант. Це означає, що ми можемо однозначно використовувати близький символ монади для представлення кожної закриваючої дужки. Це має додаткову перевагу у збереженні набору символів невеликим, що дуже допоможе, якби ми хотіли використовувати кодування Хаффмана. Оскільки близький характер монади , швидше за все, буде найпоширенішим персонажем з широким відривом, він може бути представлений одним бітом, який є надзвичайно ефективним.

Ці два хитрощі дозволять нам стиснути код, що не відповідає мозку, за допомогою наступного алгоритму:

  1. Замініть кожен закриваючий кронштейн монади на |. Або іншими словами, замінюйте кожну закриваючу кронштейн, якому не передує її відкриття, на брусок. Так...

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

    став би

    (({}|<(()()()||{}|
    
  2. Замініть кожну нижню частину її закриваючої дужки. Тому збірні дужки, в яких немає нічого, використовують наступне відображення:

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

    Тепер наш останній приклад стає:

    ((}|<()))||}|
    
  3. Видаліть |символи, що знаходяться в кінці . Оскільки ми знаємо, що загальна кількість барів повинна дорівнювати загальній кількості ({[<символів, якщо рядки в кінці відсутні, ми можемо їх зробити висновок. Отже, наприклад:

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

    став би

    ({(}|(}[)
    

Ваше сьогоднішнє завдання - це повернути цей процес.

Враховуючи рядок стисненого мозку, що містить лише символи (){}[]<>|, розгорніть його у вихідний код головного мозку. Ви можете припустити, що вхід завжди буде розширюватися до дійсного мозку. Це означає , що ні один префікс введення ніколи не буде містити більш |ніж ({[<символи.

Вхід не буде містити |символи, що тривають . Вони повинні бути виведені з контексту.

Як завжди, ви можете подати або повну програму, або функцію, а формати введення / виводу є дозволеними. А оскільки це , ваш код буде набраний по довжині вихідного коду в байтах, чим менша оцінка, тим краще.

Тестові справи

Ось кілька тестових випадків. Якщо ви хочете більше, ви можете генерувати власні тестові випадки за допомогою цього сценарію python та Brain-Flak Wiki , звідки походить більшість цих тестових випадків.

#Compressed code
#Original code

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


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

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


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

4
геній. абсолютно геніальний. Вам слід скласти похідну мову.
NH.

8
@NH. Особисто я відчуваю, що мови, які відрізняються лише кодуванням, справді нудні.
DJMcMayhem

1
@dj, але цей міг би займати менше байтів, а тому краще для гри в гольф.
NH.

5
Мозок-Флак не був розроблений таким, щоб бути хорошим у гольфі.
DJMcMayhem

Відповіді:


32

Brain-Flak , 952 916 818 байт

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

Збережені 360 байт шляхом обчислення протистоять дужок щодо , а не з нуля (наприклад , ')'= '(' + 1замість (((5 * 2) * 2) * 2) + 1)

Збережено 34 байти з деякими прямими замінами від DJMcMayhem

Збережено 10 байт, перекривши >]}код обробки

Збережено 118 байт шляхом дедупликації рулонів

Збережено 40 байт, скориставшись порожнім стеком, щоб спростити перший рулон

Збережено 48 байт, позначивши EOF -1, що дозволить отримати більш стислий код ролика

Збережено 36 байтів за допомогою запасу дорівнює логіці замість моєї власної

Збережено 98 байт завдяки Джо Кінгу знайти більш ефективний спосіб наростити вихід

Спробуйте в Інтернеті!

Перший раз гольф у Brain-Flak, тому, мабуть, є якісь справді великі поліпшення, але це працює. Багато копій / вставлення для обробки кожного типу дужок, і велике завдяки автоматичному генератору цілих чисел та фрагменту Roll звідси .

Пояснення тут , TIO формує його легше

Бонусна відповідь:

Стислий Brain-Flak 583 байт

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

Спробуйте в Інтернеті!

(Зверніть увагу, що вищезазначене посилання не працює, оскільки TIO не має стисненого інтерпретатора Brain-Flak. Транспілер для Brain-Flak можна знайти тут )

Я перевірив, що це дійсно, перекладаючи на Brain-Flak за допомогою цього інструменту, зараз достатньо ефективним, що відмітка часу є малоймовірною.


4
Перший раз по гольфу в Brain-Flak, а результат такий? Ого.
Erik the Outgolfer

Ви завжди можете замінити <>(<()>)на (<>). Також ви можете змінитись (<>{}<>)(<()>)до(<(<>{}<>)>)
DJMcMayhem

1
@JoKing Я б не знав як, я ледве встиг витягнути Roll в кінці циклу, а не мати додатковий у кожному блоці If
Kamil Drakari

1
Це поза гольфом. Це чисте безумство. Вітаємо!
Артур Аттаут

1
@JoKing Зміна була і простішою, і ефективнішою, ніж я очікував, і тепер включена у відповідь
Каміль Дракарі

7

Сітківка 0,8.2 , 103 98 байт

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

Спробуйте в Інтернеті! Посилання включає тестові випадки. Редагувати: збережено 5 байт з натхненням від @MartinEnder. Пояснення:

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

Поставте ;після кожного закритого дужки і змініть їх на відкриті дужки, а також змініть |s на ;s.

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

Порахуйте кількість незрівняних відкритих дужок і додайте стільки ;s.

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

Скопіюйте кожну відкриту дужку у відповідність ;.

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

Переверніть скопійовані дужки та видаліть ;s.


1
Ви можете уникнути всіх втечених барів, якщо перекладете |щось на зразок !. Це не буде навіть коштувати байт , якщо перевести >-}на <-{(який я думаю , що дає zдля |).
Мартін Ендер

@MartinEnder Не впевнений, що я розумію вашу думку щодо, zале я все-таки придумав спосіб гоління ще декількох байтів.
Ніл

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 -

Спробуйте в Інтернеті!

Я сумніваюся, що це найменше, але я не бачу способу зробити його меншим. На жаль, все NOPздається необхідним для синхронізації, і я не можу поставити стек, де @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

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, чомусь мене це не пінг. Я думаю, я б сказав ні. Масив символів або один рядок є обома стандартними форматами, але масив рядків мені не здається дійсним
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 байт

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

Спробуйте в Інтернеті!

Я почав це з відповіді Каміла Дракарі з гольфу , але це відійшло від мене до того моменту, коли я вирішив опублікувати це як окрему відповідь.

Пояснення:

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

І звичайно...

Стислий мозок-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

Збережено 4 байти завдяки DJMcMayhem.
Спробуйте в Інтернеті!



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пошуку відповідного дужки.
німі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.