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
대신 사용 ||
). 아뇨, 작동하지 않습니다. goto
A는 문 같은 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_eq
for를 사용하면 을 사용 ^=
하여 변수를 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::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
도움 이 되는 경우 상속을 무시할 수 있습니다 ).