23 уникальных персонажа, использующих Digraphs. (25 без). Нет UB.
Используйте синтаксис скобочных инициализаторов 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()
, то есть инициализацию нуля анонимного объекта.
Мы можем заменить ваши <=
сравнения <
сравнениями простым логическим преобразованием : сделайте приращение счетчика цикла сразу после сравнения, а не внизу цикла. IMO, это проще, чем альтернативы, предложенные людьми, например, использование ++
в первой части a, 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;)
но IMO, что людям труднее читать. Мы не оптимизируем общее количество байтов.
Если бы мы уже использовали 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
вместо '
или "
.
Это намного быстрее, чем любая из существующих версий (не полагаясь на длинный цикл), и не содержит неопределенного поведения . Он компилируется без предупреждений с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
этот аскубунту для подсчета вхождений каждого персонажа, и 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 итерации , поэтому мы должны были бы только одну петлю-ветви в нижней части, как обычный ассемблере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
Разделитель пространства (до сих пор не решен)
В уже удаленном ответе Johan Du Toit предложил использовать, в частности, альтернативный разделитель std::ends
. Это символ NUL char(0)
, и он печатается как нулевая ширина на большинстве терминалов. Таким образом, результат будет выглядеть 1234
, а не 1 2 3 4
. Или, что еще хуже, отделенный мусором от всего, что не рухнуло'\0'
.
Если вы можете использовать произвольный разделитель, когда цифру 0
легко создать cout << some_zeroed_var
. Но никто не хочет 10203040
, это даже хуже, чем без разделителя.
Я пытался придумать способ создания std::string
холдинга" "
без использования char
строкового литерала. Может быть, что-то добавить к этому? Может быть, с орграфом для []
установки первого байта в значение 32
после создания единицы длиной 1 через один из конструкторов?
Йохан также предложил std::ios
функцию-член fill (), которая возвращает текущий символ заполнения. По умолчанию для потока установлено значение 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
в случае, если это когда-нибудь поможет).