Perl, 1428 1099
This has 1193 ASCII characters (including 960 permuted binary digits).
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
My first design
Before I took a suggestion from Dennis to switch to binary, my program permuted octal digits.
My first design encodes each string in 160 octal digits, with 2 digits per character. This encoding has 1008=64 different characters. The octal system has 8 different digits. The program must have 160 copies of each digit, so it permutes 8×160=1280 digits.
I keep 160 digits in $s
and the other 1120 digits in $t
. I start with a program that is not a quine, but only prints the assignments to $s
and $t
for the next run. This is it:
$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))
is an assignment to an empty list of variables. I take this trick from the context tutorial at PerlMonks. It forces list context on the match operator =~
. In scalar context, the match would be true or false, and I would need a loop like $i++ while ($s =~ /$_/g)
to count the matches. In list context, $s =~ /$_/g
is a list of matches. I put this list in the scalar context of a subtraction, so Perl counts the list elements.
To make a quine, I take the form $_=q{print"\$_=q{$_};eval"};eval
from the Perl quines at Rosetta Code. This one assigns a string q{...}
to $_
and then calls eval
, so I can have my code in a string and also run it. My program becomes a quine when I wrap my third to last lines in $_=q{
and };eval
, and change my last print
to print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval"
.
Finally, I golf my program by changing the first assignment to $t
to a comment, and by removing extra characters.
This has 1522 ASCII characters (including 1280 permuted octal digits).
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
The switch to binary
In the comments, Dennis noticed that 960 permuted binary digits would be fewer than 1280 octal digits. So I graphed the number of permuted digits for each base from 2 to 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)
Though base 8 is a local minimum, bases 2 and 3 and 4 tie for best base, at 960 permuted digits. For code golf, base 2 is best because Perl has conversions for base 2.
Replacing 1280 octal digits with 960 binary digits saves 320 characters.
Switching code from octal to binary costs 8 characters:
- Change
oct
to oct'0b'.$_
costs 7.
- Change
/../g
to /.{6}/g
costs 2.
- Change
"%02o"
to "%06b"` costs 0.
- Change
160
to 480
costs 0.
- Change
0..7
to 0,1
saves 1.
I learned some Perl golf tips. They save 14 characters:
- Change
'A'..'Z','a'..'z','0'..'9'
to A..Z,a..z,0..9
, using barewords and bare numbers, saves 12 characters.
- Change
"\n"
to $/
saves 2 characters.
I save 3 characters by moving the #$t
comment to the end of the file. This removes the newline that ends the comment, and a literal \n
in the quine.
These changes save a total of 329 characters, and reduce my score from 1428 to 1099.
After rereading your question, I'm not sure if my answer does exactly what you had in mind. Is piping the new string to the program OK or does it have to launch an interactive prompt? – Dennis – 2014-05-10T14:00:59.380
@Dennis: That's not why your answer is not acceptable. Rather, it reads the input before printing "This program from [...]". – PleaseStand – 2014-05-10T14:48:48.027
That's what I meant, I just did't express it well. The GolfScript interpreter reads everything that is piped to it before started to execute the script. The only way to avoid this is to launch a prompt, which makes piping impossible. – Dennis – 2014-05-10T15:07:13.320
Hi, I'm trying this in JavaScript. It seems impossible to make a quine without reading the text between the <script> tags? What is the purpose of permuting the source code? You say 'possibly reordered'; does this mean permute only if necessary? – bacchusbeale – 2014-05-11T11:36:47.483