Bộ giải mã phổ quát (uốn cong quy tắc)


14

Code golf luôn bao gồm một số câu trả lời bẻ cong các quy tắc ít nhiều bằng cách phá vỡ các ràng buộc mà những người thách đấu đã chấp nhận hoặc chỉ không nghĩ đến và không liệt kê trong các quy tắc. Một trong những lỗ hổng thú vị này là khả năng xuất ra nhiều hơn thách thức yêu cầu để có được kết quả tốt hơn.

Lấy điều này đến mức cực đoan, chúng ta có thể viết một bộ giải golf mã phổ quát in ra đầu ra mong muốn - nếu bạn không quan tâm rằng nó có thể mất nhiều thời gian và xuất ra nhiều thứ khác trước và sau nó.

Tất cả những gì chúng ta cần là đầu ra là một chuỗi được đảm bảo để chứa mọi chuỗi con có thể. Đối với mã golf này, đây sẽ là chuỗi Ehrenfeucht-Mycielski :

Chuỗi bắt đầu với ba bit 010; mỗi chữ số liên tiếp được hình thành bằng cách tìm hậu tố dài nhất của chuỗi cũng xuất hiện sớm hơn trong chuỗi và bổ sung bit theo sau sự xuất hiện gần đây nhất của hậu tố đó.

Mỗi chuỗi bit hữu hạn xảy ra liên tục, vô cùng thường xuyên trong chuỗi

Một vài chữ số đầu tiên của chuỗi là:

010011010111000100001111 ... (trình tự A038219 trong OEIS ).

Kết hợp 8 bit của chuỗi thành một byte, chúng ta sẽ nhận được đầu ra ASCII mà chúng ta có thể xuất ra màn hình hoặc vào một tệp và có chứa mọi đầu ra hữu hạn có thể . Chương trình sẽ xuất ra các phần của pi, lời bài hát của Sẽ không bao giờ cung cấp cho bạn , một số nghệ thuật ASCII hay, mã nguồn riêng và mọi thứ khác bạn có thể muốn nó xuất ra.

Để kiểm tra tính chính xác, đây là giá trị băm cho 256 byte đầu tiên của chuỗi:

MD5: 5dc589a06e5ca0cd9280a364a456d7a4
SHA-1: 657722ceef206ad22881ceba370d32c0960e267f

8 byte đầu tiên của chuỗi trong ký hiệu thập lục phân là:

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

Quy tắc:


Hậu tố dài nhất trong 010 xuất hiện trước đó trong chuỗi đó là 0, phải không? Và sự xuất hiện gần đây nhất chỉ là lần thứ hai 0. Và cho đến bây giờ, không có gì sau 0 thứ hai, vì vậy không có gì chúng ta có thể xây dựng một bổ sung trên. Tôi không phải là người nói tiếng Anh bản địa - có lẽ tôi đã hiểu sai. Bài viết trên wikipedia sử dụng cùng một từ, nhưng có trình tự dài hơn nên tôi sẽ đặt tên cho nó là "gần đây nhất ... có người theo dõi".
người dùng không xác định

8
Phân biệt phạm vi: pi sẽ không bao giờ xuất hiện - chỉ mỗi chuỗi hữu hạn sẽ được chứa trong đầu ra.
Keith Randall

Tôi có một câu hỏi khác: Có thể lặp lại chồng chéo? Ví dụ trong 111, (1 [1) 1]?
người dùng không xác định

@KeithRandall: Tôi thích một chuỗi được đảm bảo không chứa 'Không bao giờ từ bỏ bạn' và các sản phẩm cùng loại.
người dùng không xác định

2
Điều đáng nói là tất nhiên sự hiện diện của một "câu trả lời" được nhúng tại một vị trí không xác định trong một chuỗi vô hạn có thể được coi là "xuất ra" câu trả lời đó, tất nhiên. Ngoài ra, trình tự cụ thể này chỉ là một ví dụ về trình tự rời rạc - có vô số trình tự như thế này.
res

Câu trả lời:


7

C, kho110 chars

Phiên bản này của chương trình sử dụng thuật toán thời gian chạy tuyến tính để tạo chuỗi. Trừ 512 từ ký tự 402 trong chương trình cho tổng số 110 âm.

#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];}}

Theo vấn đề, chương trình chạy trong một vòng lặp vô hạn, đòi hỏi nhiều phân bổ bộ nhớ và sử dụng realloc()để giữ cho chuỗi liên tục có thể góp phần phân mảnh heap. Bạn có thể cải thiện việc sử dụng bộ nhớ của chương trình bằng cách thay thế calloc(7,8)trên dòng đầu tiên bằng calloc(1,sizeof*v). Điều này sẽ giúp đặc biệt là trên máy 32 bit, trong đó 56 có thể quá lớn theo hệ số hai.

Mã này là loại không thể đọc được, và không phải là một cách thú vị; cho rằng tôi xin lỗi. Thành thật mà nói, ngay cả phiên bản không có bản quyền cũng không rõ ràng khủng khiếp:

#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];
    }
}

(Mã không được mã hóa ở trên dựa trên mã được viết bởi Grzegorz Herman và Michael Soltys, như được tham chiếu trong mô tả vấn đề và từ trang chủ của Soltys .)

Cảm ơn @schnaader và @res đã báo cáo lỗi trong phiên bản ban đầu.


Đẹp! Đó là những gì tôi hy vọng với phần thưởng -512.
schnaader

Bất kỳ ý tưởng tại sao điều này gây ra sự cố trên hệ thống? Tất cả các mallocphiên bản được đánh gôn, không được chỉnh sửa và bị sửa đổi đều dừng đầu ra sau khoảng 10000 byte và tiếp tục phân bổ bộ nhớ, gây prog > out.datra sự cố tức thì chỉ với mức sử dụng bộ nhớ ~ 700 KB. Nếu tôi chèn printf("\n%i\n", size);sau realloc, đầu ra lớn nhất là 4. Hệ thống: Windows 7 GS 64-bit, RAM 4 GB, GCC 4.6.1
schnaader

(+1) Tôi thấy rằng với Ubuntu12.04 / gcc, cả hai chương trình của bạn đều biên dịch và tạo đầu ra chính xác ... Với Win7 / mingw / gcc, cả hai chương trình đều biên dịch nhưng tạo ra lỗi phân đoạn ... Với Win7 / lcc, phiên bản không có tác dụng, nhưng phiên bản golf tạo ra lỗi phân đoạn.
res

1
Nghe có vẻ như sử dụng dữ liệu chưa được khởi tạo với tôi. Chắc chắn - tôi không có quyền truy cập vào máy Windows, nhưng valgrind cho thấy vấn đề. Có vẻ như tôi đã sao chép lỗi này từ việc triển khai tham chiếu ban đầu. May mắn thay, đó là một sửa chữa dễ dàng; cảm ơn vì đã báo cáo nó
hộp bánh mì

Tuyệt, làm việc như một bùa mê bây giờ.
schnaader

6

Ruby, 109 104 101 94 ký tự

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

Triển khai trong Ruby bằng cách sử dụng các biểu thức thông thường cho tìm kiếm hậu tố. Vì phải mất khá nhiều thời gian cho đến khi hết bộ nhớ, chương trình phải bị chấm dứt bởi người dùng.

Chỉnh sửa: Tôi chỉ nhận thấy rằng nó là đủ để bắt đầu với chuỗi 0.

Chỉnh sửa 2: Đề xuất độ phân giải lưu 2 ký tự, một số ký tự khác vì chúng ta không phải cắt bỏ một byte trước đó pack.


Sử dụng s=(s[/(.*).*\1/][/.#{$1}/]<?1??1:?0)+ssẽ lưu hai ký tự khác.
res

@res Điều này thực sự hoạt động. Cảm ơn bạn.
Howard

Bạn có thể thoát khỏi dấu ngoặc đơn xung quanh ?C?
Vụ kiện của Quỹ Monica

4

Perl, 95 ký tự

Tôi thực sự đã có một phiên bản nửa chừng của điều này lúc đầu. Sau đó, khi tôi chơi golf, mỗi phiên bản trở nên chậm hơn. Càng ngày càng chậm.

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

Ba ký tự đầu tiên ( $|=) không cần thiết, nói đúng ... nhưng không có ở đó, thông thường bạn phải đợi tập lệnh hoàn thành việc tạo ra 4096 byte đầy đủ trước khi bạn thấy bất kỳ đầu ra nào. Và điều đó sẽ mất nhiều giờ. Có thể hàng thế kỷ; Tôi không chắc. Tôi đã đề cập rằng loại hiệu suất của chương trình này suy giảm theo thời gian? Vì vậy, tôi cảm thấy bị buộc phải đưa chúng vào số đếm.

Mặt khác, kịch bản này có một trong những bối cảnh xấu nhất tôi từng tạo ra, vì vậy tôi nghĩ tôi tự hào về nó.


1
Đừng lo lắng về hiệu suất, thuật toán là O (N ^ 3) mà không tối ưu hóa. Chương trình Delphi đơn giản của tôi, tôi đã viết mất khoảng 30 giây cho 256 byte, nhưng khoảng một giờ cho 1024 byte, vì vậy tôi giả sử 4096 byte phải mất một hoặc vài ngày. Tất nhiên, tối ưu hóa RegEx và không gian có khả năng làm cho nó tồi tệ hơn :)
schnaader

Kịch bản Perl ban đầu của tôi mất 10 giây cho 256 byte. Phiên bản này mất 90 giây. (Nó cũng không có vẻ là một sự chậm lại tuyến tính.)
Breadbox
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.