Кількість байтів передбачає кодування ISO 8859-1.
+%`\B
¶$`:
1
Спробуйте в Інтернеті!
Альтернативне рішення:
+1`\B
:$`:
1
Пояснення
Це, мабуть, буде простіше пояснити на основі моєї старої, менш гольф-версії, а потім показати, як я її скоротив. Я використовував для перетворення двійкового в десятковий так:
^
,
+`,(.)
$`$1,
1
Єдиний розумний спосіб побудувати десятковий номер у Retina - це підрахунок речей (адже Retina має пару функцій, які дозволяють друкувати десятковий номер, який представляє суму). Тож дійсно єдино можливим підходом є перетворення двійкового у одинарне, а потім підрахунок кількості одинарних цифр. Останній рядок робить підрахунок, тому перші чотири перетворюють двійкові в одинакові.
Як ми це робимо? Загалом, для перетворення зі списку бітів у ціле число ми ініціалізуємо результат на, 0
а потім проходимо через біти від найбільшого до найменш значущого, подвоюємо значення, яке ми вже маємо, і додаємо поточний біт. Наприклад, якщо двійкове число є 1011
, ми б дійсно обчислили:
(((0 * 2 + 1) * 2 + 0) * 2 + 1) * 2 + 1 = 11
^ ^ ^ ^
Де я позначив окремі шматочки для наочності.
Хитрість робити це в уніру полягає в тому, що подвоєння просто означає повторення числа і b) оскільки ми підраховуємо 1
s в кінці, нам навіть не потрібно розрізняти 0
s і 1
s в процесі. Це стане зрозумілішим через секунду.
Програма робить те, що вона спочатку додає коду до початку як маркер для того, яку частину входу ми вже обробили:
^
,
Зліва від маркера, ми отримаємо значення, яке ми накопичуємо (яке правильно ініціалізовано до одинарного представлення нуля), а право значення буде наступним бітом, який слід обробити. Тепер ми застосовуємо таку заміну в циклі:
,(.)
$`$1,
Просто дивлячись на, ,(.)
і $1,
це переміщує маркер один раз праворуч. Але ми також вставляємо $`
, що є все перед маркером, тобто поточне значення, яке ми подвоюємо. Ось окремі кроки при обробці вводу 1011
, де я позначив результат вставки $`
над кожним рядком (це перший крок порожній):
,1011
1,011
_
110,11
___
1101101,1
_______
110110111011011,
Ви побачите, що ми зберегли і подвоїли нуль разом із усім іншим, але оскільки ми їх ігноруємо в кінці, не має значення, як часто ми їх подвоювали, доки кількість 1
s правильно. Якщо порахувати їх, є11
їх, саме те, що нам потрібно.
Отже, це залишає питання про те, як пограти в гольф до 12 байт. Найдорожча частина 18-байтової версії - використання маркера. Мета - позбутися цього. Ми дуже хочемо подвоїти префікс кожного біта, тому перша ідея може бути такою:
.
$`$&
Проблема полягає в тому, що ці заміни відбуваються одночасно, тому перший біт не подвоюється за кожен біт, а просто копіюється один раз кожен раз. Для введення 1011
ми отримаємо (маркування вставленого $`
):
_ __ ___
1101011011
Нам ще потрібно обробити введення рекурсивно, щоб подвоєний перший префікс знову подвоївся другим тощо. Одна ідея - вставити маркери скрізь і кілька разів замінити їх префіксом:
\B
,
+%`,
¶$`
Після першої заміни кожного маркера префіксом нам потрібно запам'ятати, де був початок введення, тому ми також вставляємо лінійку передач і використовуємо %
параметр, щоб переконатися, що наступний $`
лише підбирає речі до найближчого рядкового рядка.
Це працює, але це все ще занадто довго (16 байт під час підрахунку 1
s в кінці). Як щодо того, як ми перевертаємо речі? Місця, де ми хочемо вставити маркери, позначаються \B
(позиція між двома цифрами). Чому ми просто не вставимо префікси в ці позиції? Це майже працює, але різниця полягає в тому, що в попередньому рішенні ми фактично видаляли один маркер у кожній заміні, і це важливо, щоб процес припинився. Однак \B
це не характер, а просто позиції, тому нічого не знімається. Однак ми можемо зупинити це\B
від збігу, замість того, щоб замість цього вставити нецифровий символ у це місце. Це перетворює неслововий кордон у межу слова, що є еквівалентом попереднього видалення символу маркера. І ось що робить 12-байтне рішення:
+%`\B
¶$`:
Ось лише для повноти, ось окремі етапи обробки 1011
з порожнім рядком після кожного кроку:
1
1:0
10:1
101:1
1
1:0
1
1:0:1
1
1:0
10:1:1
1
1:0
1
1:0:1
1
1:0
1
1:0:1:1
Знову ви побачите, що останній результат містить рівно 11 1
с.
Як вправу для читача, чи можете ви бачити, як це досить просто узагальнює інші бази (на кілька додаткових байтів на приріст у базі)?