Perl, 1428 1099
Questo ha 1193 caratteri ASCII (inclusi 960 cifre binarie permutate). 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
Il mio primo disegno
Prima di ricevere un suggerimento da Dennis per passare al binario, il mio programma permutava cifre ottali.
Il mio primo disegno codifica ogni stringa in 160 cifre ottali, con 2 cifre per carattere. Questa codifica ha 100 8 = 64 caratteri diversi. Il sistema ottale ha 8 cifre diverse. Il programma deve avere 160 copie di ogni cifra, quindi consente 8 × 160 = 1280 cifre.
Continuo a inserire 160 cifre $s
e le altre 1120 cifre $t
. Comincio con un programma che non è un quine, ma stampa solo i compiti da $s
e $t
per la corsa successiva. Questo è:
$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))
è un'assegnazione a un elenco vuoto di variabili. Prendo questo trucco dal tutorial contestuale di PerlMonks . Forza il contesto dell'elenco sull'operatore di corrispondenza =~
. In un contesto scalare, la corrispondenza sarebbe vera o falsa e avrei bisogno di un ciclo come $i++ while ($s =~ /$_/g)
contare le corrispondenze. Nel contesto dell'elenco, $s =~ /$_/g
è un elenco di corrispondenze. Ho inserito questo elenco nel contesto scalare di una sottrazione, quindi Perl conta gli elementi dell'elenco.
Per fare un quine, prendo il modulo $_=q{print"\$_=q{$_};eval"};eval
dai quines Perl a Rosetta Code . Questo si assegna una stringa q{...}
di $_
e quindi chiama eval
, così posso avere il mio codice in una stringa e anche eseguirlo. Il mio programma diventa un Quine quando mi avvolgo il mio terzo per ultime righe in $_=q{
e };eval
, e cambiare il mio ultimo print
a print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
.
Infine, golf il mio programma cambiando il primo compito in $t
in un commento e rimuovendo i caratteri extra.
Questo ha 1522 caratteri ASCII (inclusi 1280 cifre ottali permutate).
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
Il passaggio al binario
Nei commenti, Dennis notò che 960 cifre binarie permutate sarebbero state inferiori a 1280 cifre ottali. Quindi ho rappresentato graficamente il numero di cifre permutate per ogni base da 2 a 16.
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)
Sebbene la base 8 sia un minimo locale, le basi 2 e 3 e 4 vincolano per la migliore base, a 960 cifre permutate. Per il golf del codice, la base 2 è la migliore perché Perl ha conversioni per la base 2.
Sostituendo 1280 cifre ottali con 960 cifre binarie si risparmiano 320 caratteri.
Il passaggio da codice ottale a binario costa 8 caratteri:
- Cambiare
oct
a oct'0b'.$_
costi 7.
- Modifica
/../g
ai /.{6}/g
costi 2.
- Modificare
"%02o"
in "% 06b" `costa 0.
- Modifica
160
ai 480
costi 0.
- Passa
0..7
a 0,1
Salva 1.
Ho imparato alcuni consigli sul golf Perl . Risparmiano 14 caratteri:
- Passare
'A'..'Z','a'..'z','0'..'9'
a A..Z,a..z,0..9
, usando parole chiave e numeri nudi, salva 12 caratteri.
- Passa
"\n"
a $/
salva 2 caratteri.
Salvo 3 caratteri spostando il #$t
commento alla fine del file. Ciò rimuove la nuova riga che termina il commento e un valore letterale \n
nel quine.
Queste modifiche salvano un totale di 329 caratteri e riducono il mio punteggio da 1428 a 1099.