Como você deve (espero) saber, um quine endurecido por radiação é um quine do qual você pode remover qualquer caractere e ainda imprimir sua fonte original pré-modificada. O problema é que, com a maioria deles, você pode remover apenas um caractere; caso contrário, tudo quebra. É aqui que entra; seu objetivo é criar uma solução resistente à radiação que possa levar o maior número possível de remoções de caracteres. Qualquer idioma que esteja em conformidade com as regras é bom.
Regras
- O programa deve ter pelo menos um caractere
- O idioma usado deve estar completo (para idiomas como HQ9 + não se qualificarem)
- Todas as outras regras que se aplicam a quines normais também se aplicam aqui.
- A solução com o mínimo
program_length^(2/n)
em que qualquer conjunto den
caracteres exatamente pode ser removido enquanto ainda imprime o código-fonte original vence.
Subleq
. Eu acho que seria ideal para esse tipo de desafio!Respostas:
Perl,
11161124 bytes, n = 3, pontuação = 1124 ^ (2/3) ou aproximadamente 108,1Atualização : verifiquei agora que isso funciona com n = 3 via força bruta (que levou alguns dias); com um programa desse complexo, é difícil verificar a resistência à radiação manualmente (e cometi um erro em uma versão anterior, e é por isso que a contagem de bytes aumentou). Finalizar atualização
Eu recomendo redirecionar o stderr para algum lugar que você não verá; esse programa produz vários avisos sobre sintaxe dúbia, mesmo quando você não está excluindo caracteres.
É possível que o programa possa ser reduzido. Trabalhar nisso é bastante doloroso, facilitando a perda de possíveis micro-otimizações. Meu objetivo era obter o maior número possível de caracteres deletáveis (porque essa é a parte realmente desafiadora do programa), e tratava o tie - break de código-golfe como algo que era bom de se procurar, mas como algo que eu não colocaria esforço ridículo para otimizar (com base em que é muito fácil quebrar a resistência à radiação por acidente).
O programa
Nota: existe um
_
caractere de controle literal (ASCII 31) imediatamente antes de cada uma das quatro ocorrências de-+
. Eu não acho que ele copiou e colou corretamente no StackOverflow, portanto, você precisará adicioná-lo novamente antes de executar o programa.A explicação
Esse programa, claramente, é composto de quatro programas menores idênticos concatenados juntos. A idéia básica é que cada cópia do programa verifique se foi danificado demais para ser executado ou não; se foi, não fará nada (além de possivelmente emitir avisos) e permitirá que a próxima cópia seja executada; se não tiver sido (ou seja, nenhuma exclusão ou o caractere que foi excluído não faz diferença na operação do programa), ele fará o que é minucioso (imprimir o código-fonte completo do programa; esse é um quine apropriado, com cada parte contendo uma codificação de todo o código-fonte) e, em seguida, saia (impedindo que outras cópias não danificadas imprimam o código-fonte novamente e, assim, arruinem a solução imprimindo muito texto).
Cada parte, por sua vez, é composta de duas partes que são efetivamente independentes funcionalmente; um invólucro externo e algum código interno. Como tal, podemos considerá-los separadamente.
Invólucro externo
O wrapper externo é, basicamente,
eval<+eval<+eval< ... >####>####...>###
(mais um ponto e vírgula e novas linhas cujo objetivo deve ser bastante óbvio; é para garantir que as partes do programa permaneçam separadas, independentemente de alguns pontos e vírgulas ou as novas linhas antes deles serem excluídas ) Isso pode parecer bastante simples, mas é sutil de várias maneiras, e a razão pela qual escolhi Perl para esse desafio.Primeiro, vamos ver como o wrapper funciona em uma cópia não danificada do programa.
eval
analisa como uma função interna, que requer um argumento. Como se espera um argumento,+
aqui está um unário+
(que já será muito familiar para os golfistas de Perl; eles são úteis surpreendentemente com frequência). Ainda estamos esperando um argumento (acabamos de ver um operador unário); portanto, o<
que vem a seguir é interpretado como o início do<>
operador (que não aceita argumentos de prefixo ou postfix e, portanto, pode ser usado na posição de operando).<>
é um operador bastante estranho. Seu objetivo usual é ler identificadores de arquivo e você coloca o nome do identificador dentro dos colchetes angulares. Como alternativa, se a expressão não é válida como um nome de arquivo, ela ocorre (basicamente, o mesmo processo que os shells do UNIX usam para converter o texto inserido pelo usuário em uma sequência de argumentos da linha de comando; versões muito mais antigas do Perl realmente usavam a casca para isso, mas hoje em dia o Perl lida internamente com o globbing). O uso pretendido, portanto, é<*.c>
semelhante ao de , que normalmente retornaria uma lista como("foo.c", "bar.c")
. Em um contexto escalar (como o argumento paraeval
), apenas retorna a primeira entrada encontrada na primeira vez que é executada (o equivalente ao primeiro argumento) e retorna outras entradas em execuções hipotéticas futuras que nunca acontecem.Agora, os shells geralmente lidam com argumentos de linha de comando; se você der algo como
-r
sem argumentos, ele será transmitido literalmente ao programa, independentemente de haver ou não um arquivo com esse nome. O Perl age da mesma maneira, desde que asseguremos que não haja caracteres especiais para o shell ou para Perl entre o<
e o correspondente>
, podemos usá-lo efetivamente como uma forma realmente estranha de literal de cadeia de caracteres. Melhor ainda, o analisador de Perl para operadores do tipo cotação tem uma tendência compulsiva a combinar colchetes, mesmo em contextos como este, onde não faz sentido, para que possamos aninhar<>
com segurança (que é a descoberta necessária para que este programa seja possível). A principal desvantagem de todos esses aninhados<>
é que escapar do conteúdo do<>
é quase impossível; parece haver duas camadas de<>
fuga sem escape para cada uma delas ; portanto, para escapar de algo dentro das três, ele precisa ser precedido com 63 barras invertidas. Decidi que, embora o tamanho do código seja apenas uma consideração secundária nesse problema, quase certamente não valia a pena pagar esse tipo de penalidade na minha pontuação, por isso decidi escrever o restante do programa sem usar os caracteres incorretos.Então, o que acontece se partes do wrapper são excluídas?
eval
fazem com que ela se transforme em uma palavra de barra , uma string sem significado. Perl não gosta disso, mas trata-os como se estivessem cercados de aspas; assimeal<+eval<+...
é interpretado como"eal" < +eval<+...
. Isso não tem efeito na operação do programa, porque é basicamente pegar o resultado dos resultados fortemente aninhados (que não usamos de qualquer maneira), convertê-lo em um número inteiro e fazer algumas comparações inúteis. (Esse tipo de coisa causa muitos avisos de spam, pois claramente não é algo útil em circunstâncias normais; estamos apenas usando-o para absorver exclusões.) Isso altera o número de colchetes de ângulo de que precisamos (porque o colchete de abertura agora está sendo interpretado como um operador de comparação), mas a cadeia de comentários no final garante que a sequência termine com segurança, não importa quantas vezes seja aninhada. (Há mais#
sinais do que o estritamente necessário aqui; escrevi como fiz para tornar o programa mais compressível, permitindo que eu use menos dados para armazenar o quine.)<
for excluído, o código agora será analisado comoeval(eval<...>)
. O secundário, outsideeval
não tem efeito, porque os programas que estamos avaliando não retornam nada que tenha efeitos reais como um programa (se eles retornam normalmente, normalmente é uma string nula ou uma palavra de barra; mais comumente eles retornam via exceção, que fazeval
com que retorne uma cadeia nula ou useexit
para evitar retornar).+
for excluído, isso não terá efeito imediato se o código adjacente estiver intacto; unário+
não tem efeito no programa. (A razão pela qual os originais+
existem existe para ajudar a reparar danos; eles aumentam o número de situações nas quais<
é interpretado como um operador unário<>
e não como relacional, o que significa que você precisa de mais exclusões para produzir um programa inválido.)O wrapper pode ser danificado com exclusões suficientes, mas é necessário fazer uma série de exclusões para produzir algo que não é analisado. Com quatro exclusões, você pode fazer o seguinte:
e no Perl, o operador relacional
<
não é associativo e, portanto, você recebe um erro de sintaxe (o mesmo que ocorreria1<2<3
). Como tal, o limite para o programa como está escrito é n = 3. Adicionar mais unários+
parece ser uma maneira promissora de aumentá-lo, mas isso tornaria cada vez mais provável que o interior do wrapper também pudesse quebrar, verificando se a nova versão do programa funciona poderia ser muito difícil.O motivo pelo qual o wrapper é tão valioso é que
eval
no Perl captura exceções, como (por exemplo) a exceção que você recebe ao tentar compilar um erro de sintaxe. Como seeval
trata de uma string literal, a compilação da string acontece no tempo de execução e, se o literal falhar na compilação, a exceção resultante é capturada. Isso fazeval
com que retorne uma cadeia nula e defina o indicador de erro$@
, mas nunca a verificamos (exceto executando ocasionalmente a cadeia nula retornada em algumas versões modificadas do programa). Fundamentalmente, isso significa que, se algo acontecer com o código dentroo invólucro, causando um erro de sintaxe, o invólucro fará apenas com que o código não faça nada (e o programa continuará sendo executado na tentativa de encontrar uma cópia não danificada de si mesmo). Portanto, o código interno não precisa ser tão à prova de radiação quanto o invólucro; tudo o que nos preocupa é que, se danificado, ele agirá de forma idêntica à versão não danificada do programa ou falhará (permitindoeval
capturar a exceção e continuar) ou sairá normalmente sem imprimir nada.Dentro do invólucro
O código dentro do wrapper, basicamente, tem a seguinte aparência (novamente, há um controle
_
que o Stack Exchange não mostrará imediatamente antes do-+
):Este código é escrito inteiramente com caracteres seguros para globos, e seu objetivo é adicionar um novo alfabeto de sinais de pontuação que possibilite escrever um programa real, através da transliteração e avaliação de uma string literal (não podemos usar
'
ou"
como nossa citação marcas, masq(
…)
também é uma maneira válida de formar uma string em Perl). (A razão para o caractere não imprimível é que precisamos transliterar algo no caractere de espaço sem um caractere de espaço literal no programa; assim, formamos um intervalo que começa no ASCII 31 e capturamos o espaço como o segundo elemento do intervalo.) Obviamente, se estamos produzindo alguns caracteres via transliteração, temos que sacrificar caracteres para transliterá-los de, mas letras maiúsculas não são muito úteis e é muito mais fácil escrever sem acesso a elas do que sem acesso a sinais de pontuação.Aqui está o alfabeto de sinais de pontuação que se tornam disponíveis como resultado da glob (a linha superior mostra a codificação, a linha inferior o caractere que codifica):
Mais notavelmente, temos um monte de sinais de pontuação que não são seguros para o globo, mas são úteis para escrever programas Perl, juntamente com o caractere de espaço. Também salvei duas letras maiúsculas, a literal
A
eZ
(que codifica não para si, mas paraT
eU
, porqueA
era necessária como ponto final superior e inferior do intervalo); isso nos permite escrever a própria instrução de transliteração usando o novo conjunto de caracteres codificados (embora as letras maiúsculas não sejam tão úteis, elas são úteis na especificação de alterações nas letras maiúsculas). Os caracteres mais notáveis que não temos disponíveis são[
,,\
e]
, mas nenhum é necessário (quando eu precisava de uma nova linha na saída, eu a produzi usando a nova linha implícita desay
ao invés de precisar escrever\n
;chr 10
também teria funcionado, mas é mais detalhado).Como sempre, precisamos nos preocupar com o que acontece se o interior do wrapper for danificado fora da literal da string. Um corrompido
eval
impedirá que algo funcione; estamos bem com isso. Se as aspas ficarem danificadas, o interior da string não é Perl válido e, portanto, o wrapper a capturará (e as inúmeras subtrações nas strings significam que, mesmo que você pudesse torná-lo válido, Perl não faria nada, o que é um resultado aceitável). O dano à transliteração, se não for um erro de sintaxe, irá mutilar a cadeia de caracteres que está sendo avaliada, normalmente fazendo com que ela se torne um erro de sintaxe; Não tenho 100% de certeza de que não haja casos em que isso ocorra, mas estou forçando-o no momento a garantir, e deve ser fácil o suficiente para corrigir, se houver.O programa codificado
Olhando dentro da string literal, revertendo a codificação que usei e adicionando espaço em branco para torná-la mais legível, obtemos isso (novamente, imagine um sublinhado de controle antes de
-+
, que é codificado comoA
):As pessoas que estão acostumadas com o método Quines reconhecerão essa estrutura geral. A parte mais crucial está no início, onde verificamos que $ o não está danificado; se os personagens foram excluídos, seu comprimento não irá corresponder
181
, então corremoszzzz((()))
o que, se não é um erro de sintaxe, devido aos suportes inigualáveis, será um erro de execução mesmo se você excluir todos os três personagens, porque nenhum dezzzz
,zzz
,zz
, ez
é uma função, e não há como impedir a análise como uma função além de excluir(((
e causar um erro de sintaxe óbvio. O cheque em si também é imune a danos; o||
pode ser danificado,|
mas isso fará com que azzzz((()))
chamada seja executada incondicionalmente; variáveis ou constantes danosas causarão uma incompatibilidade porque você está comparando uma delas0
,180
,179
,178
De igualdade para um subconjunto dos dígitos de181
; e remover um=
causará uma falha na análise e dois=
inevitavelmente farão com que o LHS avalie o número inteiro 0 ou uma seqüência nula, sendo ambos falsey.Atualização : essa verificação estava um pouco errada na versão anterior do programa, então tive que editá-la para corrigir o problema. A versão anterior ficou assim após a decodificação:
e foi possível excluir os três primeiros sinais de pontuação para obter isso:
lengtho179
, sendo uma palavra de barra, é verdadeira e, portanto, quebra o cheque. Corrigi isso adicionando doisB
caracteres extras (que codificam caracteres de espaço), o que significa que a versão mais recente do quine faz isso:Agora é impossível ocultar os
=
sinais e o$
sinal sem gerar um erro de sintaxe. (Eu tinha para adicionar dois espaços em vez de um, porque um comprimento de180
se colocar um literal0
de caracteres na fonte, o que poderia ser abusado neste contexto a zero com um bareword, que sucede. Comparar-inteiro) atualização EndDepois que a verificação de comprimento passa, sabemos que a cópia não está danificada, pelo menos em termos de exclusão de caracteres, por isso é tudo simples e simples a partir daí (substituições de sinais de pontuação devido a uma tabela de decodificação corrompida não seriam capturadas com essa verificação , mas eu já verifiquei por meio de força bruta que não há três exclusões somente da tabela de decodificação que quebram o quine; presumivelmente a maioria delas causa erros de sintaxe). Temos
$o
em uma variável já, portanto, tudo o que precisamos fazer é codificar os invólucros exteriores (com alguma pequena grau de compressão, eu não saltar para fora do código-golf parte da questão inteiramente ). Um truque é que armazenamos a maior parte da tabela de codificação em$r
; podemos imprimi-lo literalmente para gerar a seção da tabela de codificação do invólucro interno ou concatenar algum código ao seu redor eeval
executar o processo de decodificação ao contrário (nos permitindo descobrir qual é a versão codificada de $ o , tendo apenas a versão decodificada disponível neste momento).Finalmente, se fôssemos uma cópia intacta e, portanto, pudéssemos imprimir o programa original inteiro, chamamos
exit
para impedir que as outras cópias também tentem imprimir o programa.Script de verificação
Não é muito bonito, mas publicá-lo porque alguém perguntou. Eu executei isso várias vezes com uma variedade de configurações (normalmente alterando
$min
e$max
para verificar várias áreas de interesse); não foi um processo totalmente automatizado. Ele tende a parar de funcionar devido à carga pesada da CPU em outro local; quando isso aconteceu, mudei$min
para o primeiro valor do$x
que não estava totalmente verificado e continuei executando o script (garantindo assim que todos os programas no intervalo fossem verificados eventualmente). Eu só verifiquei exclusões da primeira cópia do programa, porque é bastante óbvio que exclusões das outras cópias não podem fazer mais.fonte
Befunge-98 , 884, n = 14, pontuação ≈ 2.636
Experimente online!
Isso não funciona apenas quando você remove exatamente 14 caracteres, mas mesmo quando você remove qualquer quantidade de até 14 caracteres.
n = 14
pode parecer uma escolha muito arbitrária, mas a técnica que usei só pode ser usada para ordens de proteção contra radiação de 1 a 14, mas não facilmente além disso (pode ser possível, mas não tenho idéia de como). O quine de ordem 1 tem apenas 73 bytes (embora empregue alguns truques de golfe que não se aplicam aos maioresn
):Explicação
Quando eu estava trabalhando nessa resposta , descobri que é possível definir o delta do ponteiro de instruções para
(2,0)
sob condições de proteção de radiação com o seguinte trecho:Veja a resposta para saber por que isso funciona. Achei isso apenas com um pouco de brincadeira à mão, mas isso levantou a questão de saber se existem padrões semelhantes que são robustos sob a remoção de vários caracteres. Então, escrevi um pequeno script do Mathematica para procurá-los por força bruta:
Isso revelou muito rapidamente um padrão. Para obter um snippet correspondente que funcione para a remoção de até
n
caracteres, você pode usar(m0x){n}m0
ondem
están+1
ex
ém
ou0
. Portanto, tudo o que se segue funcionaria para remover até dois caracteres:Tenho certeza de que é possível provar isso, mas verifiquei
n
até7
. Claro, isso só funciona desde que possamos representarn+1
como um único dígito, e o maior dígito desse tipo no Befunge 98 é of
que representa 15. É por isso que minha abordagem é limitadan = 14
. Se alguém encontrar uma maneira de definir o delta de maneira confiável para maiorn+1
, provavelmente seria possível aumentar a ordem dessa solução endurecida por radiação indefinidamente.Vamos dar uma olhada no código real. Existem basicamente duas partes. Primeiro, definimos o delta como
(15,0)
como acabei de mencionar:E o restante do código repetiu cada comando 15 vezes e imprime a fonte. Se removermos a repetição, fica assim:
A
"
técnica é uma técnica 2D de quining padrão: inicia o modo de sequência, empurra todos os caracteres (exceto ele próprio) para a pilha e termina o modo de sequência novamente depois de contornar. Isso nos ajuda a obter todos os pontos de código da segunda metade, mas não conseguirá fornecer nada útil a partir da primeira metade, porque durante todo of00f00...f0
bit, ele registrará apenas dois caracteres (que podem serf
ou0
dependendo de quais caracteres foram excluídos) ) Mas como essa parte não é composta de caracteres sendo repetidos 15 vezes, precisamos imprimi-la separadamente de qualquer maneira.Mais convenientemente, no quine não modificado, o comprimento da corda antes do
"
é-1 (mod 15)
. Isso garante que não importa quantos caracteres (até 14) removemos, que o número de caracteres gravados seja sempre 3 (umx
e dois def
e0
). Isso é realmente verdade para qualquer pedido de radiação de até 14.Começamos agora imprimindo a
f00f00...f0
peça:O próximo
3k$
simplesmente descarta isso0
, assim como os três caracteres que foram enviados"
desde o início do programa. Agora, a pilha contém apenas os caracteres após o"
e alguns itens indesejados abaixo do original,f00f00...f0
dependendo de quais caracteres foram excluídos.Agora, basta inverter o topo da pilha (contendo os caracteres restantes) e imprimir cada um deles 15 vezes.
E é isso. :)
fonte
JavaScript (ES6), 927 bytes, n = 1, pontuação = 859329
nota: não use um REPL (como um console do navegador) para executar isso.
Isso foi escrito antes que o tamanho do código fosse um fator, por isso ainda não é um jogo de golfe.
Isso foi muito difícil e merece uma explicação completa. Que escreverei mais tarde, depois de explorar um pouco mais esse desafio!
nota: existe uma nova linha à direita
Basicamente, a primeira linha é cuidadosamente construída para renomear todos os 'erros ortográficos' de
setTimeout
funções válidas, de modo que, se um caractere for removido de um dos,setTimeout
o código não cometerá erros e a versão ilesa poderá ser executada. Também está escrito para que, se qualquer caractere for removido da primeira linha, não haverá erro e o restante do código não seja afetado.O segundo e o terceiro bloco são exatamente equivalentes. Se um for executado até a conclusão, ele define a
_
variável para que o outro saiba que não deve duplicar o quine. Se um desses blocos errar, ele não afetará o outro bloco porque foi chamado de forma assíncronasetTimeout
. O erro causará_
não seja definido, portanto o outro bloco será restaurado com êxito. O código principal está em uma string, que é verificada quanto ao comprimento em cada bloco para garantir que não houve remoções.As strings de modelo na próxima linha com alguns comentários no final das strings de modelo protegem o código de erros se um dos backticks que formam a string de modelo for removido. Se o backtick final for removido, a sequência do modelo será finalizada pelo backtick no comentário. Se o backtick inicial for removido, o setTimeout será avaliado como uma função não atribuída (no-op) e o código será executado normalmente, sem um setTimeout. O backtick final é anulado por outro comentário.
O que você disse? Você quer experimentar? Não digas mais nada!
Recomenda-se o modo de página inteira.
Ignore a caixa de entrada, este trecho não aceita entrada.
Tente remover qualquer caractere do código!
Não acredita nisso? O código normal ainda funcionará (mas não funcionará ...) Tente algo como
console.log(5)
!nota: o trecho teve que ser modificado ligeiramente para desativar o recurso REPL, por isso removi vários recursos de saída apenas para esta resposta.
Uma explicação melhor está por vir. Enquanto isso, sinta-se à vontade para me enviar uma mensagem no chat @jrich com quaisquer comentários / perguntas / críticas!
fonte
this
vez dewindow
.