23 унікальні символи за допомогою Digraphs. (25 без). Немає УБ.
Використовуйте синтаксис ініціалізатора, уповноваженого C ++ 11, для списку-ініціалізації цілого числа до нуля, int var{};
уникаючи =
та 0
. (Або у вашому випадку, уникаючи глобальних iiii
). Це дає вам джерело нулів, окрім глобальних змінних (які статично ініціалізовані до нуля, на відміну від локальних).
Поточні компілятори приймають цей синтаксис за замовчуванням, не вмикаючи жодних спеціальних параметрів.
(Цілий фокус накрутки - це весело, і нормально для гольфу з вимкненою оптимізацією, але підписане переповнення не визначене поведінка в ISO C ++. Увімкнення оптимізації перетворить ці петлі накрутки в нескінченні петлі, якщо ви не компілюєте з gcc / clang, -fwrapv
щоб дати підписаному цілому цілому переповнення добре -визначена поведінка: обробка комплексу 2
Веселий факт: ISO C ++ std::atomic<int>
має чітко визначений підсумок 2 доповнення! int32_t
Потрібно бути доповненням 2, якщо його взагалі визначено, але поведінка переповнення не визначено, тому воно все ще може бути typedef для int
або long
на будь-якій машині, де один із цих типів має 32 біти, без прокладки та доповнення 2).
Не корисно для цього конкретного випадку:
Ви також можете ініціалізувати нову змінну як копію існуючої з дужками або (з не порожнім ініціалізатором), паронами для прямої ініціалізації .
int a(b)
або int a{b}
еквівалентніint a = b;
Але int b();
оголошує функцію замість змінної, ініціалізованої до нуля.
Крім того , ви можете отримати нуль з int()
або char()
, тобто нуль-ініціалізації анонімного об'єкта.
Ми можемо замінити ваші <=
порівняння зі <
порівняннями простим логічним перетворенням : зробіть приріст циклу лічильника відразу після порівняння, а не внизу циклу. ІМО це простіше, ніж запропоновані людьми альтернативи, як, наприклад, використовувати ++
в першій частині а, for()
щоб зробити 0 в число 1.
// comments aren't intended as part of the final golfed version
int n;
std::cin >> n; // end condition
for(int r{}; r < n;) { // r = rows from 0 .. n-1
++r;
for(int i{}; i < r;) {
++i;
std::cout << i << ' ';
}
std::cout << std::endl;
}
Ми могли б пограти в гольф аж до for(int r{}; r++ < n;)
ІМО, який людині читати менш просто. Ми не оптимізуємо загальну кількість байтів.
Якщо ми вже використовували h
, ми могли б зберегти простір '
або "
для нього.
Якщо припустити середовище ASCII або UTF-8, простір має char
значення 32. Ми можемо створити це в змінній досить легко, тодіcout << c;
char c{};
c++; c++; // c=2
char cc(c+c+c+c); // cc=8
char s(cc+cc+cc+cc); // s=32 = ' ' = space in ASCII/UTF-8
І інші значення, очевидно, можуть бути створені з послідовності ++
та подвоєння, виходячи з бітів їх бінарного подання. Ефективно зміщення 0 (нічого) або 1 (++) у LSB перед подвоєнням на нову змінну.
Ця версія використовує h
замість '
або "
.
Це набагато швидше, ніж будь-яка з існуючих версій (не покладається на довгий цикл), і не містить Undefined Behavior . Він компілюється без попереджень із g++ -O3 -Wall -Wextra -Wpedantic
та зclang++
. -std=c++11
необов’язково. Це законний і портативний ISO C ++ 11 :)
Він також не покладається на глобальні змінні. І я зробив це більш зрозумілим для людини зі змінними іменами, які мають значення.
Унікальний байт: 25 , за винятком коментарів, які я позбавивg++ -E
. І виключаючи простір та нову лінію, як ваш лічильник. Я використовував sed 's/\(.\)/\1\n/g' ladder-nocomments.cpp | sort | uniq -ic
з цього askubuntu для підрахунку подій кожного символу, і передавав це, wc
щоб підрахувати, скільки унікальних символів у мене було.
#include<iostream>
int main() {
char c{};
c++; c++; // c=2
char cc(c+c+c+c); // cc=8
char s(cc+cc+cc+cc); // s=32 = ' ' = space in ASCII/UTF-8
int n;
std::cin >> n; // end condition
for(int r{}; r < n;) { // r = rows counting from 0
++r;
for(int i{}; i < r;) {
++i;
std::cout << i << s;
}
std::cout << std::endl;
}
}
Тільки 2 f
символи - від for
. Ми могли б while
замість цього використовувати петлі, якби для них використовувались w
.
Ми, можливо, зможемо переписати петлі у стилі мови складання, i < r || goto some_label;
щоб написати умовний стрибок у нижній частині циклу, чи будь-що інше. (Але використовуючи or
замість ||
). Ні, це не працює. goto
є твердженням, як if
і не може бути підкомпонентним виразом, як він може в Perl. В іншому випадку ми могли б використовувати його для видалення символів (
і )
.
Ми могли б торгувати f
на g
з if(stuff) goto label;
а for
, і обидві петлі завжди виконуються по крайней мере 1 ітерації , тому ми повинні були б тільки одну петлю-гілки в нижній частині, як нормальний ASM do{}while
структури петлі. Якщо припустити, що користувач вводить ціле число> 0 ...
Диграфи та триграфи
На щастя, триграфи були вилучені за ISO C ++ 17, тому нам не доведеться використовувати ??>
замість того, }
якщо ми унікальні для гольфу для останньої редакції C ++.
Але тільки тріграфи саме: ISO C ++ 17 по і раніше має диграфів як :>
для ]
і %>
для}
. Тож ціною використання %
ми можемо уникнути і {
і }
, і використовувати %:
для #
чистої економії на 2 менших унікальних символи.
І C ++ має ключові слова оператора, як not
для !
оператора, або bitor
для |
оператора. З допомогою xor_eq
for ^=
, ви можете нульову змінну i xor_eq i
, але вона містить кілька символів, які ви не використовували.
Поточна g++
вже ігнорує триграфи за замовчуванням навіть без -std=gnu++17
; ви повинні використовувати -trigraphs
їх, щоб увімкнути їх, або -std=c++11
щось для того, щоб суворо відповідати стандарту ISO, який не включає їх.
23 унікальних байти:
%:include<iostream>
int main() <%
int n;
std::cin >> n;
for(int r<% %>; r < n;) <%
++r;
for(int i<%%>; i < r;) <%
++i;
std::cout << i << ' ';
%>
std::cout << std::endl;
%>
%>
Спробуйте в Інтернеті!
В остаточній версії використовується '
одноцитата замість h
або "
для роздільника пробілів. Я не хотів диграфувати char c{}
матеріал, тому я його видалив. Друк знака є більш ефективним, ніж друк рядка, тому я використовував це.
Гістограма:
$ sed 's/\(.\)/\1\n/g' ladder-nocomments.cpp | sort | uniq -ic | tee /dev/tty | wc -l
15 // newline
95 // space
11 %
2 '
3 (
3 )
4 +
9 :
10 ;
14 <
8 >
2 a
4 c
6 d
3 e
2 f
12 i
2 l
2 m
11 n
5 o
7 r
5 s
11 t
3 u
25 // total lines, including space and newline
Розділювач простору (досі невирішений)
У видаленій відповіді Йохан Дю Тойт запропонував конкретно використовувати альтернативний роздільник std::ends
. Це символ NUL char(0)
, і друкується як нульова ширина на більшості терміналів. Таким чином, вихід буде виглядати, як 1234
ні 1 2 3 4
. Або ще гірше, розділений сміттям на будь-що, що мовчки не руйнувалося '\0'
.
Якщо ви можете використовувати довільний роздільник, коли цифру 0
легко створити за допомогою cout << some_zeroed_var
. Але ніхто не хоче 10203040
, це ще гірше, ніж жоден роздільник.
Я намагався придумати спосіб створення std::string
холдингу" "
без використання char
або рядкового літералу. Можливо, до чогось додати? Може, за допомогою диграфа для []
встановлення першого байта значення 32
, після створення одного з довжиною 1 через один з конструкторів?
Йохан також запропонував std::ios
функцію члена (), яка повертає поточний символ заповнення. За замовчуванням для потоку встановлюється std::basic_ios::init()
та є ' '
.
std::cout << i << std::cout.fill();
замінює, << ' ';
але використовує .
замість'
.
З -
, ми можемо взяти покажчик cout
і використання ->fill()
для виклику функції - члена:
std::cout << (bitand std::cout)->fill()
. Чи ні, ми не використовуємо b
ні таким чином , ми могли б також використовували &
замість його лексичного еквівалента bitand
.
Виклик функції члена без .
або->
Помістіть його всередину класу та визначте operator char() { fill(); }
// not digraphed
struct ss : std::ostream { // default = private inheritance
// ss() { init(); } // ostream's constructor calls this for us
operator char() { return fill(); }
}
Потім ss s{}
перед циклом, а std::cout << i << s;
всередині петлі. Відмінно, він збирає і працює нормально, але ми повинні були використовувати p
і h
для operator char()
, для чистої втрати 1. Принаймні , ми уникали , b
щоб функцій - членів public
, використовуючи struct
замість class
. (І ми могли б перекрити спадщину, protected
якщо це коли-небудь допоможе).