Turing Completeness için en az (farklı) karakter


107

Özet:

Herhangi bir dil için, Turing-Complete olması için dilinizde en küçük benzersiz karakter sayısı nedir?

Meydan okuma:

Seçtiğiniz herhangi bir dil için, dilinizin Turing-Complete olmasını sağlayan en küçük karakter alt kümesini bulun. Karakter kümenizi istediğiniz kadar tekrar kullanabilirsiniz.


Örnekler:

  • JavaScript: +!()[]( http://www.jsfuck.com )

  • Brainfuck: +<>[](bir sarma hücre büyüklüğü varsayar)

  • Python 2: ()+1cehrx(gibi komut dosyalarından yapılmış exec(chr(1+1+1)+chr(1)))

Puanlama:

Bu zorluk bayt cinsinden değil karakterlerle puanlanır . Örneğin, örnekler için puanlar 6, 5 ve 9'dur.


Notlar:

  • Bu zorluk, diğer dillerden yalnızca sizin Turing-Complete olan dilinizi (dilin her özelliğini kullanmanız gerekmeyebilir) anlamında farklılaşır.

  • Yapabilseniz de, lütfen kullanılan karakterleri azaltmadan cevap göndermeyin. Örnek: 8 karakterli Brainfuck (diğer tüm karakterler varsayılan olarak bir yorum olduğundan).

  • Alt kümenizin Turing-Complete'in neden olduğu konusunda en azından kısa bir açıklama yapmalısınız.


90
Unary , 1 karakter. iç çeker
Dennis,

4
@Dennis İlginç bir sayı teorisi problemi için yerleşik olan Jelly veya 05AB1E'den farklı değildir. Bu zorluk, bir tarpit olarak tasarlanmamış herhangi bir dilde ilginç ve önemsiz bir optimizasyon problemi gibi görünüyor.
Martin Ender

7
@MartinEnder Java veya C gibi dillerde cevapları görmek isterim
Julian Lachniet

9
Lütfen, çözümün dilin her geçerli karakteri olduğu esolanglarda göndermeyin. İlginç değil ya da zekice değil.
Pavel,

20
@Pavel İlginç değil ya da zekâsı, uyarılmaması gerektiği, ancak kesinlikle yayınlanmaması gerektiği anlamına gelebilir.
Dennis,

Yanıtlar:


77

Haskell, 4 karakter

()=;

İle ()=biz, S, K ve I. ya ayrılmalıdır tanımlar tanımlayabilmektedir ;veya NL.

(==)S olarak tanımlıyoruz (ikinci satır daha okunaklı bir sürüm gösteriyor):

((=====)==(======))(=======)=(=====)(=======)((======)(=======))
( a     == b      ) c       = a      c       ( b       c       )

(===) Sor:

(=====)===(======)=(=====)
 a     === b      = a

ve (====)ben:

(====)(=====)=(=====)
(====) a     = a 

Neyse ki (==), (===), (====)vb geçerli fonksiyon / parametre isimleridir.

@ Ais523'ün işaret ettiği gibi, SKI Haskell gibi güçlü bir şekilde yazılmış bir dilde yeterli değil, bu yüzden bir fixpoint birleştirici eklememiz gerekiyor (=====):

(=====)(======)=(======)((=====)(======))
(=====) f      = f      ((=====) f      )

17
Bu inşaat doğrudan çalışmıyor; SKI, Haskell gibi güçlü bir şekilde yazılmış bir dille tamamlanmıyor. Ancak, ben tanımlamak için aynı tekniği kullanabilirsiniz inanıyoruz fixve KAYAK + fix olduğunu bile kesinlikle yazılı dilde, Turing tamamlandı.

Demek her tanımın başında bu tanımları ön eklediniz?
PyRulez

@PyRulez: evet. Varsayılan ayarlarımıza göre, verilen karakter seti ile işlevler yapmanın yeterli olduğunu kabul ediyorum - tam bir program gerekli değildir.
nimi

1
Muhtemelen yenisiyle değiştirmelisin (==)ki varsayılan eşitlik operatörü ile çatışmasın
gururlu haskeller

@ proudhaskeller: evet, aslında programlamak istiyorsanız, yeniden adlandırmanız daha iyi olur (==), ancak yukarıdaki kod sadece bir tamamlamanın kanıtıdır.
nimi

61

JavaScript (ES6), 5 karakter

@ETHproductions ve @ATaco'ya bu konuda yardımcı oldukları için teşekkürler; bu bir grup projesiydi ve orijinal fikir benim olmasına rağmen, ayrıntıların çoğu kendi. Bu JavaScript alt kümesinin burada geliştirildiği sohbet tartışmalarına bakın .

[]+=`

Herhangi bir Javascript programının ( []()+!) karakterleriyle yazılabileceği oldukça iyi anlaşılmıştır , ancak 5 karakter yeterli değildir . Ancak, bu keyfi JavaScript yazma konusunda bir zorluk değildir. Turing-komple bir dil yazma konusunda bir zorluktur ve Turing-tam dillerin DOM'ye veya hatta etkileşimli I / O'lara ihtiyaç duymaması gerektiği gerçeğini kullanmak, gerekli tüm işlevselliğe sahip bir program yazabileceğimizi ortaya koymaktadır. , hatta evalbir eşdeğeri çalıştırma yeteneği olmadan bile .

Temel önyükleme

JavaScript türleri ile çok esnektir. Örneğin, []boş bir dizidir, ancak +[]0'dır ve []+[]boş dizedir. Özellikle, bu karakter kümesi ile 0 üretebildiğimiz gerçeği, parantezlerin gruplama etkisinin simülasyonunu mümkün kılar; (a)olarak yazılabilir [a][+[]]. Bu tür bir numarayı yalnızca +[]aşağıdakileri kullanarak çeşitli karakterler üretmek için kullanabiliriz :

  • [][+[]]olduğu undefined(boş bir dizi ilk elemanı olmak üzere); yani
  • []+[][+[]]olduğu "undefined"(arasında stringification undefined); yani
  • [[]+[][+[]]]edilir ["undefined"](bir dizi bu sarma); yani
  • [[]+[][+[]]][+[]]bir "undefined"(ilk eleman); yani
  • [[]+[][+[]]][+[]][+[]]olduğu "u"(ilk harf).

uoluşturması en kolay karakterlerden biridir, ancak benzer teknikler bir dizi başka karakter oluşturmamızı sağlar. Daha önce olduğu gibi aynı bağlantı bize erişilebilen aşağıdaki karakter listesini verir +[](bu, gruplama / öncelik dışında bir amaç için parantez kullanan tek yapıdır çünkü +[]()hariç , aynı listedir ,):

0123456789acdefinotuvyIN (){}.

Bu karakter kümesinden çok fazla yararlı kelime heceleyemiyoruz (bunun karakter dizisi olarak üretebileceğimiz karakter dizisi olduğunu unutmayın ; bunları bir tür olmadan yürütemeziz eval). Bu nedenle başka bir karaktere ihtiyacımız var. Kullanacağız =, çünkü daha sonra işe yarayacak, ancak şimdilik karşılaştırma operatörünü hecelemek için kullanacağız ==. Bu bizi üretmesine olanak sağlayan falseve truedizgelenmiş ve içine endeksli ve hemen bize ekleyelim edilebilen, lrsbiz dizeleri içine içerebilir karakter.

Şimdiye kadar, bunun daha önce yapamadığımız, hecelememize izin verdiği en önemli kelime constructor. Şimdi, JavaScript'in şuna benzeyen bir özellik erişimi sözdizimi var:

object.property

ancak bu şekilde de yazabilirsiniz:

object["property"]

ve hiçbir şey bir dize değişmezi yerine hesaplanmış bir özellik kullanmamızı engellemiyor. Böylece hatları boyunca bir şeyler yapabiliriz.

object["c"+"o"+"n"+"s"+"t"+"r"+"u"+"c"+"t"+"o"+"r"]

(yukarıda açıklandığı gibi oluşturulan harflerle; kod çok uzun sürüyor!); bu, eşdeğer object.constructornesnelerin yapıcılarına erişmemize izin veren eşdeğerdir .

Bununla yapabileceğimiz birkaç numara var. Günlükten fantastikliğe:

  • Bir nesnenin yapıcısı bir fonksiyondur. Özellikle, bir adı vardır ve bu ad, fonksiyonun dizilişinin bir parçasıdır. Örneğin, [[]+[]][+[]]["constructor"]yapıcıya, adı String olan bir dize için yapmayı başarabiliriz ve sonra başkent Skarakterini elde etmek için onu dizeleyebiliriz . Bu, alfabemizi biraz genişletir ve daha sonra bazı yeni karakterlere ihtiyacımız olacak.
  • Tüm diziler aynı kurucuya sahiptir; []["constructor"] == []["constructor"]olduğu true(aksine [] == []yanlış olan). Bu küçük görünebilir, ancak çok önemlidir, çünkü bize değerleri kalıcı bir şekilde saklama yöntemi verir; yapıcı üzerinde rastgele bir özellik ayarlayabilir ve daha sonra tekrar okuyabiliriz. (Bu, =özellikle üretme trueve oluşturma yollarından biri yerine, özellikle kullanmamızın nedenlerinden biridir false.) Örneğin, değerlendirebiliriz [[]["constructor"]["a"]=[]]ve daha sonra []["constructor"]["a"]orada sakladığımız diziyi okuyup geri alabiliriz.

    Bu , Turing-eksiksizliği için ihtiyaç duyduğumuz gereksinimlerden birini, rastgele miktarlarda veri saklama ve alma kabiliyetini yerine getirir . Yapıcı-özellik depomuzdan değerler alarak iki elemanlı bir dizi kullanarak bir cons hücre yaratabilir ve daha sonra bellekteki keyfi büyük veri yapıları oluşturmamıza izin vererek bu değerlerden birinin yerine geri saklayabiliriz; ve bu depolamaya, geriye doğru yaparak, istediğimiz verilere erişilinceye kadar parça parça parçalayarak erişebiliriz. Okumak yıkıcıdır, fakat bu kabul edilebilirdir çünkü veri depolamak için birden fazla yerimiz vardır, bu yüzden okudukça kopyalayabiliriz ve sonra kopyayı orijinal konumuna geri koyabiliriz.

  • Bir işlev için []["find"]yapıcıya ulaşmamızı sağlar ( sınırlı alfabemizle erişebileceğimiz çok sayıda işlev vardır; yani Array.find, en kolay erişilebilir, ancak diğerleri vardır). Bu neden faydalı? Aslında, bir yapıcının amacına uygun olarak kullanabiliriz ve işlevleri oluşturabiliriz! Ne yazık ki, karakter setimizle, İşlev yapıcısına hesaplanan bir dizgiyi geçemiyoruz. Bununla birlikte, kullanımı `onu bir değişmez dizgiden geçirir (örn. []["find"]["constructor"]`function body goes here`); Bu, işlev türünün özel değerlerini, yürütüldüğünde, bu davranışı tamamen kullanarak ifade edebildiğimiz sürece herhangi bir davranışla tanımlayabileceğimiz anlamına gelir []+=. Örneğin []["find"]["constructor"]`[]+[]`, boş dizgiyi hesaplayan, atanan ve çıkan oldukça sıkıcı bir işlevdir; ofonksiyon kullanışlı değil, fakat daha karmaşık olanları olacaktır. İşlevlerin parametre alamamasına veya değer döndürememesine rağmen, bir işlevden diğerine iletişim kurmak için yapıcı-özellik depolamasını kullanabildiğimiz için pratikte sorun değildir. Diğer bir kısıtlama ise `, bir fonksiyonun gövdesinde kullanamayacağımızdır .

    Şimdi, özel işlevleri tanımlayabiliriz, ancak bu noktada bizi geride tutan şey, onları çağırmakta zorluk çekiyoruz . Programın en üst düzeyinde bir işlevi çağırabiliriz ``, ancak işlevleri yalnızca en üst düzeyden çağırabilmek herhangi bir döngü yapmamıza izin vermez. Aksine, birbirimizi arayabilmek için fonksiyonlara ihtiyacımız var.

    Bunu oldukça şık bir numara ile başardık. SDaha önce ürettiğimiz sermayeyi hatırlıyor musunuz? Bu bize hecelememizi sağlıyor "toString". Bunu aramayacağız; şeyleri []bunlara ekleyerek dizgelere dönüştürebiliriz . Aksine, biz onu değiştireceğiz . Yapıcı depolamayı, etrafta kalan kalıcı dizileri tanımlamak için kullanabiliriz. Ardından yarattığımız fonksiyonları dizilerin toStringyöntemlerine atayabiliriz ve bu atamalar da yapışır. Şimdi, tek yapmamız gereken +[]dizideki basit bir şey ve aniden özel tanımlı fonksiyonumuz çalışacak. Bu, karakterleri kullanabileceğimiz anlamına gelir.+=[]işlevleri çağırmak ve dolayısıyla işlevlerimiz birbirlerini - veya kendilerini arayabilir. Bu bize tekrar veriyor, bu da bize döngüler veriyor ve birdenbire Turing-eksiksizliği için ihtiyacımız olan her şeye sahibiz.

İşte Turing'in bütünlüğünü ve nasıl uygulandığını gösteren bir dizi özelliğin özeti:

  • Sınırsız depolama : yapıcı deposunda iç içe geçmiş diziler
  • Kontrol akışı : kullanarak ifve özyinelemeyle uygulandı :
    • if: bir boole bir sayıya dönüştürülür ve bir 2 eleman dizisine indekslenir; Bir eleman thenstringized olduğunda case işlevini çalıştırır, diğer eleman elsestringized olduğunda case işlevini çalıştırır.
    • Özyineleme : yapıcı deposunun uygun bir öğesini stringify
  • Komut sıralaması : [a]+[b]+[c]değerlendirir a, bve csoldan sağa (en azından ben kontrol tarayıcısında)

Ne yazık ki, bu oldukça pratik değildir; dizgilerin ilk prensiplere göre karakter karakterli olarak yapılması gerektiğine göre, sadece büyük değil, aynı zamanda G / Ç ( Turing-complete olması gerekli değildir) yapmanın da bir yolu yoktur . Ancak, sonlandırırsa, en azından yapıcı deposuna daha sonra manuel olarak bakmak mümkündür, bu nedenle programlarınızda hata ayıklamak mümkün değildir ve bunlar tamamen iletişimsel değildir.


16
Bu adlandırılmamışsa J5h * t'yi öneririm.
Hesap MakinesiFeline

1
İyi bir örnek program ne olurdu? Asal sınav mı? Selam Dünya?
Hesap MakinesiFeline

3
Benim, bu böyledir wat iyi korku filmi gibi lezzetli cevap, ....
saat

4
Angular1'in toString()bağımlılık enjeksiyonunda kullanımının, işlevi kullanmanın en yaratıcı yolu olduğunu düşündüm . Şimdi fikrimi değiştirdim.
Sunny Pun

1

55

Unary , 1 karakter

0

Karakter seçimi gerçekten önemli değil; Programın uzunluğu, transpiles yaptığı beyin tıkanma programını tanımlar. Teknik 0özellikler karakterleri zorunlu kılarken, çoğu alıcı bunu kontrol ediyor gibi görünmüyor.


44
Muhtemelen teknik özellikleri doğrulayan alıcılarla sorunları açmalıyız, bu çok ciddi bir konudur.
Kaptan Man

5
Şaşırdım Şaka olup olmadığını anlamak için 20 dakikaya ihtiyacım vardı.
Peter A. Schneider

3
@ PeterA.Schneider Bazı googling, birisinin aslında teoride teoriye göre bir ipi uyguladığını görecektir, ancak sonuçta elde edilen 0 dizesi muhtemelen herhangi bir pratik bağlamda gördüğüm en büyük sayıdır ve asla gerçek bir makinede uygulanamamıştır.
Darren Ringer

12
Bu sıfır dizisi aslında herhangi bir bağlamda gördüğüm en küçük sayıdır.
Matthew

1
LOL, tamam, tek sembolünüzü ek bir kimlik olarak tanımlamak gibi saçma bir şey yaparsanız ...: p
Darren Ringer

37

vim, 9 8 7 6 karakter

<C-v><esc>1@ad

İsteğe bağlı bir vimscript programı hazırlayabilir ve çalıştırabiliriz:

  1. aa<C-v><C-v>1<esc>dd@1<esc>ddddBir <C-a>kayıt almak için diziyi kullanın 1.

  2. Ekleme moduna ve aardından abir makroya ekleme moduna tekrar girmek için kullanılacak bir ekleme moduna girin.

  3. İstenilen vimscript programındaki her karakter için,

    1. <C-v><C-v>1<esc>değişmez diziyi eklemek için kullanın <C-v>1,

    2. kullanımı @1(ki <C-a><cr>burada son, <cr>artırmak için gerektiği kadar çok kez nedeniyle son satırında olmak için hiç bir operasyon) 1istenen karakterin ASCII değerine ulaşılana kadar,

    3. ve ekleme moduna ile tekrar girin a.

  4. Çizgiyi (takip eden bir yeni satırla birlikte) ile 1kayıt defterine silin <esc>dd.

  5. Sonucu vim tuş vuruşlarını kullanarak @1, ardından <esc>ddsondaki yeni satırın girdiği satırı önceki adımdan silmek için kullanın.

  6. Elde edilen rastgele bayt dizisini ile çalıştırın dd@1. Eğer a ile başlıyorsa :, vimscript kodu olarak yorumlanacak ve izleyen yeni satırdan dolayı çalıştırılacaktır dd.

Bunun minimal bir karakter kümesi olduğuna ikna olmadım, ama Turing'in tamamlandığını kanıtlamak oldukça kolay.


2
Eğer yapamaz i<C-v>1<ESC>yazmak için <C-a>ve daha sonra ddkullanmak, böylece @1herhangi bir sayı artırma için ve kullanmak zorunda değil neden <C-a>?
İnekler,

4
Vay, bu cevap inanılmaz! 1!
DJMcMayhem

@KritixiLithos Bu, bir miktar yeniden yapılandırma işleminden sonra çalışmaya başlar, teşekkürler!
Doorknob

2
@ mbomb007 Aslında ... ilginç bir uygulama detayından dolayı, <C-v>10\ n (sorma) yerine bir NUL ekler. Her durumda, evet, Turing'in bütünlüğü ile ilgili önemli değil.
Doorknob


33

Perl, 5 karakter

<>^es

Diğer betik dillerinde olduğu gibi, fikir evalisteğe bağlı dizgiler kullanmaktır. Bununla birlikte, karakter kümemiz tırnak işaretleri veya birleştirme operatörleri içermez, bu nedenle rastgele dizeler oluşturmak çok daha karmaşık olacaktır. Bununla eval^"başa çıkmanın daha kolay olacağını, ancak bir karakter daha olduğunu unutmayın.

Ana aracımız, s<^><CODE>eeevrimleşen CODE, daha sonra çıktısını geliştiren şeydir. eBeklenen etkiyle daha fazlası eklenebilir.

Kullanılmadığı <>sürece glob operatörü olan dizeleri kullanıyoruz . İlk karakter olamaz <(aksi takdirde <<operatöre benziyor ), köşeli parantezlerin dengeli olması ve en az bir harf olmayan karakter olması gerekir (aksi halde okuma satırı operatörü olarak yorumlanır).

Bu dizeleri bir araya getirerek, ^B^V^S(*-/9;<>HJMOY[`\^begqstvetrafta bir miktar çöp almayı kabul ettiğimiz sürece (karakterlerin ilk üçü kontrol karakterleridir) herhangi bir karakter kombinasyonunu alabiliriz .

Örneğin, almak istediğimizi varsayalım "v99". Almanın bir yolu v99olduğunu "><<" ^ "e>>" ^ "see" ^ "^^^", ama biz kısıtlamaları nedeniyle bu dizeleri temsil edemez <>. Bunun yerine, biz kullanırız:

<^<<^>><>>^<^^^^^<>>^<^^^^^^e>^<^^^^^^^>^<^^^^^e>^<^^^^e^>^<e^^es>^<^ee^^>^<^<^^^^^>>^<^<>^^^^>^<^^^^^^^e>^<^^^^^^^^>

Değerlendirildiğinde Y9;v99;, elde edilen sonuç bir ova ile aynı sonucu verir v99(yani, ASCII kod 99 ile karakter).

Böylece tüm ^B^V^S(*-/9;<>HJMOY[`\^begqstvkarakter dizisini keyfi dizgemizi oluşturmak için kullanabilir , sonra yukarıdaki gibi dönüştürebilir ve onu s<><CODE>eeeeçalıştırmak için a içine sokabiliriz. Ne yazık ki, bu karakter kümesi birleştirme işlemini gerçekleştirmenin açık bir yolu olmadan hala çok sınırlıdır.

Ama neyse ki, yıldızı içeriyor. Bu *b, dizeye değer veren yazı yazmamızı sağlar "*main::b". Sonra, *b^<^B[MMH^V^SY>(^ B, ^ V ve ^ S değişmez kontrol karakterleridir), bize (6, $&);tekrar değerlendirildiğinde Perl'in eşleşme değişkeninin değerini döndürür $&. Bu bize birleştirme sınırlı bir form kullanmanızı sağlar: Biz defalarca şeyler başa ekleyebilir $_kullanarak s<^><THINGS>eve sonra kullanmak s<\H*><*b^<^B[MMH^V^SY>>eeeeval $_( \Hyatay boşluk başka bir şey eşleşir; bizim charset değil nokta, yerine bu kullanın).

Kullanarak 9-/tüm basamakları kolayca oluşturabiliriz. Rakamlar vve birleştirme kullanarak rasgele karakterler oluşturabiliriz (vXXX karakteri ASCII kod XXX ile verir). Bunları birleştirebiliriz, böylece rastgele dizeler oluşturabiliriz. Görünüşe göre her şeyi yapabiliriz.

Tam bir örnek yazalım. Diyelim ki kendi PID'ini basan bir program istiyoruz. Doğal program ile başlıyoruz:

say$$

Bunu v-notasyona çeviririz:

s<><v115.v97.v121.v36.v36>ee

Bunu yalnızca kullanarak yeniden yazarız ^B^V^S(*-/9;<>HJMOY[`\^begqstv(boşluk sadece okunabilirlik içindir ve çıktıyı etkilemez):

s<^><
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-99/-9-99/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-9/9-9/9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><999/9-9/-9-9/-9-9/-9-9/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<\H*><*b^<^B[MMH^V^SY>>eee;
>eee;

Son olarak, yukarıdaki programı sadece şuna dönüştürürüz <>^es: pastebin . Ne yazık ki, bu Perl'i çökertir Excessively long <> operator, ancak bu sadece teknik bir sınırlamadır ve dikkate alınmamalıdır.

Phew, bu oldukça yolculuktu. Birisinin işleri basitleştiren 5 karakterden oluşan bir grupla karşılaşması gerçekten ilginç olurdu.

EDIT: biraz farklı bir yaklaşım kullanarak, uzunluk sınırını aşmamaktan kaçınabiliriz <>. Tamamen işlevsel brainfuck tercümanı sadece kullanarak <>^es: Çevrimiçi deneyin! . <>^esAktarıcıdan otomatik Perl'e : pastebin .


1
Gördüğüm gibi .. kodlamanız ikinci dereceden bir sonuç alıyor, çünkü karakterleriniz iki gruba ayrılıyor, biri sadece bir çift sayıda temel karakter xor'lar tarafından üretilebiliyor, diğeri ise sadece tek bir sayı tarafından üretilebilen ve sizi zorlayan Aralarında değiştirirken başka bir glob ekleyin. Programı, ^başka karakterlerle ya da diğer karakterlerle bağlanmış kısa değerlendirilebilir parçalara bölme şansınız var mı?
Ørjan Johansen

@ ØrjanJohansen Yep, bunu tespit etmek iyi bir iş. Şu anda bir çözüm üzerinde çalışıyorum.
Grimy

Bu küçültülmüş örneği bir TIO bağlantısı yapabilirsiniz. Çevrimiçi deneyin!
Ørjan Johansen

7
Talep: Bu "biraz farklı bir yaklaşımı"
CalculatorFeline

32

Python 2, 7 karakter

exc="%\n

Herhangi bir Python 2 programı bu 7 karakter kullanılarak kodlanabilir ( \nyeni satırdır).

Keyfi dizge oluşturma

İkame operatörünü tekrar tekrar %tek bir dizgeye uygulayarak birleştirme yapabiliriz . Örneğin, eğer a=1, b=2, c=3, "%d%%d%%%%d" % a % b % cbize dize verecektir "123". Neyse ki, harfler execbize erişim vermek %xve %ctemelde olan hex()ve chr(). İle %ckarakterleri temsil eden gerekli sayılara sahip olduğumuz sürece herhangi bir dize oluşturabiliriz. Daha sonra bu dizgiyi execanahtar kelimeyi kullanarak python kodu olarak çalıştırabiliriz .

Rakam yap

Karşılaştırmalarla ( ) yarasa 0girip 1hemen erişebiliriz ==. Birleştirme basamakları ve modülo kombinasyonuyla, ASCII'de 43temsil edilen sayıyı oluşturmak mümkündür +. Bu, kodumuz için ihtiyaç duyduğumuz sayıları oluşturmamızı sağlar.

Bir araya koyarak

Bu açıklamada, bu kısıtlamalar altındaki programların nasıl yazılabileceğini anlamak için gerekli olmadıklarından, bazı ayrıntıları atladım. Aşağıda, herhangi bir python programını yalnızca bu 7 karakteri kullanan, işlevsel olarak eşdeğer bir sürüme dönüştüren bir Python 2 programı var. Kullanılan teknikler k anarşi golfüne yapılan bu sunumdan ilham almıştır . Bazı basit hileler, oluşturulan programların boyutunu makul sınırlar içinde tutmak için de kullanılır.

import sys

var = {
    43: 'e',
    'prog': 'x', # the program will be stored in this variable
    'template': 'c',
    0: 'ee',
    1: 'ex',
    2: 'ec',
    4: 'xe',
    8: 'xx',
    16: 'xc',
    32: 'ce',
    64: 'cc',
    'data': 'cx', # source program will be encoded here
}

unpacker = 'exec"".join(chr(eval(c))for c in {}.split())'.format(var['data'])

source = sys.stdin.read()
charset = sorted(list(set(source+unpacker)))
codepoints = map(ord, charset)

output = (
    # create template for joining multiple characters
    '{}="%c%%c%%%%c%%%%%%%%c"\n'.format(var['template']) +

    # create 1
    '{0}={1}=={1}\n'.format(var[1], var['template']) +

    # create 0
    '{}={}==""\n'.format(var[0], var['template']) +

    # create 3
    # store it at var[43] temporarily
    (
        'exec"{0}=%x%%x"%{2}%{2}\n' +
        'exec"{0}%%%%%%%%=%x%%x%%%%x"%{1}%{2}%{1}\n'
    ).format(var[43], var[0], var[1]) +

    # create 4
    # this step overwrites the value stored at var[0]
    (
        'exec"{1}=%x%%x"%{0}%{1}\n' +
        'exec"{1}%%%%=%x%%x"%{2}%{0}\n'
    ).format(var[43], var[0], var[1]) +

    # create 43
    'exec"{0}=%x%%x"%{1}%{0}\n'.format(var[43], var[0])
)

# create powers of 2
for i in [2, 4, 8, 16, 32, 64]:
    output += 'exec"{0}={1}%c{1}"%{2}\n'.format(var[i], var[i/2], var[43])

for i, c in enumerate(codepoints):
    # skip if already aliased
    if c in var:
        continue

    # generate a new name for this variable
    var_name = ''
    if i < 27:
        for _ in range(3):
            var_name += 'exc'[i%3]
            i /= 3
    else:
        i -= 27
        for _ in range(4):
            var_name += 'exc'[i%3]
            i /= 3
    var[c] = var_name

    # decompose code point into powers of two
    rem = c
    pows = []
    while rem:
        pows.append(rem&-rem)
        rem -= rem&-rem

    # define this variable
    front = 'exec"{}={}'.format(var[c], var[pows.pop()])
    back = '"'
    for i, p in enumerate(pows):
        front += '%'*(2**i) + 'c' + var[p]
        back += '%' + var[43]
    output += front + back + '\n'

# initialise the unpacker
output += 'exec"""{}=""\n"""\n'.format(var['prog'])
i = 0
length = len(unpacker)
while i < length:
    if (length-i) % 4 == 0:
        # concat 4 characters at a time
        w, x, y, z = [var[ord(unpacker[i+j])] for j in range(4)]
        output += 'exec"{}%c={}%%{}%%{}%%{}%%{}"%{}\n'.format(var['prog'], 
                    var['template'], w, x, y, z, var[43])
        i += 4
    else:
        output += 'exec"""{}%c="%%c"%%{}"""%{}\n'.format(var['prog'],
                    var[ord(unpacker[i])], var[43])
        i += 1

# encode source data
output += var['data'] + '="""'
output += '\n'.join(var[ord(c)] for c in source)
output += '"""\n'

# execute the program
output += 'exec"exec%c{}"%{}'.format(var['prog'], var[32])

print output

Çevrimiçi deneyin


Giriş programının zaten gerekli karakter grubuyla sınırlı olup olmadığını görmek için bazı kontroller ekleyebilirsiniz ve eğer öyleyse, sadece cat.
mbomb007

26

Mathematica, 5 4 karakter

I[]

Bu, bir işleç görevi gören ve adlandırılmamış işlevler için hazır sözcükleri adlandırılmış argümanlarla yazabilmenizi sağlayan , özel kullanımlı bir Unicode karakteridirFunction . Karakter Mathematica'daki gibi gözüküyor , bu yüzden ben bu cevabın geri kalanında netlik için onu kullanacağım.

Bu kullanarak, uygulayabilir S, Kve Icombinators kombinatoriyel mantığı:

I -> II↦II
K -> II↦III↦II
S -> II↦III↦IIII↦II[IIII][III[IIII]]

Bunlarla ilgili bir sözdizimsel sorun, bu birleştiricilere argümanlar iletmeye çalışırsak sorun çıkacak çok düşük önceliğe sahip olmasıdır. Normalde bir birleştiriciyi Cparantez içinde sararak düzeltirsiniz (C), ancak parantezimiz yoktur. Bununla birlikte, daha sonra kullanabileceğimiz kadar yüksek önceliğe sahip başka bir sihir de kullanabilir Ive []sarabiliriz C:

I[C][[I[[]]I]]

Son olarak, bir uygulama yazmak A x y z( Ayukarıda gösterildiği gibi "parenthesised" bir combinator olduğunu ve x, y, zveya parenthesised olabilir veya olmayabilir, ya da daha büyük ifadeler olabilir), biz yazabiliriz:

A[x][y][z]

Bu parantez eşdeğeri gerçekte nasıl çalıştığı sorusunu bırakıyor. Geldiğim sırayla kabaca anlatmaya çalışacağım.

Yani bir şeyi gruplamak için sözdizimsel olarak sahip olduğumuz şey parantezler []. Mathematica'da parantez iki şekilde görünür. İşlev çağrıları f[x]olarak veya bir dizin oluşturma işleci olarak f[[i]](bunun için gerçekten çok kısadır Part[f, i]). Özellikle, bu ne geçerli ne [C]de [[C]]sözdizimi anlamına gelir . Önünde bir şeye ihtiyacımız var. Bu teoride herhangi bir şey olabilir. Eğer biz kullanırsak, Izaten elimizde olabilir I[C]. Bu değerlenmemiş kalır, çünkü Itek bir işlev değildir (hiç bir işlev değildir).

Fakat şimdi Ctekrar açmanın bir yoluna ihtiyacımız var , çünkü aksi halde aslında bir argüman iletmeye çalıştığımızda değerlendirmeye alınmayacak x.

Burası sadece listelerde değil, f[[i]]isteğe bağlı ifadelerde kullanılabilecek kullanışlı bir fyer. fKendisinin formda olduğunu varsayar head[val1,...,valn], sonra f[[0]]verir head, f[[1]]verir val1, f[[-1]]verir valnvb. O yüzden ya almak gerekir 1veya -1ayıklamak Cya çünkü, tekrar I[C][[1]]veya I[C][[-1]]değerlendirir C.

Biz yapabilirsiniz olsun 1keyfi bir tanımsız sembol gibi gelen x, ancak bunu yapmak için, biz bölümü için başka bir karakter gerekiyordu ( x/xverir 1tanımsız için x). Çarpma biz herhangi bir ek karakterler (prensipte) olmadan gerçekleştirebilir tek aritmetik işlemdir, bu yüzden vermek kadar çarpılır bazı değer gerekir -1veya 1. Bu, özellikle Itanımlayıcılarımız için özellikle seçmemin nedeni olarak ortaya çıkıyor . Çünkü Itek başına Mathematica'nın hayali birim için yerleşik sembolüdür.

Fakat bu son bir problemi bırakıyor: aslındaI bizzat kendisiyle nasıl çarpıyoruz ? Sadece yazamayız IIçünkü bu tek bir sembol olarak ayrıştırılır. Bu belirteçleri a) değerini değiştirmeden ayırmalıyız ve b) herhangi bir yeni karakter kullanarak.

Bir büyünün son biti belgelenmemiş bir davranış parçasıdır: f[[]](veya eşdeğerde Part[f]) geçerli sözdizimi ve fkendini döndürür . Yani yerine çarparak Itarafından I, biz çarpın I[[]]tarafından I. Parantezlerin yerleştirilmesi, Mathematica'nın daha sonra yeni bir belirteç aramasına neden olur ve gerektiği şekilde I[[]]Ideğerlendirir -1. Ve işte böyle sonuçlanırız I[C][[I[[]]I]].

Kullanamadığımızı unutmayın I[]. Bu, fonksiyonun tartışmasız bir çağrışımıdır I, ancak daha önce dediğim gibi Ibir fonksiyon değildir, bu yüzden bu değerlenmeden kalacaktır.


Harika cevap
Patrick Stevens,

23

Python 2,8 karakter

exc'%~-0

Bu karakterler, ve format dizelerini kullanarak herhangi bir Python programının çevrilmesine / yürütülmesine izin verir exec. Turing-eksiksizliği için herhangi bir programı çevirebilmek gerekmese de, bu yine de TC'yi yapan en az karakterdir. Çok güçlü olması sadece bir bonus.

Sıfır dışında herhangi bir tek hanenin yanı sıra çift tırnak işareti de kullanılabilir. (Şimdi düşünüyorum da, 1sen kullanabilirsiniz beri kesinlikle daha kısa programlarda sonuçlanan daha iyi olurdu 1, 11ve 111aynı zamanda,.)

İşte program print:

exec'%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c'%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0

Çevrimiçi deneyin

Temel program gerektirir

exec''

xPrograma eklenen her karakter (karakter sayısı) gerektirir:

  • % - 2**(n-1)
  • c - 1
  • - - ord(x)*2
  • ~ - ord(x)*2
  • 0 - 1

Bunun istisnası, kodlanmış programı 48 yerine %'0'karakter kullanmak gibi kısaltmak için belirli optimizasyonların / kısayolların alınabilmesidir .0-~

Pratik kullanımlar (AKA golf): Bu taktiği, ek bir handikap karakteri kullanmadan bu sorunu çözmek için kullandım.

Karakter listesi ve kodlayıcı program için kredi: burada

Sonuçta elde edilen program boyutunda daha düşük bir sınır bulma hakkında bilgi için (optimizasyonlar olmadan) bu yoruma bakın .

Gereken bayt sayısı artar O(2**n), bu nedenle golf oynamak için bu yöntem önerilmez. Bu kaynak kısıtlamasını kullanan bir kıskanç delicesine uzun olacaktır.


Eğer sadece operatör önceliği çalıştırırsa +veya -öncesinde çalışırsa %, bir karakteri kaldırabiliriz.
mbomb007

Her bir Python programını, azaltılmış karakter kümenize çevirebilmenin dikkat çekici olması, Turing'in eksiksiz olması için gerekli değildir. Yine de gerekli kontrol debisini execzaten kullanmadan elde etmenin zor olacağını hayal etsem de.
Martin Ender

Bu gerçekten teknik olarak bir Torna Komple dili bile değil, öyle mi? Tercümanı, gömülü Python tercümanı olan bir Torna Tutma dili için arama kabiliyetine sahiptir. Bu, Turning Complete'in olup olmadığına bakılmaksızın, başka bir tercümana bir kabuk komutu çağırabildiği sürece, herhangi bir dilde işe yarayacaktır.
mmachenry

@ mmachenry Python kendi derleyici ve tercüman kullanıyor. Başka bir dil kullanmıyor. Ve Python'da beyinsel bir tercüman yaratıldı, bu yüzden Turing Complete. Bu bilgiyi kullanarak, tartışmanız yanlıştır.
mbomb007

@ mbomb007 Hayır benim argüman yanlış değil. Python açıkça bir Tornalama Tamamlayıcı dilidir. Hesaplama, iç arama için istediğiniz herhangi bir karakteri kullanarak Python'dan bir Python yorumlayıcısı aranarak yapılır. Programı belirttiğiniz dil, bir programlama dili değil, yalnızca bir kodlamadır. Bunu kullanarak, her programlama dilini kelimenin tam anlamıyla yapmak Turing Complete'i 0 ve 1 karakterlerini kullanarak ve kaynak dosyalarını ikili olarak görüntülemekte önemsizdir. Sorunun ruhu, gerçek dilin sözdizimsel bir alt kümesini bulmaktır.
mmachenry

23

C (taşınabilir), 24 18 13 karakter

aimn[]={};,1+

Bu, formun tüm programlarını kapsar

main[]={<sequence of constants>};

... burada sabitlerin sırası (1 + 1 + 1 ... formunda) programınızın makine kod gösterimini içerir. Bu, ortamınızın tüm bellek bölümlerinin yürütülmesine izin verdiğini varsayar (görünüşe göre tcc [thanks @Dennis!] Ve NX bitsiz bazı makineler için geçerlidir). Aksi halde, Linux ve OSX için anahtar sözcüğü consthazırlamanız gerekebilir ve Windows #pragmaiçin segmenti yürütülebilir olarak açıkça işaretlemek zorunda kalabilirsiniz .

Örnek olarak, yukarıdaki tarzda yazılmış olan aşağıdaki program Hello, World!Linux ve OSX'te x86 ve x86_64'te yazdırır .

main[]={111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+11111+11111+11111+11111+11111+11111+11111+11111+111+11+11+11+11+11+11+1+1,1111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+11111+1111+1111+1111+111+111+111+111+111+111,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+111111+111111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1+1+1,111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+111+11+11+11+11+11+11+11+1,1111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+1111+1111+1111+111+11+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+1+1+1+1+1+1+1,1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1,1111111111+111111111+111111111+111111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+1+1+1+1+1+1,111111+111111+11111+11111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+11+11+11+11+11+11+11+11+11+11,11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+11+11+11+11+11+11+11+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+11+11+11+1,111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+11+11+1+1+1+1+1,11111+11111+11111+11111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+1+1+1+1+1};

Çevrimiçi deneyin!


2
@TR: Sıfırın en az x86 makine kodunda (çok önemli bir talimat değil) kullanılmasından kaçınılması oldukça kolaydır, özellikle de sorun yalnızca üst üste dört sıfır bayt varsa oluşur.

2
@GB 32 bit girişli bir makinede0==1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+11+11+11+11+11+11+11+1
ceilingcat

3
tcc olmadan kaçmanıza izin verir const. tio.run/nexus/…
Dennis,

8
@GB 0 daha kısa bir gösterimi gerçekleştirdim1==11
ceilingcat

3
@ wizzwizz4, her durumda saf C değil, Turing'i tamamlayan hiçbir şekilde değil. Her ne olursa olsun hiçbir C semantiği yoktur. Zaten çalıştırılabilir bir şey almak için derleyici ve yürütme ortamı ayrıntılarına güvendiğinizden, keyfi olarak adlandırılmış bir giriş noktasına izin verebilirsiniz.
John Bollinger

20

Retina , 6 karakter

$%`{¶

Yanı sıra besinler (0x0A).

Bir yandan, bu kadar düşük elde edebildiğime şaşırdım. Öte yandan, dahil edilmesinden çok mutsuzum . Her biri $`{iki hatta üç amaç için tekrar kullanılır, ancak birlikte yalnızca bir amaç için hizmet eder. Bu onların daha israflı görünmesini sağlar ve yaklaşımın şıklığını hafifçe yok eder. Umarım bu inşaatı yenmenin bir yolu vardır.

Kanıtın üzerine. Yukarıdaki karakterleri kullanarak döngüsel etiket sistemlerini Retina'ya çevirmenin basit bir yolunu anlatacağım .

Öncelikle, kullanıyor olacak `ve {yerine ikili alfabesi için 0ve 1. Bunlar uygundur, çünkü regex'ten kaçmaları gerekmez, ancak Retina için veya ikame sözdiziminde anlamları vardır. Ben `için 0ve {için kullanıyorum 1, ancak bu seçenek isteğe bağlı. Geçen karakteri ile çalışan bize kullanmanızı sağlar çünkü Dahası, biz bellekte dize (ve yapımları) ters gidiyoruz $ve $`yerine ^ve $'karakter yeniden kullanımını maksimize.

İlk kelime ile gösterilirse Sve i(tersine çevrilmiş) yapım çağrılırsa , ortaya çıkan program şöyle görünecektir:pi


S
{`

{$
¶p1$%``
``$

{$
¶p2$%``
``$

{$
¶p3$%``
``$

...

Bu yapı kaçınılmaz bir şekilde bir üretim uygulandığında hafızada çoğalır ve sona ermesi muhtemel değildir - aslında, döngüsel etiket sisteminin sona ereceği noktada (çalışma dizesi boşaldığında) ortaya çıkan Retina programının davranışı temelde tanımsız.

Programın ne yaptığına bakalım:


S

Çalışma dizesini ilk kelimeye sıfırlayarak başlıyoruz.

{`

Bu, programın geri kalanını, sonuçta elde edilen dizgiyi değiştirmeyi başaramaz hale getirene kadar sarar (hey, yerleşik yerleşik sonsuz döngü algılama için ücretsiz ...). Oradaki iki besleme hattı gerçekten gerekli değil, ancak döngüyü bireysel yapımlardan daha net bir şekilde ayırıyorlar. Programın geri kalanı yapımların her birini takip ediyor ve döngüden dolayı bunları tekrar tekrar ve döngüsel olarak işliyoruz.

Her üretim iki aşamada işlenir. Öncelikle, öncü (veya bizim durumumuzda takip eden) sembolünün {bu durumda olduğu durumu ele alırız, bu durumda üretimi kullanırız:

{$
¶pi$%``

Regex yalnızca dize bittiğinde eşleşir {. Bu durumda, bununla değiştirelim:

  • Bir satır beslemesi ( ). Yalnızca çalışma dizesinin son satırıyla çalışacağız, bu nedenle çalışma dizesini şu ana kadar etkin bir şekilde atar (bu nedenle programın bellek kullanımı büyüyüp büyür).
  • Burada çalışan dizgeye hazırladığımız mevcut üretim ( ) (döngüsel etiket sisteminin eklediği yer).pi
  • Kalan önceki çalışma dizesi ( $%`). Bu yüzden şunu eklemeliyiz : $%`maçtan kalan her şeyi alır, ancak aynı satırda. Dolayısıyla, bu önceki yapımlardan bıraktığımız bütün çöpleri görmüyor. Bu hüner bize bir şey eşleşmesi sağlayan sonunda bir şey eklemek için çalışma dizesinin başında gibi bir şey kullanmak zorunda kalmadan, çalışma dize (.+)ve $1anlamlı ihtiyacımız karakter sayısını patlatmak hangi.
  • Tek bir backtick ( `). Bu etkin yerini {( 1biz ile eşleşti -Symbol) `( 0sonraki aşama zaten mevcut üretim işlenmiş olup olmadığını bilmek gerekir kalmaması -Symbol).

Her üretimin ikinci kısmı, üretimin atlandığı önemsiz durumdur:

``$

Sadece bir iz siliyoruz `. `İlk hatta iki kişiye ihtiyacımızın nedeni , Retina'nın ilk backtick'i yapılandırma ve regex arasındaki ayırıcı olarak görmesidir. Bu basitçe boş bir konfigürasyon verir, böylece regex'in geri tepme çubuklarını kullanabiliriz.


20

Java 7, 18 17 karakter

\bcdefu0123456789

Tüm java kaynak kodları unicode kod noktalarına düşürülebilir. "a", yalnızca kullanıldığı için gerekli değildir *:jJzZ. Yıldız işareti çarpma ya da blok yorumları için kullanılır. Çarpma işlemi yalnızca tekrarlanan bir eklemedir ve bunun yerine tek satırlık yorumlar kullanabilirsiniz (veya yalnızca bunları atlayın). Kolon, bunun yerine bir if ifadesi kullanabileceğiniz üçlü operatörler ve döngüler için normalle değiştirilebilecek foreach döngüleri için kullanılır. j ve z, java'daki hiçbir anahtar kelimenin parçası değildir.

Başka bir karakteri silmeye çalışmak, Java kazan plakasında gerekli olan karakterlerden en az birini eklememizi gerektirir class a{public static void main(String[]a){}}. Aşağıya bakınız:

1 -> a (which has already been removed)
2 -> r (required for "String")
3 -> S (required for "String")
4 -> t (required for "static")
5 -> S (required for "String")
6 -> v (required for "void")
7 -> g (required for "String")
8 -> ( (required for "main(String[]a)"
9 -> i (required for "static")
b -> { (required for "class a{")
c -> l (required for "class")
d -> } (required for "(String[]a){}}")
e -> n (required for "main")
f -> o (required for "void")

İşte bir Hello World programına bir örnek: Çevrimiçi deneyin!

Java 8, 16 karakter

\bdefu0123456789

Bunu belirtmek için ais523'e teşekkür ederiz. Java 8, arayüzlerin statik yöntemlere sahip olmasını sağlar, yani "c" yi düşürebiliriz çünkü "class" içindeki "l" için buna ihtiyacımız yoktur. "c" kullanılır, ,<lL\|bu yüzden "a" kaldırdığımızdan biraz daha fazla java işlevselliği kaybederiz, ancak hala tam bir sonuç için yeterlidir. Çevrimiçi deneyin!


3
Elbette, onaltılık hanelerin hangisinin çıkarılabileceğini bulmak, Java'da bunu çözmenin ilginç bir parçası mı? :)
Martin Ender

@MartinEnder kesinlikle. Biraz zaman dönünce bu daha üzerinde çalışma planı
Poke

6
Ve bir şey yazmaya hazır olan ben Java, 127 characters... Güzel olan, Poke;)
Olivier Grégoire

Gerekli karakterler dayanarak Cevabıma , ben başka bir altıgen basamak kaldırılabilir inanmıyorum.

3
Java 8'e geçerseniz, bunu 16'da yapabilirsiniz; Java 8, arayüzlerin durağan yöntemlere sahip olmasını sağlar, bırakmanıza izin verir c(içindeki tüm harflere interfacehala altıgen harflerle aveya hiç kullanılmaz c).

19

Labirent , 5 karakter

~{}

Artı satır beslemeleri (0x0A) ve boşluklar (0x20).

Smallfuck'tan (1 bit hücreleri kullanan azaltılmış Brainfuck varyantı) indirgenme şeklinde bir kanıt çizeceğim . Smallfuck'ın kendisinin Turing-tamamlanmadığını not edin, çünkü dil, teypinin sonlandırılması gerektiğini belirtir; tasarım kısıtlamaları).

Bu indirgeme boyunca önemli bir değişmez, her programın (veya alt programın) aynı satırda başlayan ve biten ve eşit sayıda sütuna yayılan bir Labirent programına (veya alt programa) yol açması olacaktır.

Labirentte başlangıçta sonsuz (örtülü) 0s miktarı ile doldurulmuş iki yığın bulunur . {ve }en üst değeri bu yığınlar arasında kaydırın. Ana yığının tepesini mevcut "hücre" olarak kabul edersek, bu iki yığın Smallfuck tarafından kullanılan sonsuz bandın iki yarı sonsuz yarısı olarak görülebilir. Bununla birlikte, yukarıda belirtilen değişmezliği sağlamak için her bir kaset değerinin iki kopyasının istifler üzerine yerleştirilmesi daha uygun olacaktır. Bu nedenle <ve >tercüme edilecektir {{ve }}(isterseniz bunları takas olabilir) sırasıyla.

Hücre değerlerine izin vermek yerine 0ve 1, kullanıyoruz 0ve -1hangileri arasında geçiş yapabileceğimizi ~(bit yönünde olumsuzlama). Kesin değerler, Turing-eksiksizliğinin amaçları için önemli değildir. Yığındaki değerin her iki kopyasını da değiştirmeliyiz ki bu da bize tekrar eşit bir çeviri sağlar: *olur ~}~{.

Bu kontrol akışı komutlarını bırakır []. Labirentte açık bir kontrol akışı yoktur, bunun yerine kontrol akışı kodun düzeni tarafından belirlenir. Bu yerleşimi yapmak için boşluklara ve satır beslemelerine ihtiyacımız var.

İlk ~~olarak, iki ~etkili bir şekilde iptal olarak, no-op olduğunu unutmayın . Bunu, kodları, uzunlukları eşit olduğu sürece, keyfi olarak uzun yollara sahip olmak için kullanabiliriz. Şimdi AA[BB]CCLabyrinth'e çevirmek için şu yapıyı kullanabiliriz (Labyrinth'deki her snippet'in boyutunun değişmeyen tarafından garanti edildiği şekilde eşit olması için çift harf kullanıyorum):

      ~~~~
      ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

Burada, genişliği ile eşleşen ..uygun bir sayıdır .~BB

Yine, yapının genişliğinin eşit kaldığını unutmayın.

Şimdi bu döngünün nasıl çalıştığını inceleyebiliriz. Kod, üzerinden girilir AA. İlki ~~hiçbir şey yapmaz ve kavşağa ulaşmamıza izin verir. Bu kabaca aşağıdakilere karşılık gelir [:

  • Eğer mevcut hücre değeri sıfırsa, IP nihayetinde atlayacak olan dümdüz ilerlemeye devam eder BB. ..Kısmı hala no-operasyon. Sonra ~başka bir kavşakta bir buluştuk Şimdi mevcut değerin sıfır olmadığını biliyoruz , bu nedenle IP kuzeye döner. Altıdan sonra başka bir kavşağa ulaşana kadar üstteki kıvrımın etrafında gider ~. Böylece bu noktada mevcut değer hala sıfır değildir ve IP, doğuya doğru hareket etmek için tekrar sırayı alır CC. Üç unutmayın ~önce CCdönüş akımı değeri 0döngü atlandı zaman, olması gerektiği gibi.
  • Döngünün başındaki geçerli hücre değeri sıfır değilse, IP güneye döner. Ulaşmadan ~önce altı (daha BBhiçbir şey yapmadan), daha sonra bir ~sonraki kavşağa ulaşmadan önce altı tane daha çalışır . Bu kabaca eşittir ].
    • Geçerli hücre sıfırsa, IP kuzeye doğru hareket etmeye devam eder. Bir sonraki ~değer, değeri sıfır yapmaz, böylece IP, döngünün tamamen atlanması durumunda yolu birleştiren bu ikinci kavşağı alır. Yine, üç ~ulaşmadan önce değeri sıfıra döndürür CC.
    • Geçerli hücre sıfır değilse, IP batıya döner. Bir ~sonraki kavşaktan önce var , yani bu noktada IP değeri batıya devam edecek şekilde mevcut değer sıfırdır. Daha sonra ~IP tekrar ilk kavşağa ulaşmadan önce tek bir sayı olacaktır , böylece değer döndürülür -1ve IP bir sonraki yinelemenin güneyine geçer.

Program herhangi bir döngü içeriyorsa, ilk önce AAprogramın tepesine uzatılmalıdır, böylece IP başlamak için doğru hücreyi bulur:

~     ~~~~
~     ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

Bu budur. Bu azaltmadan kaynaklanan programların hiçbir zaman sona ermeyeceğini, ancak Turing'in tamamlanma gerekliliklerinin bir parçası olmadığını unutmayın (Kural 101 veya Fractran'ı dikkate alın).

Sonunda, bunun optimal olup olmadığı sorusundan ayrıldık. İş yükü karakterleri açısından, üç komuttan daha iyisini yapmanın mümkün olduğundan şüpheliyim. İki kayıt ile Minsky'nin makineleri dayalı bir alternatif yapısını bakınız, ancak bu gerektirir =()ya da =-~sadece bir yığın manipülasyon komutu ancak daha sonra iki aritmetik komutları sahip olan. Yanlış olduğunu kanıtladığım için mutlu olurum. :)

Düzen komutlarına gelince, satır beslemelerinin gerekli olduğuna inanıyorum, çünkü tek bir hatta yararlı kontrol akışı mümkün değil. Bununla birlikte, boşluklar teknik olarak gerekli değildir. Teoride, tüm ızgarayı ~{}(veya =()veya =-~) dolduran bir yapı bulmak ya da çizgilerin hepsinin aynı olmadığı düzensiz bir düzen kullanmak mümkün olabilir . Bununla birlikte, böyle bir kod yazmak inanılmaz derecede zordur, çünkü Labyrinth her hücreye bir bağlantı olarak bakacaktır ve istediğiniz zaman kodun dallanmasını önlemek için gerçekten dikkatli olmanız gerekir. Eğer herhangi biri, alanı atlamanın Turing-eksiksizliği için mümkün olup olmadığını ispatlayabilir veya ispatlayabilirse, bunun için oldukça büyük bir ödül vermekten memnuniyet duyarım. :)


19

Haskell, 5 7 karakter

()\->=;

İşlevsel bir dil olarak Haskell'in elbette lambdaları vardır, bu nedenle lambda hesabını simüle etmek kolaydır. Lambdas sözdizimi en azından karaktere ihtiyacımız var . Ek olarak, isteğe bağlı lambda ifadeleri oluşturabilmek için sınırsız sayıda değişken sembolüne ihtiyacımız var. Neyse ki, çünkü bunun için herhangi bir yeni karakterler gerekmez , , , ..., tüm geçerli değişken isimleridir. Aslında, içindeki parantezin her bir kombinasyonu, sadece ve lambda ifadeleri için ayrılanlar dışında, ve satır yorumu başlatan , geçerli bir değişken adıdır .(\variable->body)argument()\->
(>)(>>)(>>>)\->\->--

Örnekler:

  • S = (\(>)(\\)(-)->(>)(-)((\\)(-)))türleri(t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1
  • K = (\(>)(-)->(>))türünet -> t1 -> t
  • I = (\(>)->(>))yazınt -> t

Düzenleme: Ancak, ais523 yorumlarda da belirtildiği gibi , bu yapı , sınırsız döngülere girme kabiliyetine sahip olmadığı için tek başına Turing-complete olmayan tipli lambda matematiğini uygular . Bunu düzeltmek için özyinelemeyi gerçekleştiren bazı fonksiyonlara ihtiyacımız var. Şimdiye kadar adını verilmeyen lambdalar kullandık, ki bunlar kendilerini arayamazlar, çünkü onların bir adı yoktur. Bu yüzden karakterleri eklemek =ve ;bir fixfonksiyon uygulamak zorundayız :

(>)=(\(-)->(-)((>)(-)));   -- equivalent to: f =(\ x -> x ( f  x ));

Bu beyanla birlikte lambda matematiği Turing tamamlandı, ancak ekledik =ve ;artık kullanılan lamilara ihtiyacımız yok, nimi'nin kullandığı cevapta görebileceğiniz gibi ()=;.


Teknik olarak derleme zamanında olmadan kaldırılmayacak mainmı?
PyRulez

4
Basitçe yazılan SKI birleştiricisi hesabı Turing-tamamlandı değildir; Bunun için türlenmemiş bir lambda hesabına ihtiyacınız var. Maalesef, gösterilerinizin dediği gibi, Haskell, kod üzerine varsayılan olarak yazılı bir yorum ekler.

@PyRulez Varsayılan kurallara göre, fonksiyonların kabul edilebilir olduğunu varsaydım.
Laikoni

@ ais523 SKI birleştiricileri, verilen gösterimde isteğe bağlı lambda terimleri kullanılarak, örneğin kilise sayıları ve bunlardaki işlevler kullanılarak oluşturulmuş bir örnektir.
Laikoni

@ ais523 Lambda Calculus'un yazdığı kaç tane birleştiricinin tamamlanması gerekiyor? Sanırım sadece birleştiriciye ihtiyacın var, değil mi?
PyRulez,

18

CJam, 3 karakter

)Martin Ender'in önerisine göre kaldırıldı

'(~

Örnek olarak verilen Python'a benzer.

Kullanarak karakter '~elde edebilirsiniz ~. Ardından (, istediğiniz karakteri almak için onu azaltabilirsiniz ( ~yazdırılabilir son ASCII karakteridir). ~Herhangi bir dize normal CJam kodu olarak evals. Karakter dizileri karakterleri elde ederek [(azaltılarak ~), değerlendirerek, başka karakter dizileri koyarak, sonra karakterleri değerlendirerek oluşturulabilir ]. Bu sayede, sadece bu üç karakteri kullanarak herhangi bir CJam programını oluşturabilir ve çalıştırabilirsiniz.

Yalnızca 2 + 2 kullanarak hesaplama '(~


Başka bir meydan okuma için, birisi herhangi bir cjam programını alan ve otomatik olarak bu alt kümeye derleyen bir program yaptı. Keşke bulabilseydim
Zwei

1
2 + 2 programını önemli ölçüde düşürmeyi başardım'~((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~
Zwei

@Zwei isminize uygun, harika
Chromium

18

Brain-Flak , 6 karakter

(){}[]

Brain-Flak, yalnızca 8 karakterden oluşan minimalist bir dildir. Bununla birlikte, sadece 6 karakter kullanarak tamamlanan Turing-Blak altkümesinin olduğu kanıtlanabilir.

Yapacağımız ilk şey, sadece bir tane Brain-Flak yığını içeren bir Minsky Makinesi uygulamak. Bir Minsky Makinesinin sadece bir yığınla mümkün olduğunu ispatlayabilirsek, Brain- Flak'in <>ve []nilads olmadan tamamının tamamlandığını gösterebiliriz. Bu hemen herhangi bir karakter kaydetmez, ancak <...>bunun gerekli olmadığını gösterdiğimizde gelecekte olacaktır .

Bir Minsky Makinesi, sınırlı sayıda sınırsız sicile ve iki girişe sahip bir Turing tam otomat türüdür.

  • Kaydı arttır

  • Sıfır olmayan bir düşüş ise, aksi takdirde belirtilen talimatlara geçin.

Brain-Flak'ta bir goto yapısı oluşturmak için aşağıdaki pasajı kullanabiliriz:

(({}[()])[(())]()){(([({}{})]{}))}{}{(([({}{}(%s))]{}))}{}

Bu sayıcı azalacak ve %ssıfır ise çalışacaktır . Bu zincirlerden bir demet, hangi çizgiye gideceğimizi belirten yığına bir sayı koymamıza izin verecektir. Bunların her biri yığının tepesini azaltacaktır, ancak yalnızca biri gerçekte kodu çalıştıracaktır.

Bunu, tüm Minsky Makinesi talimatlarımız için sarıcı olarak kullanıyoruz.

Belirli bir sicili arttırmak istif değiştirmeden oldukça kolaydır. Bu dize formülü ile elde edilebilir:

"({}<"*n+"({}())"+">)"*n

Örneğin 3. sicili arttırmak için aşağıdaki kodu yazarız:

({}<({}<({}<({}())>)>)>)

Şimdi sadece ikinci işlemi uygulamak zorundayız. Brain-Flak'ta bir sayının sıfır olup olmadığını kontrol etmek oldukça basittir:

(({})){(<{}%s>)}{}

sadece %sTOS sıfır olduğunda çalıştırılacaktır . Böylece ikinci operasyonumuzu yapabiliriz.

Minsky Makineleri Turing'i tamamladığından Brain-Flak da <>ve []işlemlerini kullanmadan tamamlanıyor .

Ancak biz henüz karakterlerin sayısını azalttı değil <...>ve [...]hala kullanımda. Bu basit ikame ile çözülebilir. Çünkü her durumda <...>aslında eşdeğerdir [(...)]{}. Böylece Brain-Flak <ve >karakterleri kullanmadan tamamlanıyor (artı tüm no-op'lar).


"Çünkü <...>ve [...]hala kullanımda." Ancak, kaldırmadınız [...]. Lütfen düzelt.
CalculatorFeline

Soru: [...]Gerçekten gerekli mi? 0'a basmak başlangıçta yapılabilir ({})(ancak boş bir yığına dayanır, bu yüzden 0'ların dikkatlice karıştırılması gerekir) Asıl sorun istifin aşağıya erişmeden <...>(artık simüle edilemeyecek) gitmesidir
Hesap MakinesiFeline

16

> <> , 3 karakter

> <>, 3 ile yapılabilir 1p-:

1          Push 1
p          Pop y, x, c and put the char c in cell (x, y) of the codebox
-          Subtraction: pop y, x and push x-y

p2D kodunu, kod kutusuna karakterleri yerleştirerek değiştirerek, yansıtma sağlar. İle 1-, 1-biri çıkardığından ve 111-1--( x-(1-1-1) = x+1) bir tane eklediğinden yığına herhangi bir sayı girebilirsiniz .

Tüm 1p-komutlar yerine getirildiğinde, komut işaretçisi etrafa sarılarak "real" kodunu çalıştırmasına izin verir.

Fibonacci sayılarını hesaplayan bir örnek program ( bu cevaptan ):

111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1-1--1p

Çevrimiçi deneyin! Tüm 1p-komutlar yerine getirildiğinde, kod kutusu şöyle görünür:

01aa+v1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1- ...
@+&1->:?!;&:nao:

vİlk satırdaki her şeyi engelleyen bu standart Fibonacci> <> programıdır.


13

bash, 9 karakter

01456\$ '

Bash, $'\nnn'sekizlik ascii değerleriyle karakter girmek için bir sözdizimine sahiptir . evalKomutu bu biçimde girebiliriz $'\145\166\141\154'. İlk önce istenen sonucu sekizli değerlerine çeviriyoruz. Daha sonra, 0, 1, 4, 5 ve 6 dışındaki rakamları kullanarak herhangi bir sekizli değeri $(()), bir evalöne ekleyerek ve çıkartarak bahsedilen sekizli değerleri değerlendiren ifadelere dönüştürürüz . Son adımımızda, bir tane daha ekleriz evalve parantezleri ve eksi işaretini sekizli değerlerine dönüştürürüz. Bu yöntemi kullanarak herhangi bir bash komutunu çalıştırabiliriz, bu yüzden bu alt küme tamamlanıyor.

Örnek:

dc olur

$'\144\143' hangisi olur

$'\145\166\141\154' \$\'\\144\\$((144-1))\' hangisi olur

$'\145\166\141\154' $'\145\166\141\154' $'\$\\\'\\\\144\\\\$\050\050144\0551\051\051\\\''


12

Olay , 2 karakter

Hangi iki karakteri seçtiğin de önemli değil; İki oktetin herhangi bir kombinasyonu, Olayda Turing-tamamlandı.

Aslında bunu kanıtlamak beklediğinizden çok daha zor ve yazarken, Esolang hakkında Olayla ilgili tartışma sayfası soruna ayrılıyor . Yine de, aşağıda bilinen en basit kanıtın bir özetini vermeye çalışacağım.

Kanıttan önce, bazı arka plan. Olay, programda kullanılan belirteçleri kaynağa bakarak yönlendirir (bir belirteç, kaynakta tam olarak üç kez görünen bir dizedir, başka bir belirtecin temeli değildir ve başka bir potansiyel belirteçle çakışmaz). Bu nedenle, herhangi bir program belirteçlerin ne olduğunu değiştirerek herhangi bir karakter setini kullanacak şekilde dönüştürülebilir; dil Turing tamamlandı (ve aynı zamanda G / Ç için tam bir bütünlük de var!), programlanması inanılmaz derecede zor olmasına rağmen, ihtiyacınız olan "hepsi" sadece iki karakterle çalışması için belirteçleri kodlama yöntemidir.

Ve şimdi, burada ispatın bir özeti (Esolang'ın yerleşik matematikçisi Ørjan tarafından bulundu). Buradaki fikir, bir karakterin iki kopyasını (örneğin 1) diğer karakterin büyük bir denizinde (diğeri) kullanarak bir jetonu kodlamamızdır 0. Arasındaki mesafe 1s her bir simge için değişiklik gösterir, ancak sonra her 4 bir katı olan simge arasındaki doldurma sağlamak için, ek bir listesini kullanarak 0, bir ile s 1ortasında, ancak her bir tarafında 0 ların sayısı 1olduğu değil 4 kişilik bir çoklu ziyade başka programda görünmüyor programın bu özel insidansı özgü bir sayı. Bunun anlamı her biri 11Dolgu içinde sadece iki kez görünebilir, bu yüzden bir tokenin parçası olmayacak; amaçlanan her belirteç, tam olarak iki adet 1 içerir ve hiçbir sahte belirteç birden fazla içeremez 1. Daha sonra, bir 1veya sıfır 1s içeren tüm olası belirteçleri en az dört kopyasını ekleyerek çıkarmak için kenara biraz dolgu ekleriz .


11

Retina , 3 karakter

{`

ve newline.

Öncelikle, ikame yapabilmek için newline'a ihtiyacımız var (tüm programı daha fazla karaktere ihtiyaç duyacak tek bir regex'e sığdırmak istemiyorsak gerekli); ve `ve {döngü yapmanın en az karakter yoğun yoludur. Anlaşılan başka bir şeye ihtiyacımız yok.

Uygulayacağımız hedef dil Thue'nin belirleyici bir çeşididir ( sıradancılıkçılığın Turing'in bütünlüğü için gerekli olmadığı; hangi değerlendirme sırasının kullanıldığına bakılmaksızın doğru çalışması için bir Thue programı yazmak mümkündür). Temel fikir derlemek etmektir pattern::=replacementiçine

`pattern
replacement

(Bu, Thue’nun doğrudan bir Retina çevirisidir; alternatif olarak, eğer Retina’yı tanıyor ancak Thue’yu bilmiyorsanız, Thue’nun nasıl çalıştığını öğrenme yöntemi olarak kullanabilirsiniz); Bunun bir istisnası olarak, ilk desenden önce gelir {`(tüm programı bir döngüye yerleştirmek için; Thue programları, yerine başka bir seçenek eklenmeyene kadar çalışmaya devam eder ve bu Retina'nın aynı şekilde çalışmasına neden olur).

Tabii ki bu, Thue Turing'in tamamıyla adil {ve `kalıplarla ve yerine koyulduğunu kanıtlamamız gerektiği anlamına geliyor , ancak bu yeterince basit; Biz ASCII kodu ile bir karakteri değiştirmek n ile `, n +1 {, ve başka `. Bir modelin karakter sınırlarında herhangi bir yerde eşleşmesi açıkça imkansızdır, bu yüzden orijinal programla aynı şeyi yapacaktır.


1
"Başka programlar mümkün olmadıkça devam edene kadar devam eden programlar devam ediyor ve bu da Retina'nın aynı şekilde çalışmasına neden oluyor" istisnasıyla, tüm programdan geçilen bir dizgeyi değiştirememesi durumunda, Retina'nın erken sonlandırılması istisnasıyla. Böylece bedava basit sonsuz döngü algılama bile elde edersiniz.
Martin Ender

1
Ah doğru. Bu Turing'in bütünlüğünü etkilemiyor elbette (içsel durumu değiştirmeyen sonsuz bir döngü programın hesaplama sınıfına katkıda bulunamaz).

10

Brachylog , 5 karakter

~×₁↰|

Bu karakter dizisi , Fractran'ın bir versiyonunu uygulamamıza izin veriyor. , görünebilecek tek sayının yeniden sayılan ürünler olduğu (yani sadece 1 rakamını kullanarak ondalık sayılarla yazılabilen sayılardan oluşan ürünler) olan bir Fractran . (alt simge olarak bir tamsayı ile) mevcut değeri bu tamsayıya böler, ancak yalnızca tam olarak bölündüğünde (aksi takdirde "başarısız olur" ve çalışması için başka bir durum arar; |durumları ayırır). ×bir tamsayı ile çarpmamıza izin verir. Böylece ~×₁|bir Fractran uygulamasının bir adımını uygulayabiliriz. O zaman tüm programı tekrar yeni akım değerinde çalıştırarak tekrarlanmamıza izin verin. İşte Brachylog'a 11111111111111111111111/111çevrilmiş çok basit bir Fractran programı ( ) örneği.

Peki bu Turing tamamlandı mı? Fractran Turing'i tamamlamak için tek yapmamız gereken yeterince büyük asal sayılardır (Fractran'da bir Turing eksiksiz dili için tercüman yazmak için yeterli). Vardır beş kanıtlanmış ve dört şüphelibüyük olasılıkla henüz keşfedilmemiş olanlara ek olarak, asalları yeniden birleştirin. Aslında bu durumda ihtiyacımız olandan daha fazlası. Program olasılıkları soldan sağa doğru kontrol eder, böylece bir prime komut gösterici olarak ve iki tane daha sayıcı olarak kullanabiliriz, sadece üç asal olan Turing tamlığını gösteririz (iyi bir şey, çünkü tekrarları 2, 19 ile kullanmamızı sağlar. ve kaynak kodun yazılmasını oldukça zorlaştıracak olan 317 veya 1031 hane ile kanıtlanmış fakat can sıkıcı derecede büyük ünitelere başvurmak zorunda kalmadan 23 hane). Bu, iki sayaçlı bir Minsky makinesinin uygulanmasını mümkün kılar (Turing'in eksiksiz olması için yeterlidir).

Derleme özellikle nasıl çalıştığını İşte. Minsky makine uygulamamız için aşağıdaki iki komutu kullanacağız (bu, Turing tamamlandı olarak bilinir) ve her komutun etiketinde bir tamsayı olacaktır:

  • L Etiketi: Eğer {A veya B} sayacı sıfır ise, X'e gidin. Aksi halde düşürün ve Y'ye gidin.
  • L etiketi: Artış sayacı {A veya B}, sonra Z'ye gidin.

Hangi komutun, payda 11, 11 en büyüklerini önce en yüksek güçlerine koyarak seçmeyi seçiyoruz; 11'in üssü komutun etiketidir. Bu şekilde, eşleşen ilk bölüm o anda çalıştırılan komut olacaktır (çünkü önceki olanlar tüm bu 11'ler tarafından bölünemez). Bir azaltma komutu olması durumunda, A veya B sayacı için sırasıyla 111111111111111111111 veya 11111111111111111111111 paydasını bir faktör yerleştiririz ve bu faktörü olmayan başka bir komutla takip ederiz; "Azaltma" durumu, birinci komut tarafından, "sıfır" durumu ise ikinci olarak uygulanacaktır. Bu arada, "goto", paytörde 11 uygun bir güçle ve paytörde 1111111111111111111 veya 111111111111111111111 faktörü ile "artış" ile gerçekleştirilecektir.


İkili olarak coprime üniteleri kullanamamanın özel bir nedeni var mı?
Hesap MakinesiFeline

@CalculatorFeline: Hayır, ama onları ihtiyacı olmayan inşaatı bulana kadar düşünmedim. Bu karakter seti ile yazılmış golf programlarında kesinlikle yardımcı olacaktır.

Ayrıca, tüm tekrar sayıları> 1 ikili kopyadır (bir düşünün)
CalculatorFeline

@CalculatorFeline: Hayır değiller. 111 ve 111111’in her ikisi de, açıkça belli ki, 3 ile bölünebilir durumdadır.

* hiçbir birim başka bir birim ayırmaz
CalculatorFeline

10

Befunge-98, 3 karakter

Bildiğim kadarıyla, Befunge-98'in tamamıyla bitmesi gerekiyordu, bu yüzden sadece herhangi bir Befunge-98 programının sadece üç karakter kullanarak nasıl oluşturulabileceğini göstermemiz gerekiyor. İlk çözümüm şu dört karaktere dayanıyordu:

01+p

Komutla 1birlikte birden çok değer ekleyerek yığına herhangi bir pozitif tamsayı alabiliriz +ve sıfır için basitçe kullanırız 0. İstediğimiz herhangi bir sayıyı itme yeteneğine sahip olduğumuzda p, Befunge oyun alanındaki herhangi bir yere herhangi bir ASCII değeri yazmak için (put) komutunu kullanabiliriz.

Ancak, Sp3000'in belirttiği gibi , aslında sadece üç karakterle başa çıkabilirsiniz:

1-p

Herhangi bir negatif sayı, başlayarak 1ve sonra tekrar tekrar çıkarılarak hesaplanabilir 1(örneğin, -3 olacaktır 11-1-1-1-). Daha sonra, herhangi bir pozitif sayı 1'den 1'den çıkarılarak ifade edilebilir; burada 1-n, nasıl kullanılacağını zaten bildiğimiz bir negatif sayıdır (örneğin, 4 = 1 - (- 3), ki bu olacaktır 111-1-1-1--).

Bu nedenle, yürütmek istediğimiz kodu yavaşça üreten bir tür önyükleyici yazmak için üç karakterimizi kullanabiliriz. Bu yükleyicinin çalışması bittiğinde, oyun alanının ilk satırının başlangıcına sarılacaktır; bu noktada yeni oluşturulan kodumuzun başlangıcını tutmalıdır.

Örnek olarak, işte 2 + 2 toplamak ve sonucu çıkarmak için gereken Befunge kodunu üreten bir bootloader: 22+.@

Ve biraz daha karmaşık bir örnek için, bu "Merhaba Dünya" dır: "!dlroW olleH"bk,@


Bu bir poliglottur, aynı karakterler> <> ve türevleri için kullanılabilir. İyi iş!
Sok

2
Befunge-98, 3 ile 1p-de yapılabilir
Sp3000,

@ Sp3000 Elbette evet! 3 karaktere indirmenin bir yolu olabileceğinden emindim. Teşekkürler.
James Holderness

9

Yakut, 8 karakter

eval"<1+

Python cevaplarından ilham alındı

Nasıl çalışır

  • eval rastgele bir dize yürütmek için kullanılabilir.
  • "<1+, herhangi bir dize oluşturmak için gereken minimum karakter kümesidir

Ruby'de bir dize, boş dize başlangıç ​​noktası olarak kullanılarak oluşturulabilir ve buna ascii karakterleri eklenebilir, örneğin:

eval ""<<111+1<<11+11+11+1<<111<<11+11+11+1

aslında eşdeğerdir

eval ""<<112<<34<<111<<34

hangi dize değerlendirir

p"o"

8

OCaml, 9 karakter

fun->()`X

Bu karakterler SKI Combinator Calculus'u OCaml'de uygulamak için yeterlidir. Özellikle, yeterli parantezle boşluk kullanılmasını önleyebiliriz. Ne yazık ki OCaml'daki lambda ifadeleri funanahtar kelimeyi gerektirir, bu yüzden daha özlü bir çözüm mümkün değildir. Bununla birlikte, daha karmaşık lambda ifadeleri isteniyorsa, rasgele değişken isimleri oluşturmak için aynı harfler kullanılabilir.

S Birleştirici:

fun(f)(u)(n)->f(n)(u(n)) türü ile ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c

K Birleştirici:

fun(f)(u)->u türü ile 'a -> 'b -> 'b

Ben Birleştirici:

fun(f)->f türü ile 'a -> 'a

Ais523'te belirtildiği gibi, basitçe SKI'yi kodlamak yetersizdir. Burada, tip sistemini değiştirmek için polimorfik varyantlar kullanan Z için bir kodlama verilmiştir. Bununla alt kümem tamamlanmış olmalı.

Z Birleştirici:

fun(f)->(fun(`X(x))->(x)(`X(x)))(`X(fun(`X(x))y->f(x(`X(x)))y))

türü ile (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b


2
Basitçe yazılan SKI birleştiricisi hesabı Turing-tamamlandı değildir; Bunun için türlenmemiş bir lambda hesabına ihtiyacınız var. Maalesef, gösterilerinizin dediği gibi, OCaml varsayılan olarak kodun üzerine yazılı bir yorum ekler.

1
O zaman sadece y-birleştiricinin (ve benzer şekilde z-birleştiricinin) kodlanmasına izin verecek polimorfik varyantların kullanımına izin vermek için birkaç karaktere ihtiyacım var.
Devin Lehmacher

Z birleştiricisi nedir?
Hesap MakinesiFeline

@CalculatorFeline Y-birleştiricinin katı bir değişkenidir. OCaml'de gereklidir, çünkü OCaml tembel değildir. İşte Wikipedia sayfasına bir link: en.wikipedia.org/wiki/…
Devin Lehmacher

8

Yığın tabanlı birleşik diller, 4 karakter

Underload

():^

GolfScript

{}.~

CJam

{}_~

GS2

  • geri al, sekme, @boşluk (GS2'nin yazdırılamaz çok kullandığını biliyordum, ancak bu saçmalık…)

dc (@seshoumara tarafından önerilen)

[]dx

Düşük yük sadece Turing-komple kullanımıyla kanıtlandı ():^(Esolang'ın yerleşik matematikçi Ørjan'ı sayesinde). Kanıtı burada açıklamak için çok uzun olduğunu, ancak eğer ilgilenirsen, bu konuda okuyabilirsiniz burada .

Söz konusu komutlar ()(yığına kod yerleştirme), :(yinelenen üst yığın öğesi) ve ^(yığının tepesini değerlendir) şeklindedir. Bu komutlar yığın tabanlı dillerde (özellikle birleştirici diller) oldukça yaygındır ve bu yüzden yukarıdakilerden oluşan bir koleksiyon verdim; bu dillerin tümü, Underload ile aynı nedenle 4 karakterde Turing tamamlandı.


Bunlarla yığın işlemi yapabileceğinizi anlıyorum, ancak matematiksel hesaplamalar yapmak için en az bu yığını doldurmak için sayılara ihtiyacınız yok mu? Yoksa 4 karakterden birini kullanarak aynı zamanda mı yapılır?
seshoumara

1
@seshoumara: Bu yöntem kullanıldığında numaralar (ve diğer tüm veri depolama alanları) çok dolaylı olarak uygulanır . Aritmetik olarak tanınabilir bir şeye gelmeden önce iki veya üç, belki de dört soyutlama seviyesi var. Bu tür şeyler, bunun gibi çok sınırlı sistemlerin Turing eksiksizliği kanıtlarında yaygındır.

Bir cevabın kendime doğru bir dille gönderilmesini düşünüyordum, aynı zamanda yığın tabanlı bir dil, fakat 4'ten daha fazla karakter içeren başka bir yöntem kullanarak. Dc listenize sığabilir mi?
seshoumara

@seshoumara: Evet, gerekli tüm işlevselliğe sahip görünüyor. Ekledim ve size kredi verdim.

Belki FlogScript'i araştırabilirsin.
mbomb007


7

Raket (Şema), 4 karakter

(λ)

Yalnızca λ, parantez ve boşluğu kullanarak, doğrudan Scheme'in Lambda Calculus alt kümesinde programlayabiliriz. Keyfi olarak çok sayıda benzersiz tanımlayıcı sağlamak için bunları bir araya getirerek tüm tanımlayıcılar için λ karakterini yeniden kullanırız.

Örnek olarak, işte sonsuza dek döngüye giren klasik Omega birleştiricisi.

((λ (λλ) (λλ λλ)) (λ (λλ) (λλ λλ)))

6

Python 3, 9 karakter

exc('%1+)

Temel bir açıklama için Python 2 cevabıma bakınız . Bu cevap buna dayanıyor.

Python iki ile aynı karakterleri kullanmak yerine, ()artık parantez kullanımına sahip olduğumuz için karakter bırakabiliyoruz. Programlar hala temel şekle sahip olacak

exec('%c'%stuff)

ancak +yerine kullanarak programın uzunluğunu kısaltırız -, sonra yerine ~kullanarak kaldırabiliriz . Sonra ekleyebilir , ve gerekli ASCII değerlerini alır.10111111

Program print()en kısa zamanda şöyle olur:

exec('%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c'%(111+1)%(111+1+1+1)%(11+11+11+11+11+11+11+11+11+1+1+1+1+1+1)%(11+11+11+11+11+11+11+11+11+11)%(111+1+1+1+1+1)%'('%')')

Çevrimiçi deneyin

Kendinizi düşünüyor olabilirsiniz, biri olmayan bir NULL byte'ı nasıl oluşturur 0? Korkma genç çekirge! Çünkü %matematik için de kullanabileceğimiz , sıfır ile yaratma yeteneğimiz var 1%1.


Neden programında NUL baytını istiyorsun?
NieDzejkob

@NieDzejkob Bu sitede, "neden" her zaman "çünkü biz yapabiliriz" cevabı. Bu durumda, ancak, bir hata yapsa bile, Python'un tam uygulaması olmazdı.
mbomb007

Turing Completeness için NUL baytına ihtiyacınız olmaz; bir BF tercümanı olmadan yazılabilir
MilkyWay90

@ MilkyWay90 Doğru, ancak neden hesaplayamıyorsunuz?
mbomb007

6

PHP 7, 6 karakter

'().;^

Fikir, aşağıdaki yapıyı kullanarak rasgele kod yürütmenin mümkün olduğudur:

('create_function')('','<code>')();

eval Burada işe yaramaz, çünkü bu bir dil yapısıdır ve değişken fonksiyonlarını kullanarak çağrılamaz.

create_function ve kod, mevcut karakterlerin bit cinsinden XOR'larının bir birleşimi olarak yazılabilir:

(<char1_1>^<char1_2>^...).(<char2_1>^<char2_2>^...)...

Kullanılması ().;^için <charX_Y>, alabileceğimiz

()./:;<=JKLMXY^_bcdepqvw

ve bazı yazdırılamayan karakterler. Bu yeterli değil, ancak şimdi 'eXp'()bazı sayısal karakterleri arayabilir ve alabiliriz:

''.'eXp'('eXp'('')) -> 1
''.'eXp'('eXp'('eXp'(''))) -> 2.718281828459
''.'eXp'('eXp'('eXp'('eXp'('eXp'(''))))) -> 3814279.1047602

Bu bize verdiği 1, 2ve 3(diğer dize bir karakter uzunsa diğer karakterler, XOR tarafından göz ardı edilecektir). Dan ().;^123artık hepimiz ASCII karakter kümesi oluşturabilir.

Çevrimiçi deneyin


5

Pyke, 5 karakter

0h.CE

Bu, sonsuz büyük bir sayı üretme, onu dizeye çevirme ve Pyke kodu olarak değerlendirme yeteneğine sahiptir.

Kodun açıklaması:

0- Yığına 0 ekleyin. Bu bir numara başlatmak için gereklidir

h- Önündeki sayıyı arttır. Bunu keyfi bir şekilde tekrarlayarak, çok büyük sayılar oluşturabilirsiniz. Pyke, onları varsayılan olarak kullanan Python'da yazıldığı gibi bignumları destekler.

.C- Aşağıdaki algoritmayı kullanarak bir sayıyı dizgeye çevirin: ( Github link )

def to_string(num):
    string = ""
    while num > 256:
        num, new = divmod(num, 256)
        string = chr(new) + string
    string = chr(num) + string
    return string

Bu noktada, Pyke'de keyfi değerleri olan keyfi bir dizi dizge ve doğal sayı oluşturabiliriz. Regex'e karşılık gelen formda sayılar oluşturulabilir 0(h)*ve dizelerle oluşturulabilir.0(h)*.C . Dizgilerin ve tam sayıların rastgele bir karışımını oluşturmak için birbirleriyle iç içe geçebilirler.

E- bir dize Pyke kodu olarak değerlendirin. Bu, zaten çalışmakta olan Pyke kodu ile aynı ortamı kullanır, böylece girdi gibi şeyleri paylaşır.

Pyke'in Turing'in Tamamlandığına dair kanıt denendi.

Bir dili göstermenin en basit yollarından biri tamamlamanın turing olduğunu Brainf * ck'yi onun içine uygulamaktır. : O listesi ve sözlük operasyonlar nedeniyle Pyke çalışacak şekilde tasarlanmıştır alanda onlara ihtiyacı olmadığı için varolmayan oldukça fazla olduğundan bu birçok dilden daha çok zor Pyke içinde muhtemelen .

İlk önce brainf * ck için bir tercüman yaratır ve yukarıdaki sayıyı oluşturmak için algoritmamızı kullanarak kodlar ve sonra bu sayıyı 0ve ile ifade ederiz h. Daha sonra aynı şekilde çalışacak kodu içeren dizgeyi yaratıyoruz. Bunu bırakacak olsaydık, yığını olduğu gibi tutardık.

string containing brainf*ck code
string containing brainf*ck interpreter

Bunun anlamı, Pyke yığını ilk girişte olduğu gibi kodun zıt biçimde olması gerektiğidir.

Şimdi eğlenceli kısım: brainf * ck yorumlayıcı bir kuyruklu 216 byte ile!

Q~B"><ht.,".:=B;Z]1=L;W~Bo@D=c"ht"{I~c~LZ@EZ]1~LR3:=L)~c\,qIz.oZ]1~LR3:=L)~c\.qI~LZ@.CpK)~c"<>"{I~c"<>""th".:ZE=ZZ1_qI0=Z~L0"":0]10:=L)Z~LlqI~L~Ll"":1_]10:=L))~c\[qI~LZ@0qI\]~B~o>@~o+h=o))~c\]qI~o\[~B~o<_@-t=o)~o~BlN

Burada dene!

Kodu yarı tamamlanmış ancak düzenlenebilir biçimde denemek istiyorsanız, burada deneyin!

Bir dizeden sayıya dönüştürmek için aşağıdaki Python kodunu kullanabilirsiniz:

def conv(string, t=0):
    t *= 256
    t += ord(string[0])
    if len(string) != 1:
        return conv(string[1:], t)
    return t

(Neredeyse) nihai çözüm burada denenebilir!

Brainf * ck yorumlayıcısının açıklaması

İlk önce programı parçalara ayırın:

  • İlklendirme:

Q~B"><ht.,".:=B;Z]1=L; - The initialisation part
Q~B"><ht.,".:          - input.replace("><+-.,[]", "><ht.,")
                       - replace the characters in brainf*ck with some modified ones. 
                       - this means we can `eval` the add and subtract bits easily.
             =B;       - set `B` to this.
                       - The `B` variable contains the instructions
                Z]1=L; - set `L` to [0]
                       - `L` contains the stack, initialised with 0
  • Ana döngü:

​​ ​ ​

W~Bo@D=c !code! ~o~BlN - The main loop
W                      - do
 ~Bo@D=c               -  c=B[o++]
                       -  the c variable is used to store the current character.
                ~o~BlN - while
                ~o     -   o 
                     N -  ^ != V 
                  ~Bl  -   len(B)
                       -  this stops the program running once it's finished.
  • Talimatlar
    • Artım / Azaltma:+-

​​ ​ ​

"ht"{I~c~LZ@EZ]1~LR3:=L) - The bit that does incrementing and decrementing
"ht"{I                 ) - if c in "ht"
        ~LZ@             -  L[Z]
                         -  `Z` contains the current stack pointer
      ~c    E            -  eval current character with ^ as an argument
                         -  returns the contents of `Z` either incremented or decremented
             Z]1~LR3:=L  - L[Z] = ^
  • Giriş ,:

​​ ​ ​

~c\,qIz.oZ]1~LR3:=L) - The code for output 
~c\,qI             ) -  if character == ",":
      z.o            -    ord(input)
         Z]1~LR3:=L  -   L[Z] = ^
  • Çıktı .:

​​ ​ ​

~c\.qI~LZ@.CpK) - The code for input 
~c\.qI        ) - if c == ".":
      ~LZ@      -    L[Z]
          .C    -   chr(^)
            pK  -  print(^)
  • Sola / Sağa Kaydır <>::

​​ ​ ​

~c"<>"{I~c"<>""th".:ZE=Z - main part 
~c"<>"{I                 - if "<>" in c:
        ~c"<>""th".:     -  c.replace("<>", "th")
                    ZE=Z -  Z = eval(char, Z)

Z1_qI0=Z~L0"":0]10:=L) - lower bound check
Z1_qI                ) - if Z == -1:
     0=Z               -  Z = 0
        ~L0"":         -  L.insert("", 0)
              0]10:=L  -  L[0] = 0

Z~LlqI~L~Ll"":1_]10:=L) - upper bound check
Z~LlqI                ) - if Z == len(L):
        ~Ll"":          -  L.insert("", len(L))
      ~L      1_]10:=L  -  L[-1] = 0
  • Şartlı [:

​​ ​ ​

~c\[qI~LZ@0qI\]~B~o>@~o+h=o)) - Code for `[`
~c\[qI                      ) - if c == "[":
      ~LZ@0qI              )  -  if L[Z] == 0:
               ~B~o>          -     B[o:]
             \]     @         -    ^.find("]")
                     ~o+h=o   -   o = o + ^ + 1

- Ve ] :

​​ ​ ​

~c\]qI~o\[~B~o<_@-t=o) - Code for `]`
~c\]qI               ) - if c == "]":
          ~B~o<_       -    reversed(B[:o])
        \[      @      -   ^.find("[")
      ~o         -t=o  -  o = o - ^ -1

5

Yığılmış, 5 karakter

{!n:}

Bu şaşırtıcı derecede kısa. Stacked her bir SKI kombinasyonunu uygulayabilirse, Turing Complete (Tamamlandı) olur. Tekrar:

  • I birleştirici - kimlik işlevi. x -> x
  • K birleştirici - sabit fonksiyon. x -> y -> x
  • S birleştirici - ikame işlevi. (x, y, z) -> x(z)(y(z))

Ben birleştirici: {!n}

Şimdi, yığılmış özellikler için. {! ... }bir n-lambdadır. Argümanı dolaylı olan, tek bir işlevdir n. Ardından, son ifade işlevden döndürülür. Böylece, {!n}tartışmayı nve verimi alan bir işlevdir n.

K birleştirici: {!{:n}}

Şimdi, {:...}hiçbir argüman almayan ve döndüren bir işlevdir .... Bunu n-lambda oluşumumuzla birleştirerek elde ederiz (netlik için boşluk ekleyerek):

{! { : n } }
{!         }   n-lambda. arguments: (n)
   { : n }     lambda.   arguments: ()
       n       yields n.

S Birleştirici: {n!nn!nnn:nnn{!n}!nn!nnn{!n}!n!!}

Tamam, bu biraz daha karmaşık görünüyor. Böylece, bir lambda tanımlayıcı olmayan karakterlerle ayrılmış argümanları alır. Dolayısıyla, başlıktaki lambda eşdeğerdir:

{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}

Bu üç argüman alan bir lambdadır n, nnve nnn. En bu değiştirmek edelim x, yve znetlik için:

{x y z:z{!n}!y!z{!n}!x!!}

İkisi {!n}!, !"çalıştır" anlamına gelen boşlukları tekrar önlemek için sadece kimlik işlevidir . Yani, yine, azaltarak:

{x y z:z y!z x!!}

Bir açıklama ile:

{x y z:z y!z x!!}
{x y z:         }  three arguments
       z y!        apply `y` to `z` -- `y(z)`
           z x!    apply `x` to `z` -- `x(z)`
               !   apply `x(z)` to `y(z)` -- `x(z)(y(z))`

Ve bu nedenle, bu S birleştiricisidir.


{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}boşluk içerir.
Hesap MakinesiFeline

@CalculatorFeline Ondan önce cümleyi okudun mu? Tamam, bu biraz daha karmaşık görünüyor. Böylece, bir lambda tanımlayıcı olmayan karakterlerle ayrılmış argümanları alır. Bu nedenle, başlıktaki lambda eşdeğerdir:
Conor O'Brien

Ah. (Kendime not: Bir salak olmayı bırak.)
CalculatorFeline
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.