BrainF ** k, 396 391 байт
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
Я не втримався від спокуси зробити це. По крайней мере, трикутник вказує стороною вниз.
Введення надходить як рядок числових символів, за яким слідує один новий рядок.
Вихідні дані містять один пробіл у кожному рядку.
Приклади:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
Пояснення
Оскільки досить складно пояснити код з функціональної точки зору, ми можемо замість цього подивитися на нього з точки зору стану стрічки в різний час. Основна ідея тут полягає в тому, що трикутник, який ми виводимо, ініціалізується як щільно упакований (для BF, все одно) масив, який зменшується в розмірі на 1 раз на кожну ітерацію циклу. Ще одна важлива думка полягає в тому, що ми використовуємо 255для позначення «заповнювача місця», якого ми можемо шукати на стрічці.
Ініціалізація
Це найпростіший крок. На початку програми ми виконуємо наступне:
>+>>++++[-<++++++++>]->
Це змушує стрічку в наступний стан (де >N<вказується розташування вказівника на стрічці)
[ 0 1 32 255 >0< 0 0 ...]
Перше число тут - "буфер". Ми не збираємось використовувати його довгостроково, але корисно зробити невеликі операції простішими та копіювати дані навколо.
Друге число - це кількість пробілів, які ми будемо виводити на початку кожного рядка, починаючи після першого рядка. У першому рядку не буде провідних пробілів.
Третє число - пробільний символ, який ми виводимо.
Четверте число - це заповнення 255, щоб ми могли відносно легко повернутися до цієї позиції.
Вхідні дані
З цієї позиції ми прочитаємо всіх персонажів. Наприкінці цього кроку ми сподіваємося опинитися в такій ситуації:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
Де a b c d e f ...вказується рядок числових символів, який був введений (не новий рядок).
Ми виконуємо це за допомогою наступного:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
У цьому є деякі нюанси. Перш за все, ми будемо виводити кожен символ у міру їх отримання, а потім виводимо пробіл після нього. По-друге, ми не хочемо копіювати значення ASCII на стрічку, ми хочемо скопіювати фактичну числову цифру. По-третє, ми хочемо зупинитися, коли потрапили в новий рядок і залишимо себе на хорошому місці в той час.
Скажіть, наш внесок є 6723. Потім, прочитавши першу 6, наша стрічка виглядає так:
[ 0 1 32 255 >54< 0 0 ...]
Ми перевіряємо, що це значення не дорівнює 10(новий рядок ASCII) з ,----------[++++++++++. Потім ми роздруковуємо значення і продовжуємо, одночасно віднімаючи 48 від вхідного значення і додаючи 32 до значення поруч із ним ( >>++++++++[-<++++<------>>]<), залишаючи нас тут:
[ 0 1 32 255 6 >32< 0 ...]
Зверніть увагу, як протягом цього процесу ми можемо припустити, що всі цифри праворуч від нашого введення дорівнюють 0 - це означає, що нам не загрожує зруйнування будь-якого попереднього стану, якщо ми будемо використовувати значення праворуч для обчислення 6 * 8та 4 * 8.
Тепер ми виводимо символ простору, який ми щойно створили, і вводимо новий ввід, видаляючи прорахований нами простір. Врешті-решт, вхід буде припинено новим рядком, і цикл вийде, залишаючи a, 255де був би новий рядок ( ,----------]-). Це другий символ заповнювача, який ми будемо використовувати для навігації по стрічці. На даний момент у нашому сценарії наша стрічка саме така:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
Розрахунок
Як це працює, це те, що список цифр між нашими 255заповнювачами зменшиться по одній ітерації циклу. Коли в ньому залишилося лише одна цифра, ми закінчили і повинні негайно зупинитися (зауважте, що в цей момент кожна цифра у цьому списку вже виведена, тому нам не доведеться турбуватися про її виведення знову).
Тепер ми використовуємо цей трюк , щоб перейти до першого 255заповнювач: <+[-<+]-. Це ефективно шукає стрічку ліворуч 255, не змінюючи нічого між ними. Тепер, коли ми перемістили вказівник, ми можемо перевірити нашу умову виходу: якщо в списку є лише одна цифра, то в комірці буде розміщено два пробіли праворуч 255. Таким чином, ми перевіряємо це і починаємо цикл:>>+[-<<
Перший крок у нашому циклі - вивести новий рядок. Тому ми переходимо до першої комірки (наша буферна комірка), додаємо до неї 10 і виводимо. Наступним кроком є виведення всіх провідних символів космосу. Вивівши їх, ми збільшуємо свій рахунок на кількість провідних просторів. Ці дії виконуються за допомогою наступного:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
Що залишає нас у такому стані:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
Наступний наш крок - скопіювати перше значення у списку, окрім другого заповнювача 255:
[[->+]->>+<<<+[-<+]->]
Ми по суті робимо це, стрибаючи вперед і назад між нашими заповнювачами 255, залишаючи нас тут:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
Тепер ми починаємо цикл, повторюючи решту списку, зупиняючись при натисканні 255:>+[-<
У цій точці цифра, що знаходиться зліва від нас, завжди дорівнює 0. Отже, оскільки ми їх любимо, ми вставляємо 255там заповнювач, щоб ми могли повернутися до свого місця у списку. Наступним кроком є переміщення другого місця в списку в місця, які оточують місце, де ми перемістили перше місце, окрім другого заповнювача 255. Ці дії виконуються за допомогою наступного:
->
[[->+]->+>>+<<<<+[-<+]->]
Залишаючи нас тут: [ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
тепер і обидва, 6і 7були переміщені до місця, де може відбутися обчислення. Нам потрібні дві копії 7тому, що наступний номер у списку також буде потрібен. 7Відразу ж після 255цієї мети служить, тоді як інший 7буде споживатися розрахунку.
Спочатку додаємо дві цифри:
<+>->+[->+]->>
[->+<]>
Залишаючи нас тут:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
Наступна комбінація кроків - найскладніша. Нам потрібно подивитися, чи число, на яке ми вказуємо, більше 10, і якщо воно є, ми віднімаємо 10. Насправді ми робимо, що ми віднімаємо з нього 10 і бачимо, чи потрапило воно 0в якусь точку віднімання. Якщо так, ми додаємо 10пізніше. Наприкінці цього ми повинні мати модуль суми 10.
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
На цьому етапі ми досягли мети. У нас сума модуля 10! Крім того, незалежно від того, чи було число більше 10, ми закінчимо тут:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
Наступні наші цілі - вивести цю нову суму, прослідкувати її з пробілом та вставити її в наш список. Ми все це робимо за допомогою попередніх технік 255-копірування та додавання 48до нашої суми, тому я не буду це детально висвітлювати.
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
І ми тут: [ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
Зверніть увагу, як ми додаємо додатковий 255заповнювач після того, як щойно введений, 3щоб ми не втратили місце в списку. У цей момент ми виводимо свою суму та її простір, тому нам потрібно очистити та повернути до стану, коли буде працювати наступна ітерація цього циклу. Нам потрібно очистити наші 51і 32комірки, перемістити 7один раз праворуч і перейти до заповнювача списку, щоб ми могли почати все спочатку.
[-]<[-]<<<[->+<]<<+[-<+]
Тепер ми тут: [ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
саме там ми хочемо стати для наступної ітерації. Тож перевіряйте 255 і рухайтеся далі! ( >+])
Коли ми вийдемо з циклу, у нас з’явиться цілий новий список - складений із сум попереднього списку. Перший раз це виглядатиме так:
[ 0 2 32 255 3 9 5 0 >0< ]
Тепер ми хочемо повторити весь цей процес у нашому новому списку, тому ми пливемо 255униз ліворуч і починаємо все спочатку! Нам потрібно зробити трохи очищення >>[-]<<, а потім скинути наш заповнювач <-. Після цього ми знаходимося в тому самому місці, що і після введення, тому ми можемо піти, роблячи ті самі перевірки: <+[-<+]->>+і бум! У нас є наш повний цикл! Все , що нам потрібно це закриває дужка, і коли він закінчується , ми вже на виході все, тому ми зробили: ].