범용 (규칙 굽힘) 코드 골프 솔버


14

코드 골프는 항상 도전자들이 당연한 것으로 생각했거나 생각하지 않았고 규칙에 나열하지 않은 제약 조건을 위반하여 규칙을 다소 구부리는 몇 가지 답변을 포함합니다. 이 흥미로운 허점 중 하나는 더 나은 결과를 얻기 위해 요구하는 것보다 더 많은 결과를 출력 할 수 있다는 것입니다.

이것을 극단적으로 가져 가면 원하는 출력을 인쇄하는 범용 코드 골프 솔버를 작성할 수 있습니다.

우리가 출력 할 필요가있는 것은 가능한 모든 서브 시퀀스를 포함하도록 보장 된 시퀀스입니다. 이 코드 골프의 경우 Ehrenfeucht-Mycielski 시퀀스가됩니다 .

시퀀스는 3 비트 (010)로 시작하고; 각 연속 숫자는 시퀀스 내에서 더 일찍 나타나는 시퀀스의 가장 긴 접미사를 찾고 해당 접미사의 가장 최근에 나온 비트를 보완하여 형성됩니다.

비트의 모든 유한 하위 시퀀스는 시퀀스 내에서 연속적으로, 종종 빈번하게 발생합니다.

시퀀스의 처음 몇 자리는 다음과 같습니다.

010011010111000100001111 ... ( OEIS의 순서 A038219 ).

시퀀스의 8 비트를 바이트로 결합하면 화면 또는 파일로 출력 할 수 있고 가능한 모든 유한 출력 을 포함하는 ASCII 출력을 얻게 됩니다. 이 프로그램은 pi의 일부, "Never will give up"의 가사 , 멋진 ASCII 아트, 자체 소스 코드 및 출력 할 수있는 모든 것을 출력합니다.

정확성을 테스트하기 위해 시퀀스의 처음 256 바이트에 대한 해시가 있습니다.

MD5: 5dc589a06e5ca0cd9280a364a456d7a4
SHA-1: 657722ceef206ad22881ceba370d32c0960e267f

16 진 표기법으로 된 시퀀스의 처음 8 바이트는 다음과 같습니다.

4D 71 0F 65 27 46 0B 7C

규칙 :


그 순서에서 앞서 나온 010의 가장 긴 접미사는 0입니다. 그리고 가장 최근의 초기 모습은 두 번째 0입니다. 지금까지는 두 번째 0 뒤에 아무것도 없으므로 보완 할 수있는 것은 없습니다. 나는 영어를 모국어로 사용하지 않습니다. 어쩌면 방금 틀 렸습니다. wikipedia 기사는 동일한 단어를 사용하지만 더 긴 시퀀스를 가지므로 "가장 최근에있는 ... 추종자가 있습니다"라고 이름을 지정합니다.
사용자 알 수 없음

8
Pedantic quibble : pi는 절대 나타나지 않습니다. 모든 유한 문자열 만 출력에 포함됩니다.
키이스 랜달

다른 질문이 있습니다 : 반복이 겹칠 수 있습니까? 예를 들어 111, (1 [1) 1]?
사용자 알 수 없음

@ KeithRandall : 나는 '당신을 포기하지 않을 것'과 비슷한 종류의 프로덕션을 포함하지 않는 시퀀스를 선호합니다.
사용자가 알 수 없음

2
무한한 문자열의 지정되지 않은 위치에 포함 된 "응답"의 존재는 물론 해당 답변을 "출력하는"것으로 간주 될 수 없습니다. 또한,이 특정 서열은 분리형 서열 의 한 예일뿐입니다 . 이와 같은 수많은 서열이 있습니다.
res

답변:


7

C, –110 자

이 버전의 프로그램은 선형 런타임 알고리즘을 사용하여 시퀀스를 생성합니다. 프로그램에서 402 문자에서 512를 빼면 총 음수가 110이됩니다.

#define C v=calloc(7,8),v->p=p
#define G(F,K)u->F[d[K]]
#define S(F,T)G(f,T)=F,G(t,T)=T,G(n,T)=
struct{int p,f[2],t[2];void*n[2];}r,*u,*v,*w;char*d,c;p,b,h,i,j,k;
main(s){for(;d=++p-s?d:realloc(d,s*=2);){d[i=p]=b;c+=c+b;p%8||putchar(c);
for(u=&r;b=u->p,u->p=p,w=G(n,k=i);S(i,k)v=G(n,k),u=v)for(h=G(f,k),j=G(t,k);j>h;--i,--j)
if(d[i]-d[j]){S(i,k)C;u=v;S(h,j)w;S(0,i)C;b=w->p;goto x;}S(0,i)C;x:b=1-d[b+1];}}

문제에 따라 프로그램은 무한 루프로 실행되므로 많은 메모리 할당이 필요 realloc()하며 시퀀스를 연속적으로 유지하는 데 사용하면 힙 조각화가 발생할 수 있습니다. calloc(7,8)첫 줄을 로 바꾸면 프로그램의 메모리 사용량을 향상시킬 수 있습니다 calloc(1,sizeof*v). 이것은 특히 32 비트 시스템에서 도움이 될 것입니다. 56 비트는 2 배가 될 수 있습니다.

코드는 읽을 수없고 재미있는 방식이 아닙니다. 그 점에 대해 사과드립니다. 솔직히 말하면, ungolfed 버전조차도 너무 명확하지 않습니다.

#include <stdio.h>
#include <stdlib.h>

typedef struct branch branch;
typedef struct node node;

struct branch {
    int from, to;
    node *next;
};

struct node {
    int pos;
    branch br[2];
};

static node root = { 0 };

static unsigned char *data = NULL;
static int endpos = 0;
static int size = 1;

static node *mknode(void)
{
    node *n;

    n = calloc(1, sizeof *n);
    n->pos = endpos;
    return n;
}

static branch *getbranch(node *n, int p)
{
    return &n->br[data[p]];
}

static void setbranch(node *n, int from, int to, node *next)
{
    n->br[data[to]].next = next;
    n->br[data[to]].from = from;
    n->br[data[to]].to = to;
}

int main(void)
{
    node *u, *v, *w;
    int follower, from, i, i0, j;
    int out, b;

    out = b = 0;
    for (;;) {
        ++endpos;
        if (endpos == size) {
            size *= 2;
            data = realloc(data, size);
        }
        data[endpos] = b;
        out = (out << 1) | b;
        if (endpos % 8 == 0) {
            putchar(out);
            out = 0;
        }

        i = endpos;
        u = &root;
        for (;;) {
            follower = u->pos + 1;
            u->pos = endpos;
            w = getbranch(u, i)->next;
            if (!w)
                break;
            i0 = i;
            from = getbranch(u, i0)->from;
            for (j = getbranch(u, i0)->to ; j > from ; --j) {
                if (data[i] != data[j]) {
                    /* divide branch */
                    v = mknode();
                    setbranch(u, i, i0, v);
                    u = v;
                    setbranch(u, from, j, w);
                    setbranch(u, 0, i, mknode());
                    follower = w->pos + 1;
                    goto bitfound;
                }
                --i;
            }
            v = getbranch(u, i0)->next;
            setbranch(u, i, i0, v);
            u = v;
        }
        /* extend branch */
        setbranch(u, 0, i, mknode());

      bitfound:
        b = 1 - data[follower];
    }
}

(위의 ungolfed 코드는 문제 설명 및 Soltys 홈페이지 에서 참조한 Grzegorz Herman 및 Michael Soltys가 작성한 코드를 기반으로합니다 .)

초기 버전의 버그를보고 해 주신 @schnaader 및 @res에게 감사드립니다.


좋은! 그것이 내가 -512 보너스로 바랐던 것입니다.
schnaader 2016 년

이것이 왜 시스템에 의해 충돌을 일으키는 지 아십니까? 골프화되고 골프화되지 않고 malloc수정 된 모든 버전은 약 10000 바이트 후에 출력을 중지하고 메모리 할당을 유지 prog > out.dat하며 ~ 700KB 메모리 사용으로 즉각적인 충돌을 일으 킵니다 . printf("\n%i\n", size);after를 삽입 realloc하면 가장 큰 출력은 4입니다. 체제 : Windows 7 교수 64 비트, 4기가바이트 RAM, GCC 4.6.1
schnaader

(+1) Ubuntu12.04 / gcc를 사용하면 두 프로그램 모두 올바른 출력을 컴파일하고 생성합니다 ... Win7 / mingw / gcc를 사용하면 두 프로그램 모두 컴파일되지만 세그먼테이션 오류가 발생합니다 ... Win7 / lcc를 사용하면 ungolfed 버전은 작동하지만 골프 버전은 세그먼테이션 오류를 생성합니다.
res

1
초기화되지 않은 데이터를 사용하는 것 같습니다. 충분합니다-Windows 컴퓨터에 액세스 할 수 없지만 valgrind가 문제를 보여줍니다. 원래 참조 구현 에서이 버그를 재현 한 것 같습니다. 다행히도 쉽게 고칠 수 있습니다. 보고 해 주셔서 감사합니다!
breadbox

좋아, 지금은 매력처럼 작동합니다.
schnaader

6

루비 109 104 101 94 문자

s=?0
loop{s=(s[/(.*).*\1/][/.#{$1}/]<?1??1:?0)+s
s.size&7<1&&$><<[s.reverse.to_i(2)].pack(?C)}

접미사 검색을 위해 정규 표현식을 사용하여 Ruby로 구현합니다. 메모리가 부족할 때까지 시간이 오래 걸리기 때문에 사용자가 프로그램을 종료해야합니다.

편집 : 방금 sequence로 시작하기에 충분하다는 것을 알았습니다 0.

편집 2 : res의 제안은 2 문자를 저장합니다. 일부 바이트를 잘라낼 필요가 없기 때문에 일부는 다른 문자를 저장 pack합니다.


를 사용 s=(s[/(.*).*\1/][/.#{$1}/]<?1??1:?0)+s하면 다른 두 문자가 저장됩니다.
res

@res 이것은 실제로 작동합니다. 감사합니다.
Howard

괄호를 없앨 수 있습니까 ?C?
기금 모니카의 소송

4

펄, 95 자

나는 실제로 이것의 중간 정도의 버전을 처음에 가지고있었습니다. 골프를 타면서 각 버전이 느려졌습니다. 점점 느려집니다.

$|=$_="010";
y///c%8||print pack"B*",/(.{8})$/while/(.+)$(?(?{m|.*$^N(.)|})(?{$_.=1-$^N})|(?!))/

처음 세 문자 ($|= )는 필요하지 않습니다. 엄밀히 말하면 ...이 없으면 출력이 표시되기 전에 스크립트가 전체 4096 바이트 생성을 완료 할 때까지 기다려야합니다. 그리고 그것은 몇 시간이 걸릴 것입니다. 아마 몇 세기; 잘 모르겠습니다. 이 프로그램의 성능이 시간이 지남에 따라 저하된다고 언급 했습니까? 그래서 그 때문에 나는 그들을 계수에 포함시켜야한다고 느꼈습니다.

다른 한편으로,이 스크립트에는 내가 만든 것 중 가장 추악한 정규식 중 하나가 포함되어있어 자랑 스럽습니다.


1
성능에 대해 걱정하지 마십시오. 알고리즘은 최적화없이 O (N ^ 3)입니다. 필자가 작성한 간단한 Delphi 프로그램은 256 바이트의 경우 약 30 초가 걸리지 만 1024 바이트의 경우 약 1 시간이 걸리므로 4096 바이트가 하루 또는 며칠이 걸리는 것으로 가정합니다. 물론, 정규식과 공간의 최적화는 더 :) 만들 가능성이
schnaader

초기 Perl 스크립트는 256 바이트에 10 초가 걸렸습니다. 이 버전은 90 초가 걸립니다. (또는 선형 감속으로 보이지 않습니다.)
breadbox
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.