Kendisinin bir dizeyi kodlamasına izin veren program (quine-variant)


16

Aşağıdaki 80 karakterlik satırı yazdıran bir program yazın:

Codegolf.stackexchange.com adresinden gelen bu program kendisine bir dize kodlama izni verir.

daha sonra bir giriş satırını kabul eder, daha sonra kaynak kodunu büyük olasılıkla yeniden sıralanan kod noktaları ile yazdırır (hiçbiri eklenmez ve hiçbiri silinmez). Bu kod yürütüldüğünde, yazdırılan satırın en son girdi satırı olması dışında aynı şey gerçekleşmelidir.

Perl tarzı normal ifade ^[A-Za-z0-9. ]{80}$herhangi bir girdi satırı ile eşleşir. Ek bir varsayımda bulunamazsınız.

Bir başvurunun puanı, kaynak kodundaki 94'ten az kod noktası sayısıdır . Alçak daha iyi.

Kod, bir sorguda kabul edilemeyecek hiçbir şey yapmamalıdır ( örn. Dosya okuma). Özellikle, negatif puanı olan herhangi bir başvuru 93 gibi bir şekilde hile yapmalıdır! 64 80'den az .

2014-04-21 eklendi: Programınızın tüm kaynak kodu, altında kod noktalarını saydığınız karakter kodlamasında iyi biçimlendirilmiş olmalıdır. Örneğin, UTF-8 sondaki bayt aralığında (80..BF) art arda 80 bayt kullanamaz ve her birini tek bir U + FFFD DEĞİŞTİRME KARAKTERİ olarak sayamazsınız (veya daha da kötüsü, kod noktası olarak değil).

Buna ek olarak, kodlama bir kod noktasını ( örn. SCSU ) kodlamak için birden çok yola izin veriyorsa , programınızın yanı sıra doğrudan veya dolaylı olarak oluşturduğu tüm programlar bunlardan yalnızca birini kullanmalıdır (veya en azından hepsine kod boyunca eşit davranılmalıdır. ).


Sorunuzu yeniden okuduktan sonra, cevabımın tam olarak aklınızdan geçenleri yapıp yapmadığını bilmiyorum. Yeni dizgiyi programa aktarmak tamam mı yoksa interaktif bir istem mi başlatmak zorunda?
Dennis

@Dennis: Bu yüzden cevabınız kabul edilemez. Aksine, "Bu program [...]" dan yazdırmadan önce girdiyi okur .
PleaseStand

Demek istediğim bu, sadece iyi ifade etmedim. GolfScript yorumlayıcısı, komut dosyasını yürütmeye başlamadan önce kendisine verilen her şeyi okur. Bundan kaçınmanın tek yolu, boru tesisatını imkansız kılan bir istem başlatmaktır.
Dennis

Merhaba, ben JavaScript deniyorum. <script> etiketleri arasındaki metni okumadan bir sorgu yapmak imkansız gibi görünüyor mu? Kaynak koduna izin vermenin amacı nedir? 'Muhtemelen yeniden sıralandı' diyorsunuz; bu sadece gerekliyse izin veriyor mu?
bacchusbeale

Yanıtlar:


5

GolfScript, 231 162 131

'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~

Nasıl çalışır

Bir dizeyi kodlamasına izin verilecek 94 farklı karakter seçerek başlıyoruz. 94 karakter işe yarayacaktır, ancak golf amacıyla aşağıdakileri seçiyoruz:

\n .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
àáâãäåçèéêëìíîïðñòóôõöøùúûüýÿ

Bu karakterlerin dizisine “&” diyelim.

Giriş satırı her zaman 81 karakter (LF dahil) içerecektir. Bu karakterlerin tümü “&” karakterinin ilk 65 karakterinde bulunur. Üst 128 bayttaki karakterleri seçmenin tek nedeni budur.

Dizenin her karakterini “&” diziniyle değiştiririz, böylece LF 0 olur, boşluk 1 olur vb.

Elde edilen 81 sayıyı tek bir tabanın 65 rakamının rakamları olarak değerlendiriyoruz. Bu numaraya “N” diyelim.

Şimdi, “&” tüm olası permütasyonlarını numaralandırıyoruz ve yukarıdan bu sayıya karşılık gelen permütasyonu alıyoruz. Bu, aşağıdaki şekilde elde edilir:

  1. Set c = 1ve A = [].
  2. Başına Ekle N % ciçin A.
  3. Set N = N / cve c = c + 1.
  4. Eğer c < 952'ye geri dönün.
  5. Set i = 0ve s = "".
  6. Karakteri alın &[A[i]], “s” ye ekleyin ve “&” işaretinden çıkarın.
  7. Ayarlayın i = i + 1.
  8. Eğer i < 946'ya gidin geri.

Yukarıda açıklandığı gibi bir dizeyi kodlayan ve kodunu çözen “E” ve “D” kod bloklarımız olduğunu varsayalım.

Şimdi, sorunun gereksinimlerine uyan kod blokları için bir sarıcıya ihtiyacımız var:

'encoded string'{\.$[{}/]:&; D puts '"#{`head -1`}"'~ E "'".@+\+\'.~'}.~

Bu aşağıdakileri yapar:

  • {…}.~bir bloğu tanımlar, çoğaltır ve ikinci kopyayı yürütür. İlk kopya yığın üzerinde kalacaktır.

  • \.$ kodlanmış dizeyi blokla değiştirir ve kodlanmış dizenin sıralı karakterlerle bir kopyasını oluşturur.

  • [{}/]:&; dizeyi yukarıdan bir diziye dönüştürür, “&” içine kaydeder ve atar.

  • D puts kodlanmış dizginin kodunu çözer ve sonucu yazdırır.

  • '"#{`head -1`}"'~head -1kabukta yürüterek bir girdi satırını okur .

  • E "'".@+\+ dizeyi kodlar ve tek bir tırnak işareti ekler ve ekler.

  • \'.~'kodlanmış dizeyi ve bloğu değiştirir ve dizeyi ekler '.~'.

  • Blok yürütüldükten sonra, GolfScript yığının içeriğini (kodlanmış dize, blok '.~') yazdırır ve çıkar.

“E” aşağıdaki gibi tanımlanabilir:

{&?}%        # Replace each character by its index in “&”.
);           # Remove the last integer from the array, since it corresponds to the LF.
65base       # Convert the array to an integer “N” by considering it a base 65 number.
[            #
  94,        # For each integer “c” in 0 … 93:
  {          #
    )        # Increment “c”.
    1$1$%    # Push “N % c”.
    @@/      # Rotate “N % c” below “N” and “c” and divide the first by the latter.
  }/;        # Discard “N”.
]            # Collect the results of “N % c” in an array “A”.
-1%          # Reverse “A”.
&\           # Push “&” and swap it with “A”.
[            #
  {          # For each “j” in “A”:
    1$=.[]+  # Push “&[j] [&[j]]”.
    @^       # Rotate “&” on top of “[&[j]]” and take their symmetric difference.
  }/         #
]            # Collect the charcters into an array.

“D” aşağıdaki gibi tanımlanabilir:

0&           # Push 0 (initial value of the accumulator “A”) and “&”.
@            # Rotate the encoded string on top of “&”.
{            # For each character “c” of the encoded string:
    @2$,*    # Rotate “A” on top of the stack and multiply it by the length of “&”.
    2$2$?+   # Get the index of “c” in “&” and add it to “A”.
    @@^      # Rotate “A” below “&” and “c” and take their symmetric difference.
}/;          # Discard “&”.
65base       # Convert “A” into the array of its digits in base 65.
{&=}%        # Replace each digit by the corresponding character in “&”.
''+          # Convert the resulting array into a string.

Son golf:

  • İki karakteri kaydetmek için \.$[{}/]:&;0&@ile değiştirin 0@.$[{}/]:&\.

  • {;65base}:bBir karakteri kaydetmek için işlevi tanımlayın .

  • Dizedeki sondaki LF ve LF dışındaki tüm boşlukları kaldırın.

Misal

$ # Create GolfScript file using base64 to avoid encoding issues.
$ base64 > permute.gs -d <<< JzHg4jT/YVZvNUf5cFpCdGlYT/xyc/NO7k1tV+VLSGMwOUpk8frqeXrtRUPkWe9oRFUg4+FJRvU26TjyUuxqVHYyM/hudfBMd3hmU2v0YutBZWxx/S7n6FBRCvb7ZzcnezBALiRbe30vXTomXHtAMiQsKjIkMiQ/K0BAXn0vezs2NWJhc2V9OmJ+eyY9fSUnJytwdXRzJyIje2BoZWFkIC0xYH0iJ357Jj99JSliWzk0LHspMSQxJCVAQC99LztdLTElJlxbezEkPS5AXn0vXSInIi5AK1wrXCcufid9Ln4K
$
$ # Set locale to en_US (or any other where one character is one byte).
$ LANG=en_US
$
$ # Go back and forth between two different strings.
$ # Second and sixth line are user input, not output from the script.
$
$ golfscript permute.gs | tee >(tail -n+2 > tmp.gs) && golfscript tmp.gs && rm tmp.gs
This program from codegolf.stackexchange.com permutes itself to encode a string.
Permuting source code code points to encode a string is a certain quine variant.
'18äJoS3sgV9qdçëxm0ÿKMNe5íPî.Htn2ciâIuøbRZéð4AwB7áìUüöôWõèûfñåLàóDrhQlO6
pTaýzòkùYCyFêïãG júEvX'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
Permuting source code code points to encode a string is a certain quine variant.
This program from codegolf.stackexchange.com permutes itself to encode a string.
'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
$
$ # Sort all characters from the original source code and hash them.
$ fold -1 permute.gs | sort | md5sum
b5d978c81df5354fcda8662cf89a9784  -
$
$ # Sort all characters from the second output (modified source code) and hash them.
$ golfscript permute.gs | tail -n+2 | fold -1 | sort | md5sum
Permuting source code code points to encode a string is a certain quine variant.
b5d978c81df5354fcda8662cf89a9784  -
$
$ # The hashes match, so the characters of the modified source code are a permutation
$ # of the character of the original one.

224 eksi 94, 130.
mbomb007

Açıklayabilir misiniz?
Dennis

1

Perl, 1428 1099

Bu 1193 ASCII karaktere sahiptir (960 izin verilen ikili basamak dahil). 1193-94 = 1099

$s='010011100001100010101100111111101001101011101000100000101011011010100110111111011111101011101000100110111111011100101000011101011110100000101000100101011111111110101100101101011010011100100100011110110001011100100001011010100111100000011110111110011100101000100110111111101001011110101011100110101110101101011110101100111111100010101101101100011110100101011111111111101101101000111111011110100111011100101000011101011110111111011010111111101100101101101011100010100111100000111110';$_=q{$i=join'',A..Z,a..z,0..9,'. ';print map({substr$i,oct'0b'.$_,1}$s=~/.{6}/g),$/;chop($s=<>);$s=join'',map{sprintf"%06b",index$i,$_}$s=~/./g;$t=join'',map{$_ x(480-(()=$s=~/$_/g))}0,1;print"\$s='$s';\$_=q{$_};eval#$t"};eval#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

İlk tasarımım

Dennis'den ikiliye geçmesi için bir öneri almadan önce, programım sekizlik sayılara izin verdi.

İlk tasarımım her dizeyi karakter başına 2 basamakla 160 sekizlik basamakta kodlar. Bu kodlamanın 100 8 = 64 farklı karakteri vardır. Sekizli sistemin 8 farklı basamağı vardır. Program her basamağın 160 kopyasına sahip olmalıdır, böylece 8 × 160 = 1280 basamağa izin verir.

160 haneyi $s, diğer 1120 haneyi tutuyorum $t. Bir quine olmayan bir program ile başlamak, ama yalnızca atamaları yazdırır $sve $tsonraki saldırı için. Budur:

$s = '2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';
$t = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777';

# $i = character map of 64 characters, such that:
#  substr($i, $_, 1) is the character at index $_
#  index($i, $_) is the index of character $_
$i = join '', 'A'..'Z', 'a'..'z', '0'..'9', '. ';

# Decode $s from octal, print.
#  1. ($s =~ /../g) splits $s into a list of pairs of octal digits.
#  2. map() takes each $_ from this list.
#  3. oct() converts $_ from an octal string to a number.
#  4. substr() on $i converts number to character.
#  5. print() outputs the characters from map() and a final "\n".
print map({ substr $i, oct, 1 } $s =~ /../g), "\n";

# Read new $s, encode to octal.
#  1. ($s = <>) reads a line.
#  2. chop($s) removes the last character of $s, the "\n".
#  3. ($s =~ /./g) splits $s into characters.
#  4. map() encodes each character $_ as a pair of octal digits.
#  5. join() concatenates the pairs from map().
chop($s = <>);
$s = join '', map { sprintf "%02o", index $i, $_ } $s =~ /./g;

# Make new $t.
#  1. map() takes each $_ from 0 to 7.
#  2. $_ x (160 - (() = $s =~ /$_/g)) makes a string where $_ repeats
#     160 times, minus the number of times that $_ appears in $s.
#  3. join() concatentates the strings from map().
$t = join '', map { $_ x (160 - (() = $s =~ /$_/g)) } 0..7;

# Print the new assignments for $s and $t.  This is not yet a quine,
# because it does not print the rest of the program.
print "\$s = '$s';\n\$t = '$t';\n";

(() = $s =~ /$_/g))boş bir değişken listesine atamadır. Bu numarayı PerlMonks'taki bağlam öğreticisinden alıyorum . Liste içeriğini eşleştirme işlecinde zorlar =~. Skaler bağlamda, maç doğru veya yanlış olur $i++ while ($s =~ /$_/g)ve maçları saymak gibi bir döngüye ihtiyacım olur . Liste bağlamında, $s =~ /$_/geşleşmelerin listesidir. Bu listeyi bir çıkarımın skaler bağlamına koydum, bu yüzden Perl liste öğelerini sayar.

Bir Quine yapmak için, ben şeklinde $_=q{print"\$_=q{$_};eval"};evalgelen Rosetta Kodu'ndaki Perl quines . Bu, bir atar bir dize q{...}kadar $_sonra ve çağrıları evalbir dizesinde kodumu var ve ayrıca çalıştırmak, böylece. Benim programım son çizgiler benim üçte sarın bir quine olur $_=q{ve };evalve benim son değiştirmek printiçin print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Son olarak, ilk ödevi $tbir yoruma çevirerek ve fazladan karakterleri kaldırarak programımı golf oynuyorum.

1522 ASCII karakteri vardır (1280 izin verilen sekizlik basamaklar dahil).
1522-94 = 1428

$s='2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
$_=q{$i=join'','A'..'Z','a'..'z','0'..'9','. ';print map({substr$i,oct,1}$s=~/../g),"\n";chop($s=<>);$s=join'',map{sprintf"%02o",index$i,$_}$s=~/./g;$t=join'',map{$_ x(160-(()=$s=~/$_/g))}0..7;print"\$s='$s';#$t\n\$_=q{$_};eval"};eval

İkili programa geçiş

Yorumlarda Dennis, 960'a izin verilen ikili basamakların 1280 sekizlik basamaktan daha az olacağını fark etti. Bu nedenle, her bir taban için izin verilen basamak sayısını 2'den 16'ya kadar grafikledim.

Maxima 5.29.1 http://maxima.sourceforge.net
using Lisp ECL 13.5.1
...
(%i36) n : floor(x);
(%o36)                             floor(x)
...
(%i41) plot2d(n * ceiling(log(64) / log(n)) * 80, [x, 2, 16],
              [xlabel, "base"], [ylabel, "number of permuted digits"]);
(%o41) 

x ekseninde tabanı olan grafik, y ekseninde izin verilen basamak sayısı

Taban 8 yerel bir minimum olmasına rağmen, taban 2 ve 3 ve 4 en iyi taban için 960 izin verilen basamakta bağlanır. Kod golf için taban 2 en iyisidir çünkü Perl taban 2 için dönüşümlere sahiptir.

1280 sekizlik basamağın 960 ikili basamakla değiştirilmesi 320 karakterden tasarruf sağlar.

Kodu sekizlikten ikili sayıya geçirmek 8 karakterdir:

  • Değişim octiçin oct'0b'.$_maliyetlerin 7.
  • Değişim /../giçin /.{6}/gmaliyetlerin 2.
  • Değişim "%02o""% 06B" için `0 mal olur.
  • Değişim 160için 480maliyetlerin 0.
  • Kaydetme 0..7olarak değiştirme 0,11.

Bazı Perl golf ipuçlarını öğrendim . 14 karakter kaydederler:

  • Değişim 'A'..'Z','a'..'z','0'..'9'için A..Z,a..z,0..9, kullanan barewords ve çıplak sayılar, yalnızca 12 karakter kazandırır.
  • 2 karakter kaydetmek "\n"için değiştirin $/.

#$tYorumu dosyanın sonuna taşıyarak 3 karakter kaydediyorum . Bu, yorumu sonlandıran yeni satırı \nve ayraçtaki bir değişmezi kaldırır .

Bu değişiklikler toplam 329 karakter kazandırıyor ve puanımı 1428'den 1099'a düşürüyor.


1
Sekizli rakamlar yerine ikili kod kullanmak için "sadece" 960 izin verilen karakter gerekir.
Dennis

@Dennis Bahşiş için teşekkürler! Ben ikili (312 karakter kaydetme) geçiş yaptım. Buradayken 17 karakter daha bıraktım.
kernigh
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.