Digraphs를 사용하여 23 개의 고유 한 문자. (없이 25). UB가 없습니다.
사용 C ++ 구문 초기화 보강 (11) 에 제로의 정수를 목록 초기화 int var{};방지 =및 0. 또는 귀하의 경우 전역을 피하십시오 iiii. 전역 변수 이외의 0 소스를 제공합니다 (로컬과 달리 정적으로 0으로 초기화 됨).
현재 컴파일러는 특별한 옵션을 활성화 할 필요없이 기본적으로이 구문을 허용합니다.
(정수 랩 어라운드 트릭은 재미 있고 최적화가 비활성화 된 골프에는 괜찮지 만, 부호있는 오버플로는 ISO C ++에서 정의되지 않은 동작입니다. 최적화를 활성화하면 gcc / clang -fwrapv으로 컴파일하여 부호있는 정수 오버 플로우를 제대로 제공 하지 않는 한 해당 랩 어라운드 루프를 무한 루프로 바꿉니다. 정의 된 동작 : 2의 보완 랩 어라운드.
재미있는 사실 : ISO C ++ std::atomic<int>에는 잘 정의 된 2의 보완 기능이 있습니다! int32_t모두에 정의 된 경우 2의 보수를 할 필요가있다하지만 여전히에 대한 형식 정의 할 수 있도록 오버 플로우 동작은 정의되지 int또는 long그 유형 중 하나는 32 비트, 아니 패딩을 어떤 기계에, 2의 보수.)
이 특정한 경우에는 유용하지 않습니다 :
중괄호 또는 비어 있지 않은 이니셜 라이저를 사용하여 직접 초기화를 위해 기존 변수의 사본으로 새 변수를 초기화 할 수도 있습니다 .
int a(b)또는 int a{b}동등int a = b;
그러나 int b();0으로 초기화 된 변수 대신 함수를 선언합니다.
또한, 당신은과 0을 얻을 수 있습니다 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 환경을 가정하면 space의 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대신 사용 ||). 아뇨, 작동하지 않습니다. gotoA는 문 같은 if과 표현의 하위 구성 요소는 펄 수 등이 될 수 없습니다. 그렇지 않으면 (및 )문자 를 제거하는 데 사용할 수 있습니다 .
우리는 무역 수 f를 위해 g함께 if(stuff) goto label;대신에 for, 우리는 보통은 ASM처럼, 맨 아래에 루프 지점 필요할 것 때문에 두 루프는 항상 적어도 1 반복을 실행하는 do{}while루프 구조. 사용자가 정수> 0을 입력한다고 가정하면 ...
디 그래프 및 트리 그래프
운 좋게도 ISO C ++ 17에서 3 점을 제거 했으므로 가장 최근의 C ++ 개정을 위해 고유 한 골프 ??>대신에 사용할 필요가 없습니다 }.
그러나 특히 3 가지 그래프 : ISO C ++ 17에는 여전히 :>for ]및 %>for 와 같은 digraph 가} 있습니다. 그래서 사용하는 비용에 %, 우리는 모두 피할 수 {와 }, 및 사용 %:을 위해 #이 개 적은 고유 한 문자의 순 절약을 위해.
그리고 C ++처럼 운영자 키워드가 not에 대한 !운영자, 또는 bitor에 대한 |연산자입니다. xor_eqfor를 사용하면 을 사용 ^=하여 변수를 0으로 만들 수 i xor_eq i있지만 사용하지 않은 여러 문자가 있습니다.
Current는 g++이미 기본적으로 3 점을 무시합니다 -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)대부분의 터미널에서 너비가 0으로 인쇄됩니다. 따라서 출력은 1234그렇지 않은 것처럼 보입니다 1 2 3 4. 또는 더 이상, 자동으로 붕괴되지 않은 것은 쓰레기로 분리됩니다 '\0'.
당신이 임의의 구분 기호를 사용할 수있는 경우 숫자는 경우 0에 쉽게 만들 수 있습니다 cout << some_zeroed_var. 그러나 아무도 원하지 10203040않습니다. 분리자가없는 것보다 더 나쁩니다.
나는 문자열 리터럴 을 사용하지 않고 홀딩 을 만드는std::string" " 방법을 생각하려고했습니다 char. 어쩌면 그것에 무언가를 추가? 생성자 중 하나를 통해 길이가 1 인 []바이트를 32만든 후 첫 번째 바이트를 값으로 설정하기 위한 digraph가 있습니까?
Johan은 또한 현재 채우기 문자를 반환 하는 std::iosfill () 멤버 함수 를 제안했습니다 . 스트림의 기본값은로 설정되며 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도움 이 되는 경우 상속을 무시할 수 있습니다 ).