Evrensel (kural bükme) Kodu Golf çözücü


14

Kod golf, her zaman meydan okuyanların verdiği ya da sadece düşünmediği ve kuralları listelemediği kısıtlamaları kırarak kuralları aşağı yukarı büken bazı cevaplar içerir. Bu ilginç boşluklardan biri , meydan okumanın daha iyi bir sonuç almasını istediğinden daha fazla çıktı alma olasılığıdır .

Bunu uç noktalara götürürsek, istenen çıktıyı yazdıran evrensel bir kod çözücü yazabiliriz - eğer yaşlanacağını ve daha önce ve sonra çok sayıda başka şey çıkarabileceğini umursamıyorsanız.

Çıktı almamız gereken tek şey, olası her alt diziyi içereceği garanti edilen bir dizidir. Bu kod golf için, Ehrenfeucht-Mycielski dizisi olacak :

Dizi üç bit 010 ile başlar; her ardışık basamak, sekansta daha erken görünen sekansın en uzun son ekini bularak ve bu son ekin en son önceki görünümünün ardından biti tamamlayarak oluşturulur.

Her sonlu bit dizisi bitişik, sonsuz sıklıkla dizide gerçekleşir

Dizinin ilk birkaç basamağı:

010011010111000100001111 ... ( OEIS'de A038219 dizisi ).

Sekansın 8 bitini bir bayta birleştirerek, ekrana veya bir dosyaya verebileceğimiz ve olası her sonlu çıkışı içeren ASCII çıktısını alırız . Program, pi'nin bölümlerini, “Asla pes etmeyeceğim ” sözlerini , bazı güzel ASCII sanatını, kendi kaynak kodunu ve çıktısını almak isteyebileceğiniz her şeyi çıktılar.

Doğruluğu test etmek için, dizinin ilk 256 baytının karmaları şunlardır:

MD5: 5dc589a06e5ca0cd9280a364a456d7a4
SHA-1: 657722ceef206ad22881ceba370d32c0960e267f

Onaltılık gösterimde dizinin ilk 8 baytı şunlardır:

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

Kurallar:

  • Programınız, 8 biti bir bayt / ASCII karakteriyle birleştirerek Ehrenfeucht-Mycielski dizisini (başka bir şey değil) çıkarmalıdır.

  • En kısa program (karakter sayısı) kazanır. Diziyi üretilen bayt başına doğrusal sürede oluşturmayı başarırsanız, karakter sayınızdan 512 çıkarın .


010'da bu sırada daha önce görünen en uzun son ek 0'dır, değil mi? Ve en son önceki görünüm sadece ikinci 0'dır. Ve şimdiye kadar hiçbir şey ikinci 0'ı takip etmiyor, bu yüzden tamamlayıcı oluşturabileceğimiz hiçbir şey yok. Ben anadili İngilizce değilim - belki de yanlış anladım. Vikipedi makalesi aynı kelimeleri kullanıyor, ancak daha uzun bir diziye sahip, bu yüzden "en son ... bir takipçisi var" olarak adlandırır.
kullanıcı bilinmiyor

8
Pedantik kelime oyunu: pi asla görünmez - çıktıda sadece her sonlu dize bulunur.
Keith Randall

Başka bir sorum daha var: Tekrarlama çakışabilir mi? Örneğin 111, (1 [1) 1] 'de?
kullanıcı bilinmiyor

@KeithRandall: 'Asla pes etmeyeceğim' ve benzer türdeki üretimleri içermediği garanti edilen bir diziyi tercih ederim.
kullanıcı bilinmiyor

2
Sonsuz bir dizgide belirtilmemiş bir yere gömülü bir “cevap” ın varlığının, elbette bu cevabı “çıktılamak” olarak kabul edilemeyeceğinden bahsetmek gerekir. Ayrıca, bu özel dizi, ayrık bir dizinin sadece bir örneğidir - bunun gibi sonsuz sayıda dizi vardır.
res

Yanıtlar:


7

C, –110 karakter

Programın bu sürümü diziyi oluşturmak için doğrusal çalışma zamanı algoritmasını kullanır. Programdaki 402 karakterden 512 çıkarılması toplam negatif 110 verir.

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

Probleme göre, program sonsuz bellek döngüsünde çalışır, bu da çok fazla bellek tahsisi gerektirir realloc()ve diziyi bitişik tutmak için kullanmak yığın parçalanmasına katkıda bulunabilir. calloc(7,8)İlk satırda yerini alarak programın bellek kullanımını artırabilirsiniz calloc(1,sizeof*v). Bu, özellikle 56'nın iki kat fazla büyük olduğu 32 bit bir makinede yardımcı olacaktır.

Kod bir tür okunamaz ve ilginç bir şekilde değil; bunun için özür dilerim. Açıkçası, çözülmemiş versiyon bile çok net değil:

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

(Yukarıdaki çözümsüz kod, Grzegorz Herman ve Michael Soltys tarafından sorun tanımında ve Soltys'in ana sayfasından yazılan koda dayanmaktadır .)

İlk sürümdeki bir hatayı bildirdikleri için @schnaader ve @res'e teşekkürler.


Güzel! -512 bonusu ile bunu umuyordum.
schnaader

Bunun sistem tarafından çökmesine neden olduğu hakkında bir fikriniz var mı? Tüm golf mallocedilmiş , golf edilmemiş ve değiştirilmiş sürümler yaklaşık 10000 bayt sonra çıkışı durdurur ve bellek ayırmaya devam eder, prog > out.datsadece ~ 700 KB bellek kullanımı ile anında bir çökme sağlar. Ben eklerseniz printf("\n%i\n", size);sonra realloc, en büyük çıkış olduğunu 4. Sistem: Windows 7 Prof. 64-Bit, 4 GB RAM, GCC 4.6.1
schnaader

(+1) Ubuntu12.04 / gcc ile her iki programınızın da doğru çıktıyı derlediğini ve ürettiğini görüyorum ... Win7 / mingw / gcc ile her iki program da derleme yapıyor ancak segmentasyon hataları üretiyor ... Win7 / lcc ile ungolfed sürümü çalışır, ancak golfed sürümü segmentasyon hataları üretir.
res

1
Bana başlatılmamış verilerin kullanılması gibi geliyor. Tabii ki - Bir Windows makinesine erişimim yok, ancak valgrind sorunu gösteriyor. Görünüşe göre bu hatayı orijinal referans uygulamasından da çoğalttım. Neyse ki kolay bir düzeltme; bildirdiğiniz için teşekkürler!
ekmek kutusu

Harika, şimdi bir cazibe gibi çalışıyor.
schnaader

6

Yakut, 109 104 101 94 karakter

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

Son ek araması için düzenli ifadeler kullanarak Ruby'de uygulama. Bellek yetersiz kalması oldukça uzun sürdüğü için programın kullanıcı tarafından sonlandırılması gerekir.

Düzenleme: Ben sadece dizisi ile başlamak için yeterli olduğunu fark ettim 0.

Edit 2: Res teklifi 2 karakter kaydeder, bazıları ise daha önce tek bir bayt kesmek zorunda olmadığımız için pack.


Kullanıldığında s=(s[/(.*).*\1/][/.#{$1}/]<?1??1:?0)+siki karakter daha kaydedilir.
res

@res Bu gerçekten işe yarıyor. Teşekkür ederim.
Howard

Parantezlerden kurtulabilir misin ?C?
Monica'nın Davası

4

Perl, 95 karakter

Aslında ilk başta bunun iyi bir sürümü vardı. Sonra golf yaparken her versiyon yavaşladı. Giderek daha yavaş.

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

İlk üç karakter ( $|=) gerekli değildir, kesinlikle konuşursak ... ama bu olmadan, komut dosyasının çıktıyı görmeden önce tam 4096 bayt üretmesini beklemeniz gerekir. Ve bu saatler alacaktı. Belki yüzyıllar; Emin değilim. Bu programın performansının zamanla kötüleştiğinden bahsetmiş miydim? Bu yüzden onları saymaya dahil etmek zorunda hissettim.

Öte yandan, bu senaryoda şimdiye kadar oluşturduğum en çirkin regexes biri var, bu yüzden onunla gurur duyuyorum.


1
Performans hakkında endişelenmeyin, algoritma optimizasyon olmadan O (N ^ 3). Yazdığım basit Delphi programım 256 bayt için 30 saniye, 1024 bayt için yaklaşık bir saat sürdü, bu yüzden 4096 baytın bir veya birkaç gün süreceğini varsayıyorum. Tabii ki, RegEx ve alan optimizasyonları daha da kötüleştirme potansiyeline sahip :)
schnaader

İlk Perl betiğim 256 bayt için 10 saniye sürdü. Bu sürüm 90 saniye sürüyor. (Ayrıca doğrusal bir yavaşlama gibi görünmüyor.)
breadbox
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.