O objetivo desse desafio é (eventualmente) gerar todos os programas de parada possíveis em um idioma de sua escolha. No início, isso pode parecer impossível, mas você pode fazer isso com uma escolha muito cuidadosa da ordem de execução.
Abaixo está um diagrama ASCII para ilustrar isso. Deixe as colunas representarem uma numeração de todos os programas possíveis (cada programa é um número finito de símbolos de um alfabeto finito). Deixe cada linha representar uma etapa singular na execução desse programa. Um X
representa a execução executada por esse programa naquele intervalo de tempo.
step# p1 p2 p3 p4 p5 p6
1 X X X X X X
2 X X X X X
3 X X X X
4 X X X X
5 X X X
6 X X
7 X X
8 X X
9 X X
∞ X X
Como você pode ver, os programas 2 e 4 não param. Se você os executasse um de cada vez, seu controlador ficaria preso no loop infinito que é o programa 2 e nunca produziria os programas 3 e além.
Em vez disso, você usa uma abordagem de encaixe . As letras representam uma possível ordem de execução para as primeiras 26 etapas. Os *
s são locais onde o programa foi interrompido e produzido. Os .
passos são ainda não executados.
step# p1 p2 p3 p4 p5 p6
1 A C F J N R V
2 B E I M Q * Z
3 D H * P U
4 G L T Y
5 K O X
6 * S .
7 W .
8 . .
9 . .
∞ . .
Requisitos para o idioma de destino
O idioma de destino (o que está sendo interpretado em paralelo) deve estar completo em Turing. Fora isso, pode ser qualquer idioma que seja completo em Turing, incluindo subconjuntos completos em Turing de idiomas muito maiores. Você também é livre para interpretar coisas como regras do sistema de etiquetas cíclicas. Você também pode criar um idioma para testar, desde que possa mostrar por que o Turing está completo.
Por exemplo, se você optar por testar o cérebro, então é melhor testar apenas o []-+<>
subconjunto, pois a entrada não é suportada e a saída é descartada (veja abaixo).
Quando se trata do programa "controller" (no qual você está jogando golfe), não há requisitos especiais. Aplicam-se restrições de idioma normal.
Como criar uma lista infinita de programas
A maioria das linguagens de programação pode ser representada como uma série de símbolos de um alfabeto finito. Nesse caso, é relativamente fácil enumerar uma lista de todos os programas possíveis em ordem crescente. O alfabeto que você usa deve ser representativo dos requisitos do idioma de destino. Na maioria dos casos, isso é ASCII imprimível. Se o seu idioma suportar Unicode como um recurso adicional, você não deve testar todas as combinações possíveis de caracteres Unicode, apenas ASCII. Se o seu idioma usar apenas []-+<>
, não teste as várias combinações de caracteres ASCII de "comentário". Idiomas como o APL teriam seus próprios alfabetos especiais.
Se o seu idioma é melhor descrito de alguma maneira não alfabética, como Fractran ou Turing Machines, existem outros métodos igualmente válidos para gerar uma lista de todos os possíveis programas válidos.
Interpretando uma lista crescente de programas
A parte principal desse desafio é escrever um intérprete paralelo para uma lista crescente de programas. Existem algumas etapas básicas para isso:
- Adicione um número finito de programas à lista
- Interprete cada programa da lista individualmente por um período finito de tempo. Isso pode ser realizado executando uma etapa de instrução para cada um. Salve todos os estados.
- Remova todos os programas de finalização / de lançamento de erros da lista
- Saída dos programas com interrupção limpa *
- Adicione mais alguns programas à lista
- Simule cada programa, alternando a execução de programas mais antigos de onde parou
- Remova todos os programas de finalização / de lançamento de erros da lista
- Saída dos programas com interrupção limpa *
- repetir
* Você só deve emitir programas que parem corretamente. Isso significa que não houve erros de sintaxe ou exceções não detectadas lançadas durante a execução. Os programas que solicitam entrada também devem ser finalizados sem a saída deles. Se um programa produz saída, você não deve encerrá-la, apenas jogue a saída fora.
Mais regras
- Você não deve gerar novos encadeamentos para conter os programas testados, pois isso descarrega o trabalho de paralelização no SO host / outro software.
- Editar: para fechar possíveis brechas futuras, você não tem permissão para
eval
(ou qualquer função relacionada) parte do código do programa testado . Você podeeval
bloquear um código a partir do código do intérprete. (A resposta BF-in-Python ainda é válida sob essas regras.) - Isso é código-golfe
- O idioma em que você enviou seu envio não precisa ser o mesmo que você está testando / produzindo.
- Você deve assumir que sua memória disponível é ilimitada.
- Ao provar a integridade de Turing, você pode assumir que a entrada está codificada no programa e a saída pode ser lida no estado interno do programa.
- Se o seu programa se exibir, provavelmente está errado ou é poliglota.
fonte
"If your program outputs itself, it is probably wrong or a polyglot."
Respostas:
subleq OISC em Python,
317269 byteshttps://esolangs.org/wiki/Subleq
Um programa subleq é uma lista extensível de números inteiros (p) e um ponteiro de instrução (i). Essa variante subleq usa endereçamento relativo, o que a página de discussão do wiki sugere que é necessário para garantir a integridade com valores limitados. Cada tick, a operação
p[i+p[i+1]]-=p[i+p[i]]
é executada e,i+=p[i+2]
se o resultado da operação for <= 0, caso contrárioi+=3
. Se i for negativo, o programa será interrompido.Essa implementação testa todos os programas cujo estado inicial é composto por números inteiros não negativos de um dígito (0-9) com um ponteiro de instrução inicial de 0.
A saída é revertida, por razões de golfe. As especificações acima podem ser atualizadas ao contrário, mas não coincidem com o código usado na implementação, por isso não a descrevi dessa maneira.
EDIT: O primeiro programa que exibe crescimento simples e ilimitado é 14283, que diminui o valor no local da memória 6 e grava um 0 explícito (em oposição ao 0 implícito em todas as células) na próxima célula negativa, a cada três marcações.
fonte
Tag cíclico bit a bit em CJam,
98878477 bytesComo esse é um loop infinito, você não pode testá-lo diretamente no intérprete online. Contudo, aqui está uma versão alternativa que lê o número de iterações do STDIN para você brincar. Para testar o programa completo, você precisará do interpretador Java .
BCT é uma variante minimalista de Cyclic Tag Systems . Um programa é definido por duas cadeias binárias: uma lista (cíclica) de instruções e um estado inicial. Para facilitar minha vida ao imprimir os programas, defini minha própria notação: cada uma das cadeias é fornecida como uma matriz de números inteiros no estilo CJam, e todo o programa é cercado
[[...]]
, por exemploTambém estou proibindo estados iniciais vazios ou listas de instruções vazias.
As instruções no BCT são interpretadas da seguinte forma:
0
, remova o bit inicial do estado atual.1
, leia outro bit da lista de instruções, chame issoX
. Se o bit inicial do estado atual for1
, acrescenteX
ao estado atual, caso contrário, não faça nada.Se o estado atual ficar vazio, o programa será interrompido.
Os primeiros programas de interrupção são
Se você quiser ver mais, confira a versão no intérprete on-line que eu vinculei acima.
Explicação
Aqui está como o código funciona. Para acompanhar o encaixe, sempre teremos uma matriz na pilha que contém todos os programas. Cada programa é um par de uma representação interna do código do programa (como
[[0 1 0] [1 0]]
), bem como o estado atual do programa. Usaremos apenas o último para fazer o cálculo, mas precisaremos lembrar do primeiro para imprimir o programa quando ele parar. Esta lista de programas é simplesmente inicializada em uma matriz vazia comL
.O restante do código é um loop infinito
{...1}g
que primeiro adiciona um ou mais programas a esta lista e calcula uma etapa em cada programa. Os programas interrompidos são impressos e removidos da lista.Estou enumerando os programas contando um número binário. O dígito inicial é retirado para garantir que também possamos obter todos os programas com 0s iniciais. Para cada representação binária truncada, eu envio um programa para cada divisão possível entre instruções e estado inicial. Por exemplo, se o contador estiver atualmente em
42
, sua representação binária é101010
. Nos livramos da liderança1
e empurramos todas as separações não vazias:Como não queremos instruções ou estados vazios, iniciamos o contador em 4, o que fornece
[[[0] [0]]]
. Essa enumeração é feita pelo seguinte código:O restante do código mapeia um bloco para a lista de programas, que executa uma etapa da computação BCT na segunda metade desses pares e remove o programa se ele parar:
fonte
Brainfuck em Python, 567 bytes
Uma solução relativamente simples, pois Brainfuck dificilmente é a linguagem mais difícil de se escrever para um intérprete.
Esta implementação do Brainfuck tem o ponteiro de dados começando em 0, apenas com valor positivo (considerado um erro se tentar ir para a esquerda de 0). As células de dados podem assumir valores de 0 a 255 e quebrar. As 5 instruções válidas são
><+[]
(-
desnecessárias devido à embalagem).Acho que a saída está correta agora, no entanto, é difícil ter certeza de que está imprimindo todas as soluções possíveis, para que eu possa estar perdendo alguma.
Os primeiros resultados:
E uma lista dos primeiros 2000: http://pastebin.com/KQG8PVJn
E, finalmente, uma lista dos primeiros 2000 resultados com
[]
eles: http://pastebin.com/iHWwJprs(todo o resto é trivial, desde que válido)
Observe que a saída não está em uma ordem classificada, embora possa parecer assim para muitos deles, pois os programas que levam mais tempo serão impressos posteriormente.
fonte
[-]
como o[+]
definitivo devem aparecer porque o conteúdo do loop é simplesmente ignorado (sem quebra automática).[-]
e[+]
foi um bug que agora deve fixo e eu tenho atualizado com as configurações.
? Não é necessário que um subconjunto de BF completo de Turing e a saída sejam ignorados de qualquer maneira. Além disso, como você está agrupando os valores das células, acho que você precisa apenas de um-
e+
.barras em Python,
640498 byteshttps://esolangs.org/wiki////
Um programa de barras é uma string, nesse intérprete limitada aos caracteres '/' e '\'. Nesta implementação, / é '1' e \ é '0' para permitir algum golfe com o uso do bin do python (x). Quando o intérprete encontra a \, o próximo caractere é gerado e os dois caracteres são removidos. Quando encontra um /, ele procura e substitui padrões como / search / replace / incluindo caracteres de escape dentro dos padrões (\\ representa \ e \ / representa /). Essa operação de substituição é executada na sequência repetidamente até que a sequência de pesquisa não esteja mais presente e a interpretação continua desde o início novamente. O programa pára quando está vazio. Um programa será eliminado se houver um conjunto não fechado de / padrões ou um \ sem nenhum caracter após.
fonte
Treehugger em Java,
1.2991.2571.2511.2071.2031.2011.1931.189 bytesfonte
Brachylog → Problema de pós-correspondência , 10 bytes
Experimente online!
Função que é um gerador que gera todos os possíveis problemas de pós-correspondência para os quais as soluções de força bruta acabam sendo interrompidas. (As soluções de força bruta para o problema de pós-correspondência são conhecidas por serem uma operação completa de Turing.) O link TIO contém um cabeçalho que converte um gerador em um programa completo e imprime cada saída imediatamente à medida que é gerada (assim, quando o TIO mata devido ao consumo de mais de 60 segundos de tempo de execução, a saída produzida até o momento é visível).
Isso usa uma formulação do problema em que as cadeias são dadas como cadeias de dígitos, os zeros à esquerda não são permitidos, exceto por
0
si só, as soluções para o problema envolvendo zeros à frente não são aceitas e uma cadeia de dígitos pode ser representada como o número ou menos o número. Claramente, nada disso afeta a integridade de Turing do idioma (porque não há necessidade de um problema de correspondência de postagem para usar o dígito zero).Este programa funciona através da geração de todas as soluções possíveis para os problemas e, em seguida, trabalhando para trás para encontrar os programas originais que são resolvidos por eles. Como tal, um programa individual pode ser produzido várias vezes. Não está claro se isso invalida a resposta ou não; observe que todos os programas de interrupção serão exibidos pelo menos uma vez (de fato, infinitas vezes, como qualquer programa que tenha soluções tem infinitas soluções), e os programas sem interrupção nunca serão exibidos.
Explicação
fonte
"Roxo sem E / S" no Ceilão, 662
O roxo é uma linguagem de instrução única modificadora e foi solicitada a interpretação aqui . Como entrada e saída não são relevantes para esta tarefa, eu removi o
o
significado do símbolo do intérprete, de modo que os (potencialmente) símbolos válidos são apenasa
,b
,A
,B
,i
e1
(o último apenas para leitura, não para escrita).Mas como o Purple é auto-modificável (e usa seu código-fonte como dados), potencialmente também programas que contenham outros caracteres são úteis, então eu optei por permitir todos os caracteres ASCII imprimíveis (que não sejam em branco) no código (outros podem ser útil também, mas não são impressos com tanta facilidade).
(Você pode modificar o intérprete para usar como sequência de caracteres permitidos como argumento da linha de comando - alterne a definição de linha comentada
a
abaixo. Em seguida, o comprimento se tornará 686 bytes.)Meu intérprete "paralelo" cria assim todas as seqüências finitas desses caracteres (em tamanho crescente e ordem lexicográfica) e tenta cada um deles.
O roxo será interrompido sem erro sempre que o comando a ser lido da fita para execução não for válido - portanto, não há programas inválidos e muitos, muitos interrompidos. (A maioria das paradas, mesmo na primeira etapa, apenas alguns dos programas com extensão 3 chegam à segunda etapa (e serão interrompidas); os primeiros sem interrupção têm extensão 6.
Eu acho que o primeiro programa sem interrupção na ordem tentada pelo meu intérprete é
aaaiaa
, que na primeira etapa define oa
registro como 0 (o que já era), e na segunda e em todas as etapas seguintes, o ponteiro da instrução volta para 0, fazendo com que seja executadoiaa
novamente.Reutilizei parte do código escrito para o meu intérprete de roxo "padrão" , mas, devido à remoção da entrada e saída, meu intérprete paralelo se torna um pouco mais curto que isso, incluindo a lógica adicional para executar vários programas ao mesmo tempo.
Aqui está uma versão comentada e formatada:
fonte
Cálculo do combinador SK em Haskell , 249 bytes
Experimente online!
Como funciona
As regras de avaliação de chamada por valor para o cálculo do combinador SK são as seguintes:
(a) S xyz ↦ xz ( yz ), para x , y , z em forma normal;
(b) K xy ↦ x , para x , y na forma normal;
(c) xy ↦ x ′ y , se x ↦ x ′;
(d) xy ↦ xy ′, para x na forma normal, se y ↦ y ' .
Como estamos interessados apenas em interromper o comportamento, expandimos um pouco a linguagem introduzindo um símbolo H que não está na forma normal, mas ao qual todas as formas normais “avaliam”:
(a) S xyz ↦ xz ( yz ), para x , y , z em forma normal;
(b ′) K x H ↦ x , para x na forma normal;
(c) xy ↦ x ′ y , se x ↦ x ′;
(d) xy ↦ xy ′, para x na forma normal, se y ↦ y ′ ;
(e) S = H;
(f) K = H;
(g) SH2H;
(h) KH = H;
i) SHH ↦ H.
Consideramos que qualquer aplicativo H x é um erro em tempo de execução a ser tratado como se fosse um loop infinito, e ordenamos avaliações para que nenhum H seja produzido por (e) - (i), exceto em um contexto em que será ignorado (nível superior, qualquer K x ☐ , qualquer K x ignorado, qualquer S x ☐ ignorado por x na forma normal, qualquer S☐H ignorado). Dessa forma, não afetamos o comportamento de interrupção dos termos usuais que faltam H.
Os benefícios dessas regras modificadas são que todo termo normalizável possui um caminho de avaliação exclusivo para H e que todo termo tem um número finito de possíveis pré-imagens em ↦. Portanto, em vez de usar a abordagem de encaixe, podemos fazer uma pesquisa abrangente muito mais eficiente de todos os caminhos de avaliação reversa de H.
n
verifica se um termo está na forma normal,f
encontra todas as pré-imagens possíveis de um termo el
é uma lista infinita e preguiçosa de termos normalizáveis produzidos pela pesquisa pela primeira vez em H.fonte