Programa que se permite codificar uma sequência (variante-quine)

16

Escreva um programa que imprima a seguinte linha de 80 caracteres:

Este programa do codegolf.stackexchange.com permite-se codificar uma string.

depois aceita uma linha de entrada e depois imprime seu código-fonte com seus pontos de código possivelmente reordenados (nenhum adicionado e nenhum excluído). Quando esse código é executado, o mesmo precisa acontecer, exceto que a linha impressa seria a linha de entrada mais recente.

O regex no estilo Perl ^[A-Za-z0-9. ]{80}$corresponderá a qualquer linha de entrada. Você não pode fazer nenhuma suposição adicional.

A pontuação de uma submissão é o número de pontos de código em seu código-fonte menos 94 . Menor é melhor.

O código não deve fazer nada que seja inaceitável em uma solução ( por exemplo, leitura de arquivo). Em particular, qualquer envio com uma pontuação negativa deve estar enganando de alguma forma, como 93! é menor que 64 80 .

21/04/2014 adicionado: O código-fonte inteiro do seu programa deve estar bem formado na codificação de caracteres sob a qual você conta pontos de código. Por exemplo, você não pode usar 80 bytes consecutivos no intervalo de bytes à direita UTF-8 (80..BF) e contar cada um como um único CARACTER DE SUBSTITUIÇÃO U + FFFD (ou pior, como nenhum ponto de código).

Além disso, se a codificação permitir várias maneiras de codificar um ponto de código ( por exemplo, SCSU ), seu programa, bem como todos os programas que gera direta ou indiretamente, deverá usar apenas um deles (ou pelo menos todos deverão ser tratados de forma equivalente em todo o código )

PleaseStand
fonte
Depois de reler sua pergunta, não tenho certeza se minha resposta faz exatamente o que você tinha em mente. A canalização da nova seqüência de caracteres para o programa está OK ou precisa iniciar um prompt interativo?
Dennis
@ Dennis: Não é por isso que sua resposta não é aceitável. Antes, ele lê a entrada antes de imprimir "Este programa de [...]".
PleaseStand
Foi isso que eu quis dizer, simplesmente não expressei bem. O intérprete GolfScript lê tudo o que é canalizado antes de começar a executar o script. A única maneira de evitar isso é iniciar um prompt, o que torna a tubulação impossível.
Dennis
Oi, eu estou tentando isso em JavaScript. Parece impossível criar uma solução sem ler o texto entre as tags <script>? Qual é o objetivo de permutar o código fonte? Você diz 'possivelmente reordenado'; isso significa permutar apenas se necessário?
bacchusbeale

Respostas:

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$=.@^}/]"'".@+\+\'.~'}.~

Como funciona

Começamos escolhendo 94 caracteres diferentes que serão permutados para codificar uma sequência. Quaisquer 94 caracteres funcionariam, mas escolhemos o seguinte para fins de golfe:

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

Vamos chamar a matriz desses caracteres "&".

A linha de entrada sempre conterá 81 caracteres (incluindo o LF). Todos esses caracteres estão presentes nos primeiros 65 caracteres de "&". Esse é o único motivo para escolher caracteres nos 128 bytes superiores.

Substituímos cada caractere da string pelo seu índice em “&”, para que LF se torne 0, o espaço se torne 1 etc.

Consideramos os 81 números obtidos os dígitos de um único número base 65. Vamos chamar esse número de "N".

Agora, enumeramos todas as permutações possíveis de "&" e recuperamos a permutação correspondente ao número acima. Isso é alcançado da seguinte maneira:

  1. Conjunto c = 1e A = [].
  2. Anexar N % ca A.
  3. Conjunto N = N / ce c = c + 1.
  4. Se c < 95, volte para 2.
  5. Conjunto i = 0e s = "".
  6. Recupere o charcter &[A[i]], anexe-o a "s" e remova-o de "&".
  7. Set i = i + 1.
  8. Se i < 94voltar para 6.

Suponha que tenhamos blocos de código "E" e "D" que codificam e decodificam uma string, conforme explicado acima.

Agora, precisamos de um invólucro para os blocos de código que atendem aos requisitos da pergunta:

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

Isso faz o seguinte:

  • {…}.~define um bloco, duplica e executa a segunda cópia. A primeira cópia permanecerá na pilha.

  • \.$ troca a sequência codificada pelo bloco e cria uma cópia da sequência codificada, com caracteres classificados.

  • [{}/]:&; converte a string de cima em uma matriz, salva em "&" e a descarta.

  • D puts decodifica a sequência codificada e imprime o resultado.

  • '"#{`head -1`}"'~lê uma linha de entrada executando head -1no shell.

  • E "'".@+\+ codifica a sequência e precede e acrescenta uma aspas simples.

  • \'.~'troca a sequência codificada e o bloco e anexa a sequência '.~'.

  • Após a execução do bloco, o GolfScript imprime o conteúdo da pilha (sequência codificada, bloco, '.~') e sai.

"E" pode ser definido da seguinte forma:

{&?}%        # 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" pode ser definido da seguinte forma:

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.

Golfe final:

  • Substitua \.$[{}/]:&;0&@por 0@.$[{}/]:&\para salvar dois caracteres.

  • Defina a função {;65base}:bpara salvar um caractere.

  • Remova todo o espaço em branco, exceto o LF à direita e o LF na string.

Exemplo

$ # 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.
Dennis
fonte
224 menos 94 é 130.
mbomb007 30/03
Você poderia elaborar?
Dennis
1

Perl, 1428 1099

Possui 1193 caracteres ASCII (incluindo 960 dígitos binários permutados). 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

Meu primeiro design

Antes de receber uma sugestão de Dennis para mudar para binário, meu programa permutava dígitos octais.

Meu primeiro design codifica cada string em 160 dígitos octais, com 2 dígitos por caractere. Essa codificação possui 100 8 = 64 caracteres diferentes. O sistema octal possui 8 dígitos diferentes. O programa deve ter 160 cópias de cada dígito, para permitir 8 × 160 = 1280 dígitos.

Eu mantenho 160 dígitos $se os outros 1120 dígitos $t. Começo com um programa que não é adequado, mas apenas imprime as atribuições para $se $tpara a próxima execução. É isso:

$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))é uma atribuição a uma lista vazia de variáveis. Eu tomo esse truque no tutorial de contexto do PerlMonks . Força o contexto da lista no operador de correspondência =~. No contexto escalar, a correspondência seria verdadeira ou falsa, e eu precisaria de um loop $i++ while ($s =~ /$_/g)para contar as correspondências. No contexto da lista, $s =~ /$_/ghá uma lista de correspondências. Eu coloquei essa lista no contexto escalar de uma subtração, para que o Perl conte os elementos da lista.

Para fazer um quine, tomo o formulário $_=q{print"\$_=q{$_};eval"};evaldos perl quines do Rosetta Code . Este atribui uma string q{...}para $_e depois chama eval, para que eu possa ter meu código em uma string e também executá-lo. Meu programa se torna um Quine quando eu envolver minha terceira a última linha em $_=q{e };eval, e mudar o meu passado printpara print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Finalmente, eu jogo meu programa alterando a primeira tarefa para $tpara um comentário e removendo caracteres extras.

Possui 1522 caracteres ASCII (incluindo 1280 dígitos octais permutados).
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

A mudança para binário

Nos comentários, Dennis notou que 960 dígitos binários permutados seriam menores que 1280 dígitos octais. Então, eu gráfico o número de dígitos permutados para cada base de 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) 

gráfico com base no eixo x, número de dígitos permutados no eixo y

Embora a base 8 seja o mínimo local, as bases 2 e 3 e 4 são a melhor base, com 960 dígitos permutados. Para o código de golfe, a base 2 é melhor porque o Perl tem conversões para a base 2.

A substituição de 1280 dígitos octais por 960 dígitos binários salva 320 caracteres.

Mudar o código de octal para binário custa 8 caracteres:

  • Alterar octpara oct'0b'.$_custos 7.
  • Alterar /../gpara /.{6}/gcustos 2.
  • Altere "%02o"para "% 06b" `custa 0.
  • Altere 160para 480custos 0.
  • Alterar 0..7para 0,1salvar 1.

Aprendi algumas dicas de golfe em Perl . Eles economizam 14 caracteres:

  • Altere 'A'..'Z','a'..'z','0'..'9'para A..Z,a..z,0..9, usando palavras de barra e números simples, salva 12 caracteres.
  • Mude "\n"para $/salva 2 caracteres.

Eu salvo 3 caracteres movendo o #$tcomentário para o final do arquivo. Isso remove a nova linha que termina o comentário e um literal \nno quine.

Essas alterações salvam um total de 329 caracteres e reduzem minha pontuação de 1428 para 1099.

Kernigh
fonte
11
Usar dígitos binários em vez de octais exigiria "apenas" 960 caracteres permutáveis.
Dennis
@ Dennis Obrigado pela dica! Eu mudei para binário (salvando 312 caracteres). Enquanto estava aqui, joguei fora mais 17 personagens.
kernigh 27/05