Кількість байтів передбачає кодування 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) оскільки ми підраховуємо 1s в кінці, нам навіть не потрібно розрізняти 0s і 1s в процесі. Це стане зрозумілішим через секунду.
Програма робить те, що вона спочатку додає коду до початку як маркер для того, яку частину входу ми вже обробили:
^
,
Зліва від маркера, ми отримаємо значення, яке ми накопичуємо (яке правильно ініціалізовано до одинарного представлення нуля), а право значення буде наступним бітом, який слід обробити. Тепер ми застосовуємо таку заміну в циклі:
,(.)
$`$1,
Просто дивлячись на, ,(.)і $1,це переміщує маркер один раз праворуч. Але ми також вставляємо $`, що є все перед маркером, тобто поточне значення, яке ми подвоюємо. Ось окремі кроки при обробці вводу 1011, де я позначив результат вставки $`над кожним рядком (це перший крок порожній):
,1011
1,011
_
110,11
___
1101101,1
_______
110110111011011,
Ви побачите, що ми зберегли і подвоїли нуль разом із усім іншим, але оскільки ми їх ігноруємо в кінці, не має значення, як часто ми їх подвоювали, доки кількість 1s правильно. Якщо порахувати їх, є11 їх, саме те, що нам потрібно.
Отже, це залишає питання про те, як пограти в гольф до 12 байт. Найдорожча частина 18-байтової версії - використання маркера. Мета - позбутися цього. Ми дуже хочемо подвоїти префікс кожного біта, тому перша ідея може бути такою:
.
$`$&
Проблема полягає в тому, що ці заміни відбуваються одночасно, тому перший біт не подвоюється за кожен біт, а просто копіюється один раз кожен раз. Для введення 1011ми отримаємо (маркування вставленого $`):
_ __ ___
1101011011
Нам ще потрібно обробити введення рекурсивно, щоб подвоєний перший префікс знову подвоївся другим тощо. Одна ідея - вставити маркери скрізь і кілька разів замінити їх префіксом:
\B
,
+%`,
¶$`
Після першої заміни кожного маркера префіксом нам потрібно запам'ятати, де був початок введення, тому ми також вставляємо лінійку передач і використовуємо %параметр, щоб переконатися, що наступний $`лише підбирає речі до найближчого рядкового рядка.
Це працює, але це все ще занадто довго (16 байт під час підрахунку 1s в кінці). Як щодо того, як ми перевертаємо речі? Місця, де ми хочемо вставити маркери, позначаються \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с.
Як вправу для читача, чи можете ви бачити, як це досить просто узагальнює інші бази (на кілька додаткових байтів на приріст у базі)?