Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Код-гольф - Создание генератора кода для печати строк в Brainfuck

Внимание! Соревнование окончено! Огромное спасибо всем тем, кто принял в нем участие) Вы можете ознакомиться с результатами и различными алгоритмами решения поставленной задачи ниже, а если вдруг у Вас возникнет хорошая идея реализации всего этого дела - не стесняйтесь и публикуйте, ведь пусть конкурс уже и закрыт, идеи, предложенные здесь, возможно, впоследствии порадуют одинокого странника ruSO, изучающего вопросы по меткам code-golf и соревнование)

Товарищи! Давненько не проходило у нас никаких соревнований, так что стоит исправить сие досадное упущение)

Думаю, каждый из нас хоть немного знаком с эзотерическим языком Brainfuck и его в буквальном смысле мозговыносящим синтаксисом. Обычное Hello world выглядит страшнее и сложнее ПО для Аполлона 11... А почему бы не автоматизировать процесс создания кода на Brainfuck для вывода нужных нам строк? Таки вопрос риторический, ибо этим мы и займемся)

Задача:
Требуется описать на любом языке программирования функцию, которая в качестве аргумента принимает строку, а на выход дает код на языке Brainfuck (также в виде строки), позволяющий распечатать входную строку

Подробнее:
Как Вы понимаете, функцию необходимо максимально ужать. Однако это еще не все: роль также будет играть длина выходного кода, так что решение "в лоб" не подойдет) Вам необходимо будет протестировать свой код на следующих двух строках:
s1 = "Hello world" s2 = "Goodbye Brainfuck"

Правила:
При решении задачи можно использовать любой язык программирования Можно оставлять несколько вариантов ответа (в разных постах) Запрещено использовать какие-либо сторонние библиотеки для решения поставленной задачи, если они не являются частью используемого языка/платформы Запрещено внутри реализуемой функции использовать строки s1 и s2 в явном или зашифрованном виде Желательно оставлять ссылку на онлайн-компилятор Вашего кода В ответе приводите как минифицированную версию Вашей функции, так и "развернутую" (пояснения приветствуются), чтобы каждый мог разобраться в магии Вашего кода и, возможно, почерпнуть что-то для себя Сгенерированный код на Brainfuck должен быть рабочим и выводить строки s1 и s2 (проверить код можно, скажем, тут или тут) Обязательным условием является наличие у Вашего ответа заголовка в формате

Язык, Кол-воСимволов

(требуется для парсера таблицы лидеров) Рассчет символов определяется следующей формулойN = func.Length + Ceil(1.5 * (B(s1).Length + B(s2).Length)) N - число символов, которое необходимо указать в ответе func.Length - длина Вашей минифицированной функции (следует учитывать только длину тела функции) B(s1).Length - длина выходного кода для строки s1 B(s2).Length - длина выходного кода для строки s2 Ceil - функция округления к ближайшему целому, которое больше заданного значения (Ceil(2.5) == 3) Продолжительность соревнования: 7 дней

Определение победителей:
Победители определяются по следующей градации:
Реализация с наименьшим числом символов Реализация с наивысшим активным рейтингом (общее число плюсов - общее число минусов) Реализация с самой ранней первой редакцией
P.S. - работа автора поста не принимает участия в подведении итогов

Если возникнут вопросы по правилам проведения конкурса - задавайте их в комментариях)

Удачи в реализации, товарищи!

Итоги:
1 место: @Groxan - c#, ответ занял 745(!) символов 2 место: @b1nary - python, ответ занял 827 символов 3 место: @rjhdby - php, ответ занял 834 символа Собственно, хотелось бы сказать пару слов о прошедшем соревновании) Еще раз огромное спасибо каждому, кто принял участие в сием мероприятии, ведь, думаю, каждый из нас смог почерпнуть из идей других участников что-то новое и интересное! Было очень интересно разбирать код, его ужатый вид, а также и логику во всех ответах, каждый из которых по-своему элегантен и интересен) И отдельно, конечно, хочется сказать про работу @Groxan, которая заняла всего 745 символов! Честно, когда я предложил данный эвент, я даже не предполагал, что хоть одна реализация преодолеет барьер в 800 символов. Но это таки случилось. Работа победителя нашего соревнования проделала уверенный путь от 912 символов к победным и действительно удивительным 745 символам! Почему "удивительным"? Предложенный алгоритм смог посоревноваться не только с участниками данного код-гольфа, но и с решением, приведённым на Wikipedia (111 символов):
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
Сгенерировав код для строки Hello World! (отличается от конкурсной строки s1) алгоритмом из ответа-победителя, мы получим ровно те же 111 символов:
-[------->+<]>-.-[->+++++<]>++.+++++++..+++.+[->--<]>.---[->+++<]>.+[--->--<]>-.+++.------.--------.-[--->+<]>.
Удивительное совпадение) Очень радует, что наше соревнование и совместные усилия участников смогли создать такой вот замечательный алгоритм! Так что еще раз отдельное спасибо каждому участнику! До новых соревнований!

Таблица лидеров:
execute(849931); .cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}}.cssload-container,.cssload-cube{width:97px;height:97px;transform-style:preserve-3d}.cssload-container,.cssload-cube,.cssload-half1,.cssload-half2{transform-style:preserve-3d}.cssload-container{position:relative;margin:23px 84px;perspective:292px}.cssload-cube{animation:cube 11.5s forwards infinite;transform-origin:center 49px}.cssload-half1,.cssload-s1{top:0;transform-origin:50% 100%}.cssload-half1{height:39px;position:absolute;animation:half-fold 11.5s forwards infinite}.cssload-side{width:19px;height:19px;background:#ddd;position:absolute}.cssload-s1{left:39px;animation:s1ani 11.5s forwards infinite}.cssload-s2,.cssload-s3,.cssload-s4{left:39px;transform-origin:50% 0}.cssload-s2{top:19px;animation:s2ani 11.5s forwards infinite}.cssload-s3{top:39px;animation:s3ani 11.5s forwards infinite}.cssload-s4{top:58px;animation:s4ani 11.5s forwards infinite}.cssload-s5{left:19px;top:19px;transform-origin:100% 50%;animation:s5ani 11.5s forwards infinite}.cssload-s6{left:58px;top:39px;transform-origin:0 50%;animation:s6ani 11.5s forwards infinite}@keyframes cube{0%,30%{transform:rotateX(0)}40%{transform:rotateX(45deg) rotateY(0) rotate(45deg)}60%{transform:rotateX(60deg) rotateY(0) rotate(45deg)}65%,70%{transform:rotateX(60deg) rotate(45deg) rotate(180deg)}75%,80%{transform:rotateX(60deg) rotate(45deg) rotate(1turn)}90%{transform:rotateX(0) rotate(0) rotate(0)}}@keyframes s1ani{0%{opacity:1;transform:translateY(0);background:#ddd}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(-90deg);background:#ddd}90%{transform:rotateX(-90deg)}}@keyframes s2ani{0%{opacity:0;transform:rotateX(-179deg)}10%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%,80%{background:#b4b4b4}65%{opacity:1;background:#b4b4b4}90%{opacity:1}to{opacity:0}}@keyframes s3ani{0%,10%{opacity:0;transform:rotateX(-179deg)}20%,90%{opacity:1;transform:rotateX(0)}40%{background:#ddd}45%{background:#969696}to{opacity:0}}@keyframes s4ani{0%,20%{opacity:0;transform:rotateX(-179deg)}10%,to{opacity:0}30%{opacity:1;transform:rotateX(0)}40%{transform:rotateX(0);background:#ddd}50%{transform:rotateX(90deg);background:#b4b4b4}80%{background:#b4b4b4}90%{opacity:1;transform:rotateX(90deg)}}@keyframes s5ani{0%,10%{opacity:0;transform:rotateY(-179deg)}20%{opacity:1;background:#ddd;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(90deg)}55%{background:#ddd}60%{background:#c8c8c8}90%{transform:rotateY(90deg);opacity:1}to{opacity:0}}@keyframes s6ani{0%,20%{opacity:0;transform:rotateY(179deg)}30%{opacity:1;transform:rotateY(0)}40%{transform:rotateY(0)}50%{transform:rotateY(-90deg);background:#ddd}60%,80%{background:#c8c8c8}90%{opacity:1;transform:rotateY(-90deg)}to{opacity:0}}@keyframes half-fold{0%,50%{transform:rotateX(0)}60%,90%{transform:rotateX(-90deg)}}body{font-size: 1rem;line-height: 1.5rem;font-family: 'Open Sans', sans-serif;background: #fff;padding: 0 2rem;}h1{font-weight: 600;margin-bottom: 3rem;text-align: center;color: #212121;}#leadership{width: 100%;margin: 1rem auto;border-collapse: collapse;box-shadow: 0 2px 7px rgba(0,0,0,0.2);background: #fafafa;}#leadership td{padding: 1rem .5rem !important;text-align: left;font-weight: 500;transition: all .3s ease-in-out;}#leadership tr:hover td{background: #03a9f4;color: #fefefe;}#leadership tr:hover td a{color: #fff;}#leadership th{padding: 1.5rem .5rem !important;color: #727272;text-align: left !important;font-weight: 500;border-bottom: 1px solid #dcdcdc;}#leadership a{text-decoration: none;color: #212121;}#leadership a:hover{color: #03a9f4;}#leadership td:nth-of-type(1){text-align: center;color: #727272;font-size: .75rem;}#leadership td:nth-of-type(2){}#leadership td:nth-of-type(2) img{width: 34px;border-radius: 50%;}#leadership th:nth-of-type(5),#leadership th:nth-of-type(6),#leadership th:nth-of-type(7),#leadership td:nth-of-type(5),#leadership td:nth-of-type(6),#leadership td:nth-of-type(7) {text-align: center !important;}


Ответ

C#, 745
Функция (334 символа):
string w(int k)=>new string(k>0?'+':'-',k>0?k:-k); int c(int a,int b,int f=0)=>f>255|a%256==0?f:c(a+b,b,++f); string m(char p,char x){var o=w(x-p);for(int d,n,s=-9;++s<9;)for(d=-9;++d<9;)for(n=-9;++n<9;){var t=w(s)+$"[{w(d)}>{w(n)}<]>"+w(x-c(p+s,d)*n%256);o=t.LengthHello world (97 символов):
-[------->+<]>-.-[->+++++<]>++.+++++++..+++.+[->--<]>.--[->++++<]>-.--------.+++.------.--------.
Goodbye Brainfuck (177 символов):
-[------->+<]>--.+[->--<]>-..-----------.--.[->----<]>+.--[->+++<]>.--[--->+<]>-.+[->++<]>.[----->---<]>.--[--->--<]>+.++++++++.+++++.--------.-[--->+<]>--.+[->+++<]>+.++++++++.
Чё происходит вообще?
string Brainfuck(string text) { //Трансформируем текст в массив разностей и подбираем кротчайший код для каждой return string.Concat($"\0{text}".Zip(text, FindBestCode)); }
string FindBestCode(char state, char target) { //Сперва генерируем тупой код var code = Fill(target - state);
//Потом пытаемся подобрать цикл вида 's[d>n<]>r.' так, чтобы он был как можно короче //Достаточно перебирать только три параметра, а четвертый вычислять на ходу //Вообще, чем шире диапазон перебора, тем лучше точность поиска for (int d, n, s = -9; ++s < 9;) for (d = -9; ++d < 9;) for (n = -9; ++n < 9;) { //Формируем цикл, попутно вычисляя 'r' var cycle = Fill(s)+$"[{Fill(d)}>{Fill(n)}<]>"+Fill(target - (IterationsCnt(state + s, d) * n + 256 * 10) % 256); //Если он короче, то запоминаем code = cycle.Length < code.Length ? cycle : code; }
return code + "."; }
int IterationsCnt(int state, int step, int cnt = 0) { //Определяем количество итераций в цикле с шагом 'step', который стартует из 'state' //Т.к. цикл может быть бесконечным, добавляем ограничение в 256 итераций return cnt > 255 | state % 256 == 0 ? cnt : IterationsCnt(state + step, step, ++cnt); }
string Fill(int cnt) { //Спамим '+' или '-' в зависимости от знака return new string(cnt > 0 ? '+' : '-', cnt > 0 ? cnt : -cnt); }

Комментариев нет:

Отправить комментарий