최소 개수의 고유 문자를 사용하여 정수 래더 생성 (C ++)


13

나는 코드 골프의 스포츠를 처음 사용합니다. C ++에서 가장 적은 수의 고유 문자를 사용하여 정수 래더를 생성하려고합니다.

정수 4가 주어 졌다고 가정 해 봅시다.

다음 사다리를 생성합니다.

11
2
1 3
1 2 3 4

요컨대, 내 프로그램은 stdin에서 양의 정수를 읽고이 사다리를 출력에 인쇄합니다. 가장 적은 수의 고유 문자로 그렇게하려고합니다.가능한 합니다.

내 프로그램은 다음과 같습니다.

#include<iostream>

int i;
int ii;
int iii;
int iiii;

main() {
    std::cin >> i;
    for(ii++; ii <= i; ii++) {
        int iii = iiii;
        for(iii++; iii <= ii; iii++) {
            std::cout << iii << " ";
        }
        std::cout << std::endl;
    }
}

내 프로그램에서 고유 문자 수를 확인하는 데 사용한 체커는 다음과 같습니다.

#include <cstdio>
#include <cstring>
using namespace std;
int check[300],diffcnt=0,cnt=0,t;
char c;
double score;
int main(){

    memset(check,0,sizeof(check));
    FILE *in=fopen("ans.cpp","r");
    while(fscanf(in,"%c",&c)!=EOF){
        cnt++;
        if(!check[c]){
            check[c]=1;
            if(c=='\r'||c=='\n') continue;
            diffcnt++;
        }
    }
    if(diffcnt<25) printf("100\n");
    else if(diffcnt<30){
        printf("%.3lf\n",20.0*100.0/cnt+20.0*(29-diffcnt));
    }
    else{
        score=20.0;
        for(int x=95;x<cnt;x++) score*=0.9;
        printf("%.3lf\n",score);
    }
    printf("Unique Characters: %d\n", diffcnt);
    printf("Total Characters: %d\n", cnt);
    return 0;
}

가급적 적게 사용하고 싶습니다이 프로그램을 완성하기 위해 25 개 고유 문자 (개행 문자는 제외하지만 공백 포함). 현재 내 프로그램은 27을 사용합니다. 더 최적화하는 방법을 모르겠습니다.

누군가 고유 한 문자 수와 관련하여 더 최적화하는 방법에 대해 조언 해 주시겠습니까? C ++ 만 사용할 수 있습니다.


5
code-golf 이외의 다른 채점 기준에 관한 을 요청하는 것은 확실히 신기 하지만, 페이지는 주제 에 맞는 프로그래밍 문제에 대한 더 나은 답변을 제공하기 때문에 주제에 관한 것 입니다.
Adám

8
@LuisMendo 많은 언어가이 스코어링 체계를 완전히 일반화하기 때문에이 경우에는 이것이 사실이라고 생각하지 않습니다. 이 사용자가 "고유 한 골프"를 배우는 데 도움이 필요하면 언어의 하위 집합에서만 의미가 있기 때문에 이것이 일반적인 도전보다 팁으로 훨씬 낫다고 생각합니다. 그것은 누군가가 그것을 게시하고 싶다면 기본 문제가 도전이 될 수 있다고 말했다.
FryAmTheEggman

3
중괄호 대신 <% 및 %> 그래프를 사용할 수 있다고 생각합니다.
내 대명사 monicareinstate입니다

2
나는 확실히 일부를 놓쳤다. #은 % :이므로 세 문자를 제거하고 한 문자 ({=> <%,} => %>, # => % :)를 입력하고 25에 도달 할 수 있습니다. 이것을 아래의 답변과 결합하면 당신이 24를 얻을 수 있다고 생각합니다.
내 대명사는 monicareinstate

2
@LanceHAOH Trigraphs는 [언더 나이트 (underhanded)] 질문에서 매우 일반적이며, trigraph에 대해 읽을 때 digraph도 나타납니다.
내 대명사는 monicareinstate

답변:


12

나는 코드에서 = 문자를 제거했다고 생각하지만, 지금은 상당히 느립니다.

#include<iostream>

int i;
int ii;
int iii;
int iiii;

int main() {
    std::cin >> i;
    i++;
    for(ii++; ii < i;) {
    for(;iii>iiii;iii++);
    for(;iii<iiii;iii++);
    ii++;
        for(iii++; iii < ii; iii++) {
            std::cout << iii << " ";
        }
        std::cout << std::endl;
    }
}

꽤 좋지는 않지만 정수 오버플로를 없애면 =를 사용하지 않고 0으로 돌아갈 수 있습니다.

또한 우리는 경비원을 조금 바꿔야했습니다. 불행히도 포함으로 인해 모든 줄 바꿈 문자를 제거 할 수 없었으므로 다음과 같은 조사 방법이 될 수 있습니다.

편집 : 지금은 시간이 부족하지만 strstream 및 기타 다양한 라이브러리를 포함하고 사용하는 경우 정수를 사용하여 공간을위한 올바른 문자에 도달하고 다시 문자를 전달할 수 있습니다. strstream


2
당신은 #include<std>모든 :s를 제거 할 수 있습니다. 훌륭한 코딩 방법은 아니지만 요점입니다.
Darrel Hoffman

3
@DarrelHoffman 나는 그것을 작동시킬 수 없다, 당신은 using namespace std;추가 p를 사용 하기 위해 할 필요가 없다 : so net 0
Expired Data

흠. 어쩌면 내 C ++은 약간 녹슨 것입니다. 또한 g그로 인해 순 손실 이 추가 됩니다. 이 코드를 금한다면, 우리는 이름을 변경하여 바이트 수를 줄일 수 ii, iii그리고 iiii다른 한 글자 이름을 (다른 이미 사용하는 문자를 선택),하지만 그건 내가 알아 맞추기 때문에이 문제가, 무슨에 관하여 아니다. 이 사용하는 어떤 이익이 될 것이다 경우 궁금하네요 getcputc대신 cin/ cout, 그것을 시도해야합니다.
Darrel Hoffman

1
내 잘못이야. 나는 방금 체커를 다시 읽었다. 줄 바꿈 문자가 무시 된 것 같습니다. 따라서 실제로 줄 바꿈 제거에 대해 신경 쓸 필요가 없습니다. 그러나 의견에 @someone의 전략 및 솔루션과 결합하여 24 자로 만들었습니다. int 대신 short를 사용하여 프로그램을 더 빠르게 만들었습니다. 그래서 추가 'h'문자를 얻었습니다. 그러나 추가 비용없이 char 데이터 유형을 사용할 수 있습니다. 문자 코드를 사용하여 "문자도 제거했습니다.
LanceHAOH

@LanceHAOH : 부호있는 정수 오버플로는를 포함하여 모든 부호있는 유형에 대해 C ++에서 정의되지 않은 동작입니다 signed char. 최적화가 활성화 된 상태에서 컴파일하는 경우 gcc -fwrapv부호있는 오버플로를 2의 보수 랩으로 정의하는 데 사용하지 않는 한이 코드는 최신 컴파일러에서 중단 될 수 있습니다 . clang도 지원합니다 -fwrapv. ( ISO C ++에서 잘 정의 된 동작 (랩 어라운드)을 unsigned포함한 정수 유형 unsigned char). 그것은 ABI에 따라 달라집니다 여부 char입니다 signed char또는 unsigned char이렇게, char확인 할 수 있습니다.
Peter Cordes

10

@ExpiredData와 @someone의 답변을 결합하여 24 개의 고유 한 문자를 얻었습니다. 또한 int 대신 짧은 데이터 형식을 사용하면 짧은 데이터 형식을 오버플로하는 데 더 짧은 시간이 걸리기 때문에 프로그램 속도가 빨라졌습니다.

내 코드는 다음과 같습니다.

%:include<iostream>

short i;
short ii;
short iii;
short iiii;
char iiiii;

main() <%
    std::cin >> i;
    iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;
    iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;
    iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;
    iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;iiiii++;
    i++;
    for(ii++; ii < i; ii++) <%
        for(;iii;iii++);
        for(iii++; iii < ii; iii++)
            std::cout << iii << iiiii;
        std::cout << iii << std::endl;
    %>
%>

@KevinCruijssen 그는 char iiiii;변수 초기화의 마지막 인 에서 그것을 사용합니다 .
Rɪᴋᴇʀ

1
@KevinCruijssen 사실입니다. 그러나 문자 코드를 사용하여 공백 문자를 표현할 수 있기 때문에 "문자를 제거 할 수 있습니다. 따라서 고유 문자의
순차는

9

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;내부. 우수함, 그것은 컴파일하고 제대로 작동, 하지만 우리는 사용했다 ph을 위해 operator char(), 우리가 피할 적어도 1의 순 손실을 b멤버 함수를 만들기 위해 public사용하여 struct대신 class. (그리고 protected도움 이 되는 경우 상속을 무시할 수 있습니다 ).


@JohanduToit : cout.fill()fromstd::ios 과 함께하는 것이 좋지만 이전에는 사용하지 않았습니다 . . 포인터를 가져 와서 ->fill()멤버 함수를 사용하여 어떻게 든 호출 할 수 있습니까? 어떤 포인터 cout또는 다른 스트림에 대한 포인터를 반환합니까 ?
Peter Cordes

죄송 << (bitand std::cout)->fill()하지만 컴파일하지만 사용합니다 -. (토큰 이름에도 불구하고 비트 단위 및 연산자가 아닌 bitand어휘와 동일합니다 &. 또한 연산자 주소로도 작동합니다.) 흠, 멤버 함수에 대한 포인터를 가져올 수있는 템플릿 또는 람다 항목이 있습니까? 우리가 할 수있는 것을 ()사용하지 않고 .->?
Peter Cordes

1
내가 찾은 유일한 다른 것은 std::ios::leftgcc에서 32로 정의되었지만 실제로 그것을 활용할 수있는 방법을 알 수는 없습니다. 나는이 일 명을 놓아 일부 실제 작업이 :-) 할 얻을 것 같네요
요한 뒤 투아을

@JohanduToit : int32를 만드는 것은 문제가되지 않습니다. 제 대답은 이미 0 ++에서 시작 하여 그렇게하는 방법을 보여줍니다 int c{};. 그러나 네, 람다, 템플릿 또는을 들여다 보는 토끼 구멍을 쓰지 않을 것 std::function입니다. 또는 std::string아이디어. 그러나 우리는 g실제로 std::string패배하지 않고 선언 할 수는 없습니다 . goto대신에 사용하려는 아이디어가 for사라지지 않았습니다. decltype(something)우리에게 char유형을 줄 수는 있지만 비용이 듭니다 y.
Peter Cordes

1
opeator에는 char 대신 auto를 사용할 수 struct ss : std::ostream { operator auto () { return fill(); } };있지만 많은 도움이되지 않습니다.
Johan du Toit

7

C ++ (gcc) x86_64 Linux 전용, 9295 8900 8712 6812 5590 바이트, 18 개의 고유 문자

int m[]={111111111111111+1111111111111+1111111111111+1111111111111+1111111111111+1111111111111+1111111111111+111111111+111111111+1111111+111111+11111+11111+11+11+11+11+11+1+1+1,11111111111+11111111111+11111111111+1111111111+111111111+111111111+111111111+111111+1111+1111+111+111+111+111+11+11+11+11+11+11+11+11+11+1+1+1,111111111111111+111111111111111+111111111111+111111111111+1111111111+1111111+1111111+11111+11111+11111+1111+111+111+11+11+11+11+11+11+11+11+11+1+1+1+1+1+1+1+1+1+1,111111111111111+111111111111111+1111111111111+1111111111111+11111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+11111+1111+111+111+11+1+1+1,1111111111111+1111111111111+11111111111+11111111111+1111111111+1111111111+1111111111+111111+11111+11111+11111+11111+1111+1111+1111+1111+111+111+111+11+11+11+11+11+11,11111111111111+1111111111111+11111111111+11111111111+11111111111+1111111111+111111111+11111111+11111111+11111111+11111111+1111+1111+1111+1111+1111+1111+1111+1111+1111+111+1+1+1+1,111111111111111+1111111111111+1111111111111+1111111111111+1111111111111+11111111111+11111111111+1111111+11111+11111+1111+1111+11+11+11+11+11+11+11+1+1+1+1,111111111111+11111111111+1111111111+1111111111+1111111111+1111111111+1111111111+1111111111+11111111+11111+11111+11111+11111+11111+11111+1+1,111111111111111+11111111111111+11111111111+11111111111+1111111111+1111111+1111111+11111+111+111+111+111+111+111+111+111+11+11+1+1+1+1+1+1,11111111111+1111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+11+1+1+1+1+1+1+1,111111111111+11111111111+11111111111+11111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+111+111+111+111+111+111+111+1+1+1+1+1+1+1,11==1,1111111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+11+11+11+1+1+1,1111111111111+111111111111+11111111111+1111111111+111111111+111111111+11111111+111111+111111+111111+11111+1111+111+111+1+1,111111111111+111111111111+11111111111+11111111111+11111111111+11111111111+111111111+111111111+11111111+111111+1111+1111+111+111+111,111111111111+11111111111+1111111111+1111111111+111111111+1111111+111+111+1+1+1+1,111111111111111+11111111111111+1111111111111+1111111111111+111111111111+1111111111+1111111111+1111111111+1111111+111111+111111+111111+11111+11111+11111+1111+1111+111+11+11+1+1+1+1,111111111111111+1111111111111+1111111111111+11111111111+1111111111+11111111+11111111+1111+1111+1111+111+111+111+111+11+11,111111111+111111111+11111111+11111111+11111111+1111111+1111111+111111+11111+1111+1111+1111+1111+111+111+11+11+11+11+11+1+1+1+1+1+1+1+1,11111111111111+111111111111+111111111111+11111111111+111111111+111111+111111+111111+1111+1111+1111+1+1+1+1+1+1+1+1,11111111111+11111111111+11111111111+11111111111+1111111111+1111111111+11111111+1111111+1111111+1111111+1111111+111111+11111+11+11+11+1+1+1+1+1+1+1+1,111111111111111+111111111111111+111111111111+1111111111+1111111111+11111111+11111111+1111111+1111111+111111+111111+11111+11111+111+11+11+1+1+1+1+1+1+1+1+1+1,11111111111111+11111111111111+111111111111+11111111111+11111111111+1111111+1111111+1111111+1111111+1111111+1111111+11+11+11+11+11+11+11+11+1,11111111111111+11111111111111+11111111111+1111111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+11111+11111+1111+1111+1111+111+111+111+111+111+111+11,111111111111111+1111111111111+111111111111+111111111111+111111111111+11111111111+1111111111+1111111111+111111111+111111+111111+111111+111111+1111+11+1+1,111111111111111+11111111111111+111111111111+111111111111+1111111111+1111111111+111111111+11111111+1111+1111+1111+111+111+111+111+111+11+11+11+11+11+11+11+11+1+1+1+1,11111111111111+11111111111111+11111111111111+11111111111+11111111111+1111111111+11111111+1111111+11111+11111+11111+1111+111+111+111+11+11+11+11+1+1+1+1+1+1,111111111111111+11111111111111+1111111111+111111111+111111111+111111111+11111111+1111111+111111+11111+1111+1111+1111+111+111+111+111+111+111+11+11+11+11+11+11+11+11+11+1+1+1+1,111111111111111+1111111111111+1111111111111+1111111111111+1111111111+111111111+111111111+111111111+11111111+1111111+11111+1111+1111+1111+111+111+111+11,1111111111111+1111111111+11111111+11111111+11111111+11111+1111+111+111+11+11+11+11+11+11+11+11+11+1+1+1+1+1+1+1+1+1+1,11111111111111+1111111111+1111111111+111111111+11111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+1111+1111+1111+111+111+11+11+11+11+11+11+11+1+1+1+1+1+1+1,11111111111111+1111111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+11111+1111+1111+111+111+111+111+111+111+1+1+1+1+1+1,111111111111111+1111111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+111111+11111+11111+11111+1111+111+111+111+11+11+11+11+11,1111111111+111111111+1111111+1111111+111111+111111+11111+11111+11111+11111+11111+11111+1111+1111+1111+11+11+11+11+11+11+11+11+11+1+1+1,111111111111111+111111111111+111111111111+111111111111+11111111111+1111111111+1111111111+1111111111+11111111+11111+1111+1111+111+111+111+111+111+111+111+111+1,1111111111+111111111+111111111+11111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+111+111+111+11+11+11+1,11111111111111+11111111111111+1111111111+1111111111+1111111111+1111111111+11111111+11111111+11111111+11111111+1111111+1111111+111+111+111+111+11+11+11+11+11+11+11+1+1,111111111111+11111111111+1111111111+111111111+111111111+111111+111111+111111+111111+11111+11111+11+11+11+11+11+1,111111111+11111+11111+111+11+1+1+1+1+1+1+1+1+1};main(){((int(*)())m)();}

온라인으로 사용해보십시오!

이것은 이 PPCG 답변의 아이디어를 기반으로 합니다. 기계어 프로그램은 32 비트 int의 배열로 표현되며 각각은 합으로 표시됩니다 1+11+111.... 그것은 인코딩을보다 효율적으로 할 수 있음을 밝혀 x으로 y같은 것을 y%(1<<32)==x. 인코딩 된 기계 언어 프로그램은 다음과 같습니다

0x0000000000000000:  55                         push    rbp
0x0000000000000001:  31 ED                      xor     ebp, ebp
0x0000000000000003:  53                         push    rbx
0x0000000000000004:  48 83 EC 18                sub     rsp, 0x18
0x0000000000000008:  48 8D 74 24 0C             lea     rsi, [rsp + 0xc]
0x000000000000000d:  31 C0                      xor     eax, eax
0x000000000000000f:  31 FF                      xor     edi, edi
0x0000000000000011:  6A 01                      push    1
0x0000000000000013:  5A                         pop     rdx
0x0000000000000014:  0F 05                      syscall 
0x0000000000000016:  89 C3                      mov     ebx, eax
0x0000000000000018:  85 C0                      test    eax, eax
0x000000000000001a:  74 0C                      je      0x28
0x000000000000001c:  6B ED 0A                   imul    ebp, ebp, 0xa
0x000000000000001f:  03 6C 24 0C                add     ebp, dword ptr [rsp + 0xc]
0x0000000000000023:  83 ED 30                   sub     ebp, 0x30
0x0000000000000026:  EB E0                      jmp     8
0x0000000000000028:  C7 44 24 0C 00 00 00 00    mov     dword ptr [rsp + 0xc], 0
0x0000000000000030:  FF C3                      inc     ebx
0x0000000000000032:  8B 44 24 0C                mov     eax, dword ptr [rsp + 0xc]
0x0000000000000036:  8D 78 01                   lea     edi, [rax + 1]
0x0000000000000039:  89 7C 24 0C                mov     dword ptr [rsp + 0xc], edi
0x000000000000003d:  E8 27 00 00 00             call    0x69
0x0000000000000042:  6A 20                      push    0x20
0x0000000000000044:  48 89 E6                   mov     rsi, rsp
0x0000000000000047:  52                         push    rdx
0x0000000000000048:  58                         pop     rax
0x0000000000000049:  50                         push    rax
0x000000000000004a:  5F                         pop     rdi
0x000000000000004b:  0F 05                      syscall 
0x000000000000004d:  5E                         pop     rsi
0x000000000000004e:  39 5C 24 0C                cmp     dword ptr [rsp + 0xc], ebx
0x0000000000000052:  7C DE                      jl      0x32
0x0000000000000054:  6A 0A                      push    0xa
0x0000000000000056:  48 89 E6                   mov     rsi, rsp
0x0000000000000059:  52                         push    rdx
0x000000000000005a:  58                         pop     rax
0x000000000000005b:  0F 05                      syscall 
0x000000000000005d:  5E                         pop     rsi
0x000000000000005e:  39 DD                      cmp     ebp, ebx
0x0000000000000060:  7F C6                      jg      0x28
0x0000000000000062:  48 83 C4 18                add     rsp, 0x18
0x0000000000000066:  5B                         pop     rbx
0x0000000000000067:  5D                         pop     rbp
0x0000000000000068:  C3                         ret     
0x0000000000000069:  85 FF                      test    edi, edi
0x000000000000006b:  74 2C                      je      0x99
0x000000000000006d:  89 F8                      mov     eax, edi
0x000000000000006f:  6A 0A                      push    0xa
0x0000000000000071:  59                         pop     rcx
0x0000000000000072:  48 83 EC 18                sub     rsp, 0x18
0x0000000000000076:  99                         cdq     
0x0000000000000077:  F7 F9                      idiv    ecx
0x0000000000000079:  89 C7                      mov     edi, eax
0x000000000000007b:  8D 42 30                   lea     eax, [rdx + 0x30]
0x000000000000007e:  89 44 24 0C                mov     dword ptr [rsp + 0xc], eax
0x0000000000000082:  E8 E2 FF FF FF             call    0x69
0x0000000000000087:  48 8D 74 24 0C             lea     rsi, [rsp + 0xc]
0x000000000000008c:  6A 01                      push    1
0x000000000000008e:  58                         pop     rax
0x000000000000008f:  50                         push    rax
0x0000000000000090:  5F                         pop     rdi
0x0000000000000091:  50                         push    rax
0x0000000000000092:  5A                         pop     rdx
0x0000000000000093:  0F 05                      syscall 
0x0000000000000095:  48 83 C4 18                add     rsp, 0x18
0x0000000000000099:  C3                         ret

... 다음 C 코드를 기반으로합니다.

void print(int x){
  if( x ) {
    int y=x%10+'0';
    print(x/10);
    write(1,&y,1);
  }
}
void f() {
  int i=0,j=0,k;
  for( ;read(0,&k,1);i=i*10+k-'0' );
  do {
    for( j++,k=0; print( ++k ), write(1," ",1), k<j; );
    write(1,"\n",1);
  } while(j<i );
}

편집 : 이제 stdin대신 입력을 수락합니다 argv[1]. @ASCII 전용 및 @PeterCordes에게 감사의 말을 전합니다!

Edit4 : 인코딩이 약간 향상되었습니다.


-w플래그 pls : P (또한 이름 ii을 바꿀 수 있음 a)
ASCII 전용

gcc -zexecstack이거 필요해 ? 때문에이 int m[]아니다 const. (그리고 최근 툴체인은 .rodata실행 불가능한 페이지에 배치되었으므로 8.2.1 20181127 및 (GNU Binutils) 2.31.1을 사용하는 const int m[]Arch Linux 시스템에서는 작동하지 않습니다 .) 어쨌든 대답에서 그러나 그것은 당신의 TIO 링크에 있습니다. gccld
Peter Cordes

OP의 고유 카운트 스코어링 알고리즘 인 BTW는 공간과 줄 바꿈을 계산하지 않으므로 전체 내용을 읽기가 끔찍하게 만들 필요는 없습니다 .P
Peter Cordes

당신은 복사하여 기계 코드 바이트를 저장할 수 1push %rax/ pop %rdi대신 다른 푸시 즉시의. 또는 간단히 말해서 64 비트가 아닌 값, 즉 포인터가 아닌 2 바이트의 값 mov %eax, %edi입니다. 또한 Linux syscall는 명령이 작동 rax하는 방식의 일부로 RIP 및 RFLAGS가 저장된 반환 값과 RCX + R11 만으로 입력 레지스터를 삭제하지 않습니다 syscall. 당신은 떠날 수 있도록 rdi하고 rdx설정 1통화를 통해, 다른 REGS를 사용합니다. 또한 RBX는 통화 보존되어 있으므로 클로버 메인의 RBX에 실제로 저장되지는 ​​않습니다. CRT 시작 코드가 중요하지 않기 때문에 작동합니다.
Peter Cordes

6

고유 한 문자 21 개 + 제거 할 수없는 줄 바꿈 1 개

%:include<iostream>
int(n)(int(i))<%
    if(--i)if(n(i))<%%>
    if(i)if(std::cout<<i<<std::addressof(std::cout)->fill())<%%>
%>
int(l)(int(i))<%
    if(n(-(--i)))<%%>
%>
int(m)(int(i))<%
    if(--i)if(m(i))<%%>
    if(i)if(l(-i))<%%>
    if(i)if(std::cout<<std::endl)<%%>
%>
int(c)(int(i))<%
    if(m(-(--i)))<%%>
%>
int(main)(int(i))<%
    if(std::cin>>i)<%%>
    if(c(-i))<%%>
%>

첫 줄 바꿈을 제외하고 공백은 필요하지 않습니다. g ++ 7.3.0에서 컴파일되었습니다.

사용 된 문자 : %:include<ostram>()f-.

다른 답변 개선 :

  1. for루프를 if재귀 로 변경 하여 세미콜론을 제거했습니다 .
  2. std::addressof(std::cout)->fill()일명으로 공간 문자를 얻었습니다 std::cout.fill().

std :: addressof, 좋은!
Johan du Toit

2

21 공백을 제외한 20 개의 고유 한 문자

모든 공백은 개행으로 변경 될 수 있습니다.

%:include<iostream>
%:include<list>
int n;
const int co<%%>;
const int ci<%not co%>;
const int cmu<%-ci-ci-ci-ci%>;
const char ctd<%-cmu-cmu-cmu-cmu-cmu-cmu-cmu-cmu%>;
const int cia<%-ctd-ctd-ctd-ctd-ctd-cmu%>;
const int ciu<%cia- -ci- -ci%>;

struct<%struct<%struct<%struct<%struct<%struct<%struct<%
int c<:ctd-ci:>;
%>d<:ctd:>;int c<:ctd-ci:>;%>d<:ctd:>;int c<:ctd-ci:>;
%>d<:ctd:>;int c<:ctd-ci:>;%>d<:ctd:>;int c<:ctd-ci:>;
%>d<:ctd:>;int c<:ctd-ci:>;%>d<:-cmu:>;int c<:-ci-cmu:>;
%>e<:co:><:ctd:><:ctd:><:ctd:><:ctd:><:ctd:><:ctd:>;

int i<:co:>;
auto ia<%e%>;
auto iu<%e%>;
int l<%std::cin>>n and co%>;

struct s<%
    int c<%std::cout<<i<:ciu:>- --i<:cia:><<ctd and n%>;
%>;
struct o<%
    int c<%--ia and n%>;
%>;
struct t<%
    std::list<s>c<%- --l%>;
    std::list<o>r<%-l%>;
    int m<%std::cout<<std::endl and n%>;
%>;
std::list<t>a<%n%>;
int main;

segfault로 종료합니다. 사용 된 문자 : %:include<ostram>;-h.

64 비트 Linux 의이 특정 컴파일러 버전에서 작동합니다.

g++-5 (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010

매개 변수를 사용하여 :

-std=c++17

그럼에도 불구하고 그것이 항상 효과가 있을지 확신하지 못합니다. 그것은 또한 다른 많은 것들에 달려 있습니다. ciaciu(4) 사이에서 분할 된 메모리 오프셋이다 ia iu하고 i. ( int이 버전에서는 32 비트입니다.) 실제 오프셋과 일치하도록 숫자를 변경해야 할 수도 있습니다. 주소가 모두 구조체에 포함되어 있으면 주소를 훨씬 더 예측할 수 있습니다. 불행히도 비 정적 auto은 구조체에서 허용되지 않습니다.

e크기는 (2 32 -1) × 2 32 바이트 인 요소 유형의 0 요소 배열입니다 . 대응하는 포인터 유형 e이 감소하면 포인터의 상위 절반이 (2 32 -1) 씩 감소하며 이는 1 씩 증가하는 것과 같습니다. 이것은 등호를 사용하지 않고 감소 된 카운터를 재설정 할 수 있습니다.

보다 안정적으로 작동하지만 하나 이상의 문자를 사용하는보다 합리적인 버전입니다 =.

%:include<iostream>
%:include<list>
int n;
int ci<%not n%>;
int cmu<%-ci-ci-ci-ci%>;
char ctd<%-cmu-cmu-cmu-cmu-cmu-cmu-cmu-cmu%>;
int i;
int l<%std::cin>>n and n-n%>;

struct s<%
    int c<%std::cout<<- --i<<ctd and n%>;
%>;
struct t<%
    std::list<s>c<%- --l%>;
    int r<%i=n-n%>;
    int m<%std::cout<<std::endl and n%>;
%>;
std::list<t>a<%n%>;
int main;

main더 이상 임의의 유형으로 정의 할 수 없기 때문에 최신 버전의 g ++에서는 작동하지 않습니다.

이 두 프로그램은 괄호를 사용하지 않습니다. 그러나 세미콜론은 피할 수없는 것 같습니다.


1

공백을 제외한 22 개의 고유 문자. 숫자를 Windows에서 올바르게 표시되는 NUL 문자로 구분합니다.

%:include<iostream>
int main(int n)<%
    std::cin>>n;
    for(int r<%%>;r++<n;)<%
        for(int i<%%>;i<r;)
            std::cout<<++i<<std::ends;
        std::cout<<std::endl;
    %>
%>

온라인으로 사용해보십시오

히스토그램 :

[%] 0x25 = 9
[:] 0x3A = 11
[)] 0x29 = 3
[i] 0x69 = 11
[n] 0x6E = 12
[c] 0x63 = 4
[l] 0x6C = 2
[u] 0x75 = 3
[d] 0x64 = 8
[e] 0x65 = 4
[<] 0x3C = 13
[o] 0x6F = 5
[s] 0x73 = 7
[t] 0x74 = 12
[r] 0x72 = 6
[a] 0x61 = 2
[m] 0x6D = 2
[>] 0x3E = 7
[(] 0x28 = 3
[;] 0x3B = 7
[f] 0x66 = 2
[+] 0x2B = 4
Unique Characters: 22
Total Characters: 189

std :: ends는 char(0)공백이 아닌 NUL 문자 ( )입니다 ( char(32)ASCII / UTF-8). en.cppreference.com/w/cpp/io/manip/ends . 나는 그것을 확인하기 위해 Linux 데스크톱에서 시도했지만 출력은 1234아닌 것처럼 보입니다 1 2 3 4. TIO 출력에서도 동일하게 보입니다!
Peter Cordes

@PeterCordes, OP는 숫자를 분리하는 방법을 지정하지 않습니다 ;-)
Johan du Toit

당신은 정말 그들에 문자 낭비 것 같아 "위해 " "그들이 사용했을 수있는 경우 iiii와 분리 '0'를 들어 10203040? 프로그램의 바이너리 출력에 여전히 구분 기호가있는 경우를 만들 수 있지만 드롭 인 교체가 아니기 때문에이 변경 사항을 지적하고 영어로 설명하는 것이 대답에 중요합니다! 설명하고 정당화하기 위해 답변을 확장하면 내 downvote를 제거하게되어 기쁩니다.
Peter Cordes

1
@PeterCordes, 점을 찍었다.
Johan du Toit 8
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.