O tópico do desafio dos ladrões está aqui .
Desafio da polícia: crie uma linguagem de programação que pareça inutilizável para a programação, mas que admita a computação (ou pelo menos a conclusão da tarefa) por meio de algum mecanismo não óbvio.
Você deve criar uma linguagem de programação simples que leia o código de um arquivo de entrada e faça ... alguma coisa. Você deve preparar um programa de solução que encontre o terceiro maior número na entrada quando executado no seu intérprete. Você precisa dificultar o máximo possível para que os ladrões encontrem um programa de solução. Observe que os ladrões podem postar qualquer solução que realize a tarefa, não apenas a que você tinha em mente.
Este é um concurso de popularidade. O objetivo da polícia é obter o maior número possível de votos enquanto sobrevive 8 dias após a publicação do intérprete sem ser quebrado. Para esse fim, as seguintes práticas devem ajudar:
- Explicando com precisão a semântica do seu idioma
- Escrevendo código legível
As seguintes táticas são fortemente desencorajadas:
- Usando criptografia, hashes ou outros métodos criptográficos. Se você vir um idioma que emprega criptografia RSA ou se recusa a executar um programa, a menos que seu hash SHA-3 seja igual a 0x1936206392306, não hesite em votar novamente.
Desafio dos assaltantes: escreva um programa que encontre o terceiro maior número inteiro na entrada quando executado no intérprete da polícia.
Este é relativamente direto. Para obter uma resposta de policial, você deve criar um programa que conclua a tarefa quando executado em seu intérprete. Quando você quebrar uma resposta, poste um comentário dizendo "Rachado" na resposta do policial com link para sua postagem. Quem quebrar mais policiais ganha o fio dos assaltantes.
Regras de E / S
- Os intérpretes devem colocar um nome de arquivo na linha de comando do programa e usar entrada e saída padrão ao executá-lo.
- A entrada será dada em unário e consistirá apenas dos caracteres
0
e1
(48 e 49 em ASCII). Um número N é codificado como N1s
seguido por a0
. Há um adicional0
antes do final do arquivo. Exemplo: Para a sequência (3, 3, 1, 14), a entrada é11101110101111111111111100
. - A entrada é garantida para ter pelo menos 3 números. Todos os números são números inteiros positivos.
- A saída será julgada pelo número de
1
s impressos antes que o programa pare. Outros caracteres são ignorados.
Nos exemplos a seguir, a primeira linha é a entrada no formato decimal; o segundo é a entrada real do programa; o terceiro é uma amostra de saída.
1, 1, 3
101011100
1
15, 18, 7, 2, 15, 12, 3, 1, 7, 17, 2, 13, 6, 8, 17, 7, 15, 11, 17, 2
111111111111111011111111111111111101111111011011111111111111101111111111110111010111111101111111111111111101101111111111111011111101111111101111111111111111101111111011111111111111101111111111101111111111111111101100
111111,ir23j11111111111u
247, 367, 863, 773, 808, 614, 2
<omitted>
<contains 773 1's>
Regras chatas para respostas policiais:
- Para evitar a segurança através da obscuridade, o intérprete deve ser escrito em um idioma entre os 100 principais deste índice TIOBE e ter um compilador / intérprete disponível gratuitamente.
- O intérprete não deve interpretar um idioma que foi publicado antes deste desafio.
- O intérprete deve caber na sua postagem e não ser hospedado externamente.
- O intérprete deve ser determinístico
- O intérprete deve ser portátil e seguir o padrão de seu próprio idioma; não use comportamento indefinido ou bugs
- Se o programa de solução for muito longo para caber na resposta, você deverá postar um programa que o gere.
- O programa de solução deve consistir apenas em ASCII e novas linhas imprimíveis.
- Você deve executar seu programa de solução em menos de 1 hora em seu próprio computador para cada uma das entradas de exemplo acima.
- O programa deve funcionar com números inteiros menores que 10 6 e qualquer número inteiro com menos de 10 6 (não necessariamente em menos de uma hora), desde que o comprimento total da entrada seja menor que 10 9 .
- Para se tornar seguro, um policial deve editar o programa de solução na resposta após oito dias.
Pontuação
O policial que se torna seguro com a pontuação mais alta e uma pontuação positiva, ganha essa pergunta.
Respostas:
Changeling (seguro)
ShapeScript
O ShapeScript é uma linguagem de programação que ocorre naturalmente. Os shifters de forma (ou Changelings , como preferem ser chamados) podem se transformar em um conjunto de instruções que lhes permite processar dados.
O ShapeScript é uma linguagem baseada em pilha com uma sintaxe relativamente simples. Não é de surpreender que a maioria dos seus built-ins lide com a alteração do formato das cordas. É interpretado, caractere por caractere, da seguinte maneira:
'
e"
comece uma string literal.Até que a citação correspondente seja encontrada no código-fonte, todos os caracteres entre essas aspas correspondentes são coletados em uma sequência, que é empurrada na pilha.
0
para9
empurrar os números inteiros de 0 a 9 na pilha. Observe que10
empurra dois números inteiros.!
aparece uma string da pilha e tenta avaliá-la como ShapeScript.?
exibe um número inteiro da pilha e empurra uma cópia do item da pilha nesse índice.O índice 0 corresponde ao item da pilha mais acima (LIFO) e o índice -1 ao mais abaixo.
_
aparece um iterável da pilha e aumenta seu comprimento.@
aparece dois itens da pilha e os empurra em ordem inversa.$
aparece duas cordas da pilha e divide a mais baixa nas ocorrências da mais alta. A lista resultante é enviada em retorno.&
aparece uma sequência (superior) e uma iterável da pilha e junta-se à iterável, usando a sequência como separador. A sequência resultante é pressionada em troca.Se o ShapeScript for usado em nosso planeta, já que os pythons são os parentes mais próximos do Changelings na Terra, todos os outros caracteres c exibem dois itens x e y (acima) da pilha e tentam avaliar o código Python
x c y
.Por exemplo, a sequência de caracteres
23+
seria avaliada2+3
, enquanto a sequência de caracteres"one"3*
seria avaliada'one'*3
e a sequência de caracteres1''A
seria avaliada1A''
.No último caso, como o resultado não é válido em Python, o Changeling reclamaria que sua forma atual não é proposital (erro de sintaxe), pois não é válido para o ShapeScript.
Antes de executar o código, o intérprete colocará toda a entrada do usuário na forma de uma sequência na pilha. Após executar o código fonte, o intérprete imprimirá todos os itens na pilha. Se alguma parte do meio falhar, o Changeling reclamará que sua forma atual é inadequada (erro de execução).
Mudança de forma
Em seu estado natural, os Changelings não assumem a forma do ShapeScript. No entanto, alguns deles podem se transformar em um código-fonte em potencial (o que não é necessariamente útil ou mesmo sintaticamente válido).
Todos os Changelings elegíveis têm a seguinte forma natural:
Todas as linhas devem ter o mesmo número de caracteres.
Todas as linhas devem consistir em caracteres ASCII imprimíveis, seguidos por um único avanço de linha.
O número de linhas deve corresponder ao número de caracteres imprimíveis por linha.
Por exemplo, a sequência de bytes
ab\ncd\n
é um Changeling elegível.Na tentativa de mudar para o ShapeScript, o Changeling passa pela seguinte transformação:
Inicialmente, não há código fonte.
Para cada linha, acontece o seguinte:
O acumulador do Changeling está definido como zero.
Para cada caractere c da linha (incluindo o avanço de linha à direita), o ponto de código de c é XORed com o acumulador dividido por 2, e o caractere Unicode que corresponde ao ponto de código resultante é anexado ao código-fonte.
Depois, a diferença entre o ponto de código de c e o ponto de código de um espaço (32) é adicionada ao acumulador.
Se alguma das partes acima falhar, o Changeling reclamará que sua forma atual é desagradável.
Depois que todas as linhas foram processadas, a transformação do Changeling em (possivelmente válido) ShapeScript está concluída e o código resultante é executado.
Solução (ShapeScript)
O ShapeScript acabou sendo bastante utilizável; ele pode até executar testes de primalidade ( prova ) e, portanto, satisfaz nossa definição de linguagem de programação.
Publiquei novamente o ShapeScript no GitHub , com uma sintaxe ligeiramente modificada e uma E / S melhor.
O código faz o seguinte:
Solução (Changeling)
Como todos os programas Changeling, esse código possui um avanço de linha à direita.
O ShapeScript cometerá um erro imediato em qualquer caractere que não entenda, mas podemos enviar seqüências de caracteres arbitrárias como preenchimentos e colocá-las mais tarde. Isso nos permite colocar apenas uma pequena quantidade de código em cada linha (no início, onde o acumulador é pequeno), seguido por uma abertura
"
. Se começarmos a próxima linha com"#
, fechamos e pop a string sem afetar o código real.Além disso, temos que superar três obstáculos menores:
A cadeia longa no código ShapeScript é um único token e não poderemos ajustá-lo em uma linha.
Vamos empurrar esta string em pedaços (
'@'
,'1?'
, etc.), o que vamos concatenar mais tarde.O ponto de código de
_
é bastante alto e o envio'_'
será problemático.No entanto, poderemos avançar
'_@'
sem esforço, seguidos por outro'@'
para desfazer a troca.O código ShapeScript que nosso Changeling gerará se parece com este 1 :
Encontrei o código Changeling executando o código ShapeScript acima através deste conversor . 2
Intérprete (Python 3)
1 Cada linha é preenchida com lixo aleatório para a quantidade de linhas e os feeds de linha não estão realmente presentes.
2 Os números na parte inferior indicam o ponto mais baixo e mais alto do código Changeling, que deve permanecer entre 32 e 126.
fonte
0"#002?'+'&'0'$'0?2?-@2?>*+00'&!++'1'*'0'+@1?$0?''&@_2-2?*@+@"3*!@#
. Desisti de encontrar um Changeling para ele, no entanto. Mesmo intercaladas com declarações principalmente inúteis, eu não tenho sido capaz de obter mais de 20 bytes no.Aleatório (escrito em C ++), Rachado! por Martin
Editar Martin quebrou. Para ver a solução dele, clique no link. Minha solução também foi adicionada.
Editar Comando fixo
print-d
para poder lidar com registros e pilhas. Como este é um comando de depuração que não é permitido em uma solução, isso não deve afetar ninguém que esteja usando a versão anterior do intérpreteAinda sou novo nisso; se houver algo errado com minha resposta ou meu intérprete, entre em contato. Por favor, peça esclarecimentos se algo não estiver claro.
Não imagino que isso seja terrivelmente difícil, mas espero que isso traga algum tipo de desafio. O que torna a reprodução aleatória bastante inutilizável é que ela será impressa apenas quando as coisas estiverem no seu devido lugar.
-> Noções básicas:
Existem 24 pilhas, como as chamamos
stack1, ... stack24
. Essas pilhas vivem em uma lista. No início de qualquer programa, essas pilhas têm zero empurrado e começam no seu devido lugar, ou seja, empilham i na i - ésima posição na lista (Observe que indexaremos a partir de 1, diferentemente do C ++). Durante o curso de um programa, a ordem das pilhas na lista mudará. Isso é importante por razões que serão explicadas quando eu discutir os comandos.Existem 5 registros disponíveis para uso. Eles são nomeados
Alberto
,Gertrude
,Hans
,Leopold
,ShabbySam
. Cada um deles é definido como zero no início de um programa.Portanto, no início de qualquer programa, existem 24 pilhas, cada uma com seu número correspondente ao seu índice na lista de pilhas. Cada pilha tem exatamente um zero no topo. Cada um dos cinco registros é inicializado em zero.
-> Comandos e sintaxe :
Existem 13 comandos (comando de depuração +1) disponíveis no Shuffle. Eles são os seguintes
cinpush
este comando não aceita argumentos. Ele espera pela entrada da linha de comando da maneira descrita na pergunta (outra entrada levará a resultados não especificados / indefinidos). Em seguida, divide a sequência de entrada em números inteiros, por exemplo101011100
- ->1,1,3
. Para cada entrada recebida, é feito o seguinte: (1) permite a lista de pilhas com base no valor. Seja o valor inteiro em questão chamado a . Se a for menor que 10, permutará u . Se a estiver entre 9 e 30 (não inclusivo), ele fará a permutação d . Caso contrário, ele faz permutação r . (2) Em seguida, empurra umna pilha que é a primeira da lista. Note que não estou falando sériostack1
(embora possa ser ostack1
primeiro da lista). As permutações são definidas abaixo. Comocinpush
é a única maneira de obter a entrada do usuário , ela deve aparecer em qualquer solução.mov value register
Omov
comando é basicamente atribuição de variáveis. Ele atribuivalue
aregister
.value
pode assumir várias formas: pode ser (1) um inteiro, por exemplo47
(2) o nome de um registro diferente, por exemploHans
(3) o índice de uma pilha seguido por 's', por exemplo4s
. Observe que este é o índice da lista, não o número da pilha. Como tal, o número não deve exceder 24.Alguns
mov
exemplos:movfs index register
Isso significa 'mover da pilha'. É semelhante aomov
comando. Existe para que você possa acessar uma pilha indexada por um registro. Por exemplo, se você definiu Hans como 4 (mov 4 Hans
) anteriormente, você podemovfs Hans Gertrude
definir Gertrude como o topo da pilha 4. Esse tipo de comportamento não pode ser acessado simplesmente usandomov
.inc register
aumenta o valor do registro em 1.dec register
diminui o valor do registro em 1.compg value value register
Isso significa 'comparar maior'. Ele define o registro igual ao maior dos dois valores.value
pode ser um número inteiro, um registro ou um índice de pilha seguido por 's', como acima.compl value value register
'compare menor' o mesmo que acima, exceto que assume o valor menor.gte value1 value2 register
Verifica se, emvalue1 >= value2
seguida, coloca o valor booleano (como 1 ou 0)register
.POP!! index
aparece na parte superior da pilha indexadaindex
na lista de pilhas.jmp label
pula incondicionalmente para o rótulolabel
. É um bom momento para conversar sobre rótulos. Um rótulo é uma palavra seguida por ':'. O intérprete analisa previamente os rótulos, para que você possa avançar para os rótulos e também para trás.jz value label
pula paralabel
sevalue
for zero.jnz value label
pula paralabel
sevalue
for diferente de zero.Exemplos de etiquetas e saltos:
"shuffle" permutation
Aqui está o comando de reprodução aleatória. Isso permite que você permita a lista de pilhas. Há três permutações válidos que podem ser usados como argumentos,l
,f
, eb
.print register
Isso verifica se todas as pilhas estão em suas posições iniciais, ou seja, a pilha i está no índice i na lista de pilhas. Se for esse o caso, ele imprime o valorregister
em unário. Caso contrário, ele imprime um erro desagradável. Como você pode ver, para produzir qualquer coisa, todas as pilhas devem estar nos lugares corretos.done!
isso diz ao programa para sair sem erro. Se o programa terminar semdone!
, ele imprimirá no console o número na parte superior de cada pilha, seguido pelo número da pilha. A ordem em que as pilhas são impressas é a ordem em que aparecem na lista de pilhas. Se uma pilha estiver vazia, será omitida. Esse comportamento é para fins de depuração e não pode ser usado em uma solução.print-d value
isso imprime o valor da pilha, registrador ou número inteiro fornecido (para acessar a pilha i , passeis
como argumento, conforme explicado acima). Essa é uma ferramenta de depuração e não faz parte do idioma, portanto, não é permitida em uma solução.-> Aqui está o código do intérprete
Toda a análise acontece na função principal. É aqui que você encontrará a análise de comandos específicos.
-> Permutações As permutações permitem os elementos da lista de pilhas da seguinte maneira:
Onde significa que
(Eles também aparecem no código do intérprete. Se houver discrepância, o intérprete está correto.)
-> Exemplo Simples
Esses dois programas simples imprimem os números de 24 para 1 (em unário) sem espaço em branco.
ou
Eles são o mesmo programa.
Explicação e Solução:
Martin tem uma boa explicação em sua resposta também.
Como Martin descobriu, essa linguagem foi inspirada no cubo de bolso (também conhecido como cubo de Rubik 2x2). As 24 pilhas são como os 24 quadrados individuais no cubo. As permutações são os movimentos básicos permitidos: cima, baixo, direita, esquerda, frente, trás.
A principal luta aqui é que, quando os valores são pressionados, apenas três movimentos são usados: para cima, para baixo e para a direita. No entanto, você não tem acesso a esses movimentos ao "embaralhar" as pilhas. Você tem apenas os outros três movimentos.
Como se vê, os dois conjuntos de três jogadas abrangem todo o grupo (ou seja, são geradores), então o problema é solucionável. Isso significa que você pode realmente resolver qualquer cubo 2x2 de Rubik usando apenas 3 dos movimentos.
Tudo o que resta fazer é descobrir como desfazer os movimentos para cima, para baixo e para a direita usando os outros três. Para esse fim, empreguei um sistema de álgebra computacional chamado GAP .
Depois de desfazer as permutações, encontrar o terceiro maior número é bastante trivial.
fonte
Brian & Chuck , Rachado por paper_box
Há algum tempo, fico intrigado com a idéia de uma linguagem de programação em que dois programas interagem entre si (provavelmente inspirados no ROCB ). Esse desafio foi um bom incentivo para finalmente enfrentar esse conceito enquanto tentava manter o idioma o mínimo possível. Os objetivos do projeto eram tornar a linguagem Turing completa, enquanto cada uma de suas partes individualmente não era Turing completa. Além disso, mesmo os dois juntos não devem estar completos com Turing sem fazer uso da manipulação do código-fonte. Eu acho que eu já conseguiu com isso, mas eu não provaram nenhuma dessas coisas ainda formalmente. Então, sem mais delongas, apresento a você ...
Os Protagonistas
Brian e Chuck são dois programas parecidos com o Brainfuck. Apenas um deles está sendo executado a qualquer momento, começando com Brian. O problema é que a fita de memória de Brian também é o código fonte de Chuck. E a fita de memória de Chuck também é o código fonte de Brian. Além disso, a cabeça de fita de Brian também é o indicador de instruções de Chuck e vice-versa. As fitas são semi-infinitas (ou seja, infinitas para a direita) e podem conter números inteiros de precisão arbitrária, inicializados em zero (a menos que especificado de outra forma pelo código-fonte).
Como o código-fonte também é uma fita de memória, os comandos são tecnicamente definidos por valores inteiros, mas correspondem a caracteres razoáveis. Existem os seguintes comandos:
,
(44
): Leia um byte de STDIN na célula de memória atual. Apenas Brian pode fazer isso. Este comando é um no-op para Chuck..
(46
): Escreva a célula de memória atual, módulo 256, como um byte em STDOUT. Apenas Chuck pode fazer isso. Este comando é um no-op para Brian.+
(43
): Incrementa a célula de memória atual.-
(45
): Diminui a célula de memória atual.?
(63
): Se a célula de memória atual for zero, este é um modo não operacional. Caso contrário, passe o controle para o outro programa. A cabeça da fita no programa utilizado?
permanecerá no?
. O cabeçote de fita do outro programa moverá uma célula para a direita antes de executar o primeiro comando (para que a célula usada como teste não seja executada).<
(60
): Mova a cabeça da fita uma célula para a esquerda. Isso não funciona se a cabeça da fita já estiver na extremidade esquerda da fita.>
(62
): Mova a cabeça da fita uma célula para a direita.{
(123
): Mova repetidamente a cabeça da fita para a esquerda até que a célula atual seja zero ou a extremidade esquerda da fita seja atingida.}
(125
): Mova repetidamente a cabeça da fita para a direita até que a célula atual seja zero.O programa termina quando o ponteiro de instruções do programa ativo atinge um ponto em que não há mais instruções à sua direita.
O Código Fonte
O arquivo de origem é processado da seguinte maneira:
```
, ele será dividido em duas partes em torno da primeira ocorrência dessa string. Todo o espaço em branco à esquerda e à direita é removido e a primeira parte é usada como código-fonte para Brian e a segunda parte para Chuck._
ambos os programas são substituídas por bytes NULL.Como exemplo, o seguinte arquivo de origem
Produziria as seguintes fitas iniciais:
O intérprete
O intérprete está escrito em Ruby. São necessários dois sinalizadores de linha de comando que não devem ser usados por nenhuma solução (pois eles não fazem parte da especificação de idioma real):
-d
: Com esse sinalizador, Brian e Chuck entendem mais dois comandos.!
imprimirá uma representação de seqüência de caracteres de ambas as fitas de memória, sendo o programa ativo listado primeiro (a^
marcará as cabeças de fita atuais).@
também fará isso, mas, em seguida, encerre o programa imediatamente. Como sou preguiçoso, nenhum deles funcionará se for o último comando do programa; portanto, se você quiser usá-los lá, repita-os ou escreva um não-operacional depois deles.-D
: Este é o modo de depuração detalhado. Ele imprimirá as mesmas informações de depuração que!
após cada tick.@
também funciona neste modo.Aqui está o código:
Aqui está minha própria solução (manuscrita) para o problema:
Este código é executável como está, porque todas as anotações usam no-ops e são ignoradas por
{
e}
.A ideia básica é:
1
s, aumente esse elemento.Ao ler um
0
, faça uma limpeza. Se o número inteiro resultante for maior que zero, volte para 1.Agora temos uma lista dos números de entrada no final da fita de Chuck e sabemos o tamanho da lista.
Subtraia 2 do comprimento da lista (para que as etapas a seguir ignorem os dois maiores elementos), chame isso
N
.Enquanto
N > 0
, incremente um total em execução e, em seguida, diminua todos os elementos da lista. Sempre que um elemento da lista atingir zero, diminuaN
.No final, o total atual conterá o terceiro maior número na entrada
M
,.Escreva
M
cópias de.
para o final da fita de Chuck.1
na fita de Brian e execute os gerados.
no final.Depois de terminar isso, percebi que poderia simplificá-lo bastante em alguns lugares. Por exemplo, em vez de acompanhar esse contador e escrevê-los
.
na fita de Chuck, eu podia imprimir um1
imediatamente, cada vez antes de diminuir todos os elementos da lista. No entanto, fazer alterações nesse código é bastante trabalhoso, porque propaga outras alterações por todo o lugar, então não me incomodei em fazer a alteração.O interessante é como acompanhar a lista e como iterá-la. Você não pode simplesmente armazenar os números consecutivamente na fita de Chuck, porque, se quiser verificar uma condição em um dos elementos da lista, corre o risco de executar o restante da lista, que pode conter código válido. Você também não sabe quanto tempo a lista levará, portanto, não pode apenas reservar algum espaço na frente do código de Chuck.
O próximo problema é que precisamos deixar a lista diminuir
N
enquanto a processamos e precisamos voltar ao mesmo lugar em que estávamos antes. Mas{
e}
apenas pularia a lista inteira.Então, precisamos escrever algum código dinamicamente no Chuck. De fato, cada elemento da lista
i
tem o formato:1
é um marcador que podemos definir como zero para indicar onde deixamos de processar a lista. Seu objetivo é capturar{
ou}
que apenas repassará o código e oi
. Também usamos esse valor para verificar se estamos no final da lista durante o processamento; portanto, enquanto não estivermos, isso será1
e o condicional?
mudará o controle para Chuck.Code A
é usado para lidar com essa situação e mover o IP no Brian de acordo.Agora, quando diminuímos
i
, precisamos verificar sei
já é zero. Enquanto não estiver,?
alternará novamente o controle, entãoCode B
existe para lidar com isso.fonte
HPR, escrito em Python 3 ( Cracked by TheNumberOne )
HPR (o nome não significa nada) é um idioma para processar listas de números inteiros. Ele foi projetado para ser minimalista , extremamente limitado e livre de restrições "artificiais" . A programação no HPR é dolorosa, não porque você precise resolver um quebra-cabeça para impedir que o intérprete grite com você, mas porque é difícil fazer um programa fazer algo útil. Não sei se o HPR é capaz de algo substancialmente mais interessante do que computar o terceiro maior elemento de uma lista.
Especificação de idioma
Um programa HPR é executado em um ambiente , que é um conjunto não ordenado e livre de duplicados de números inteiros não negativos e listas de números inteiros não negativos. Inicialmente, o ambiente contém apenas a lista de entrada (o intérprete a analisa para você). Existem três comandos e dois operadores de "fluxo de controle" que modificam o ambiente:
*
remove o primeiro elemento de cada lista não vazia no ambiente e coloca-o no ambiente. Listas vazias não são afetadas. Por exemplo, ele transforma-
diminui todos os números no ambiente e remove elementos negativos. Por exemplo, ele transforma$
gira todas as listas do ambiente um passo para a esquerda. Por exemplo, ele transforma!(A)(B)
, ondeA
eB
são programas, é basicamente umwhile
loop. Ele executa a "ação"A
até que o "teste"B
resulte em um ambiente vazio. Isso pode produzir um loop infinito.#(A)(B)
, ondeA
e quaisB
são os programas, se aplicaA
eB
ao ambiente atual e leva a diferença simétrica dos resultados.Os comandos são executados da esquerda para a direita. No final, o tamanho do ambiente é impresso em unário.
O intérprete
Este intérprete apresenta o comando debug
?
, que imprime o ambiente sem modificá-lo. Não deve aparecer em nenhuma solução para a tarefa. Quaisquer caracteres exceto*-$!#()?
são simplesmente ignorados, para que você possa escrever comentários diretamente no código. Por fim, o intérprete reconhece o idioma!(A)(#(A)())
como "executarA
até que o resultado não seja mais alterado" e o otimiza para obter velocidade extra (eu precisava que minha solução fosse concluída em menos de uma hora no último caso de teste).Minha solução
Minha solução de referência tem 484 bytes, muito curta em comparação com o programa de 3271 bytes do TheNumberOne. Isso provavelmente ocorre devido ao sofisticado e impressionante sistema de macro que TheNumberOne desenvolveu para programação em HPR. A idéia principal em ambos os nossos programas é semelhante:
No entanto, até onde eu sei, os detalhes exatos da implementação são bem diferentes. Aqui está a minha solução:
E aqui está o programa Python comentado que o produz (nada sofisticado aqui, apenas manipulação básica de strings para se livrar de toda a repetição):
fonte
TKDYNS (para matar o dragão, você precisa de uma espada) - Rachado por Martin Büttner
EDIT: Adicionei minha solução e explicação abaixo da postagem principal.
fundo
Nesta linguagem, você assume o controle de um valente guerreiro que foi incumbido de matar um terrível dragão. O dragão vive em um labirinto subterrâneo, cheio de perigos e perigos, e até agora, ninguém foi capaz de mapear e sobreviver. Isso significa que você deve navegar até o dragão na escuridão total, com nada além de intuição e coragem para guiá-lo.
...
Bem, não exatamente. Você trouxe um suprimento quase ilimitado de lacaios descartáveis com você, e eles estão dispostos a ir além de você para descobrir o caminho seguro. Infelizmente, eles são todos grossos como duas tábuas curtas e só farão exatamente o que você manda. Cabe a você criar um método inteligente de garantir que seus lacaios descubram o caminho correto.
Mais alguns detalhes
O covil do dragão assume a forma de uma grade de 10x10. Entre certos pontos adjacentes na grade, há uma passagem estreita; entre outros, há um abismo profundo e uma morte certa. Um layout de exemplo para uma grade 4x4 pode ser o seguinte:
Você sabe que sempre existe uma maneira de ir de um ponto a outro, mas nada mais foi revelado a você.
Para derrotar o dragão com sucesso, você primeiro precisa coletar alguns itens que você poderá combinar para criar uma lâmina mágica de matar dragões. Convenientemente, todas as peças desta arma foram espalhadas pelo covil do dragão. Você simplesmente tem que colecioná-los.
A diferença é que cada peça da arma foi presa. Toda vez que uma é coletada, o layout das passarelas muda. Caminhos anteriormente seguros agora podem levar à morte certa e vice-versa.
Comandos
Existem apenas 5 comandos válidos.
<
- Dê um passo para a esquerda>
- Dê um passo à direita^
- Dê um passo para cimav
- Dê um passo para baixoc
- Colete todos os itens que estiverem na sua posição atual. Se houver itens presentes, o layout do covil muda. Com as posições numeradas nas linhas como acima, tome o módulo 10. da posição. Existem 10 layouts codificados no interpretador e o layout muda para o correspondente. Por exemplo, se você estiver na posição 13, o layout será alterado paralayouts[3]
Os layouts que aparecem no interpéter foram codificados para números inteiros da seguinte maneira:
O layout vazio é codificado para zero.
Para cada aresta no layout,
x
seja a menor das duas posições em que ela se une.Se a etapa for horizontal, adicione
2^(2*x)
à codificação (que é o poder, não o XOR)Se a etapa for vertical, adicione
2^(2*x + 1)
à codificação.Fluxo de execução
O intérprete é executado com o nome de um arquivo de origem como argumento da linha de comando.
Quando o intérprete é executado, ele solicita que o usuário forneça uma missão. Essa entrada deve estar na forma descrita na pergunta e determina os locais no esconderijo dos componentes da arma. Especificamente, cada número inteiro de entrada é obtido no módulo 100 e colocado no local correspondente no covil.
Cada programa de origem consiste em várias linhas, cada linha consiste em alguma sequência dos 5 caracteres válidos acima. Essas linhas representam seus lacaios. Você, o guerreiro, acompanha uma sequência de ações conhecidas por serem seguras. Inicialmente, você não sabe nada sobre o covil, então essa sequência está vazia. Tomando cada lacaio por sua vez, é realizado o seguinte, começando na posição 0:
O subordinado é instruído a executar todas as ações conhecidas como seguras, seguidas pelas ações em sua própria linha de código.
Se o lacaio morrer a qualquer momento, você será notificado e o covil será redefinido para sua configuração inicial. Todos os itens são substituídos e as passarelas retornam às suas posições iniciais.
Se, em vez disso, o lacaio sobreviver, então você o vaporiza de qualquer maneira - afinal, é apenas um lacaio. Como antes, isso aciona a redefinição do covil ao seu estado inicial, mas desta vez, você anexa as ações da linha de código do lacaio à sequência de ações conhecidas como seguras.
Depois que todos os lacaios estiverem exaustos, você, o guerreiro, executa todas as ações que são conhecidas por serem seguras, começando novamente na posição 0. Há dois resultados possíveis:
Você coleciona todas as peças da arma - nesse caso, você mata com sucesso o dragão e uma emocionante mensagem de vitória é emitida. Essa mensagem de vitória conterá, entre outros caracteres, um
n
, onden
é o terceiro número mais alto fornecido como entrada.Você falhou em coletar algumas das peças da arma - nesse caso, o dragão continua vivo e você falhou em sua missão.
Código de intérprete (Python 2)
Boa sorte, valente guerreiro.
Minha solução e explicação
Aqui está um script Python que gera código fonte para resolver o problema. Por interesse, o código fonte final de Martin é cerca de 5 vezes menor que o código produzido pelo meu script. Por outro lado, meu script para gerar o código é cerca de 15 vezes menor que o programa Mathematica de Martin ...
Estrutura básica
Isso gera 990 linhas de código fonte, que vêm em grupos de 10. As 10 primeiras linhas contêm instruções que tentam mover um lacaio de uma posição
0
para1
outra e, em seguida, coletam um item - um conjunto para cada layout possível. As próximas 10 linhas contêm instruções que tentam mover um lacaio de uma posição1
para2
outra e coletam um item. E assim por diante ... Esses caminhos são calculados com opath
função no script - apenas faz uma pesquisa simples e profunda.Se pudermos garantir que, em cada grupo de 10, precisamente um lacaio seja bem-sucedido, teremos resolvido o problema.
O problema com a abordagem
Pode não ser sempre o caso de exatamente um lacaio do grupo dos 10 ter sucesso - por exemplo, um lacaio projetado para ir de uma posição
0
para1
outra pode acidentalmente ter sucesso em mudar de posição1
em posição2
(devido a semelhanças nos layouts), e que um erro de cálculo será propagado, potencialmente causando falhas.Como corrigi-lo
A correção que eu usei foi a seguinte:
Para cada lacaio que está tentando passar da posição
n
paran+1
, primeiro faça-o andar de posiçãon
em posição0
(no canto superior esquerdo) e recuar novamente, depois de posiçãon
em posição99
(no canto inferior direito) e recuar. Essas instruções só podem ser executadas com segurança a partir da posiçãon
- qualquer outra posição inicial e o lacaio sairá da borda.Portanto, essas instruções extras impedem que lacaios acidentalmente cheguem a algum lugar que não deveriam, e isso garante que exatamente um lacaio de cada grupo de 10 seja bem-sucedido. Observe que não é necessariamente o lacaio que você espera que seja - pode ser que o lacaio que acredita que ele está no layout 0 seja bem-sucedido, mesmo quando estamos realmente no layout 7 - mas, de qualquer forma, o fato de termos A posição agora alterada significa que todos os outros subordinados do grupo necessariamente morrerão. Essas etapas extras são calculadas pela
assert_at
função e asafe_path
função retorna um caminho que é a concatenação dessas etapas extras com o caminho comum.fonte
Firetype, Rachado por Martin Büttner
Uma mistura muito estranha de BF e CJam. E quem sabe o que mais! Tenho certeza de que será fácil, mas foi divertido de qualquer maneira. Para sua informação, o nome está se referindo a Vermillion Fire do Final Fantasy Type-0 .
NOTA : Por favor, perdoe-me por quaisquer ambiguidades nesta descrição. Eu não sou o melhor escritor ...: O
Martin rachou isso muito rapidamente! Este foi o meu programa original para resolver o problema:
Sintaxe
Um script Firetype é basicamente uma lista de linhas. O primeiro caractere de cada linha é o comando a ser executado. Linhas vazias são basicamente NOPs.
Semântica
Você tem uma matriz de números inteiros e um ponteiro (pense em BF). Você pode mover os elementos para a esquerda e direita ou "empurrar" na matriz.
Empurrando
Quando você "pressiona" um elemento e está no final da matriz, um elemento extra será anexado ao final. Se você não estiver no final, o próximo elemento será substituído. Independentemente, o ponteiro será sempre incrementado.
Comandos
_
Empurre um zero na matriz.
+
Incremente o elemento no ponteiro atual.
-
Reduza o elemento no ponteiro atual.
*
Duplique o elemento no ponteiro atual.
/
Divida pela metade o elemento no ponteiro atual.
%
Pegue o elemento no ponteiro atual e pule para frente muitas linhas e mova o ponteiro para a esquerda. Se o valor for negativo, pule para trás.
=
Pegue o elemento no ponteiro atual e pule para a linha + 1. Por exemplo, se o elemento atual estiver
0
, ele irá pular para a linha1
. Isso também move o ponteiro para a esquerda.,
Leia um caractere da entrada padrão e empurre seu valor ASCII.
^
Pegue o elemento no ponteiro atual, interprete-o como o valor ASCII de um caractere e converta-o em um número inteiro. Por exemplo, se o valor atual for
49
(o valor ASCII de1
), o elemento no ponteiro atual será definido como o número inteiro1
..
Escreva o número atual na tela.
!
Pegue o elemento no ponteiro atual e repita a próxima linha várias vezes. Também move o ponteiro para a esquerda.
<
Mova o ponteiro para a esquerda. Se você já está no começo, um erro é gerado.
>
Mova o ponteiro para a direita. Se você já está no final, um erro é gerado.
~
Se o elemento atual for diferente de zero, substitua-o por
0
; caso contrário, substitua-o por1
.|
Esquadre o elemento atual.
@
Defina o elemento atual para o comprimento da matriz.
`
Duplique o elemento atual.
\
Classifique os elementos no e antes do ponteiro.
#
Negue o elemento atual.
O intérprete
Também disponível no Github .
fonte
self.ptr-1
acesso, provavelmenteself.ptr>0
não deve verificar>=0
. (Isto não deve invalidar quaisquer programas válidos, mas poderia fazer alguns programas de tornar o trabalho acidentalmente que não deveria.)=
define o valorarray() - 1
, a documentação diz+1
?Acc !! (seguro)
É baack ...
... e
espero quedefinitivamente mais à prova de brechas.Eu já li o Acc! spec. Como está o Acc !! diferente?
Em Acc !!, variáveis de loop ficam fora do escopo quando o loop sai. Você só pode usá-los dentro do loop. Lá fora, você receberá um erro "o nome não está definido". Fora essa alteração, os idiomas são idênticos.
Afirmações
Os comandos são analisados linha por linha. Existem três tipos de comando:
Count <var> while <cond>
Conta
<var>
desde 0, desde que<cond>
seja diferente de zero, equivalente a C ++for(int <var>=0; <cond>; <var>++)
. O contador de loop pode ser qualquer letra minúscula. A condição pode ser qualquer expressão, não necessariamente envolvendo a variável de loop. O loop é interrompido quando o valor da condição se torna 0.Os loops requerem chaves estilo K&R (em particular, a variante Stroustrup ):
Como mencionado acima, as variáveis de loop estão disponíveis apenas dentro de seus loops ; tentar referenciá-los posteriormente causa um erro.
Write <charcode>
Gera um único caractere com o valor ASCII / Unicode fornecido para stdout. O código pode ser qualquer expressão.
Qualquer expressão autônoma é avaliada e atribuída de volta ao acumulador (acessível como
_
). Assim, por exemplo,3
é uma declaração que define o acumulador como 3;_ + 1
incrementa o acumulador; e_ * N
lê um caractere e multiplica o acumulador por seu código.Nota: o acumulador é a única variável que pode ser atribuída diretamente; variáveis de loop e
N
pode ser usado em cálculos, mas não modificado.O acumulador é inicialmente 0.
Expressões
Uma expressão pode incluir literais inteiros, variáveis de loop (
a-z
),_
para o acumulador e o valor especialN
, que lê um caractere e avalia seu código de cada vez que é usado. Nota: isso significa que você só tem uma chance de ler cada personagem; da próxima vez que você usarN
, estará lendo a próxima.Os operadores são:
+
, Adição-
subtração; negação unária*
multiplicação/
divisão inteira%
módulo^
exponenciaçãoParênteses podem ser usados para reforçar a precedência das operações. Qualquer outro caractere em uma expressão é um erro de sintaxe.
Espaço em branco e comentários
Os espaços em branco à esquerda e à direita e as linhas vazias são ignorados. O espaço em branco nos cabeçalhos do loop deve ser exatamente como mostrado, com um único espaço entre o cabeçalho do loop e a chave de abertura também. O espaço em branco dentro das expressões é opcional.
#
inicia um comentário de linha única.Entrada / Saída
Acc !! espera uma única linha de caracteres como entrada. Cada caractere de entrada pode ser recuperado em seqüência e seu código processado usando
N
. Tentar ler além do último caractere da linha causa um erro. Um caractere pode ser emitido passando seu código para aWrite
instruçãoIntérprete
O intérprete (escrito em Python 3) traduz Acc !! código no Python e
exec
pronto.Solução
A queda do Acc original ! eram variáveis de loop que continuavam acessíveis fora de seus loops. Isso permitiu salvar cópias do acumulador, o que facilitou muito a solução.
Aqui, sem esse buraco de loop (desculpe), temos apenas o acumulador para armazenar coisas. Para resolver a tarefa, no entanto, precisamos armazenar quatro valores arbitrariamente grandes. 1 A solução: intercalar seus bits e armazenar o número de combinação resultante no acumulador. Por exemplo, um valor de acumulador de 6437 armazenaria os seguintes dados (usando o bit de menor ordem como um sinalizador de bit único):
Podemos acessar qualquer bit de qualquer número dividindo o acumulador pela potência apropriada de 2, mod 2. Isso também permite configurar ou inverter bits individuais.
No nível da macro, o algoritmo faz um loop sobre os números unários na entrada. Ele lê um valor no número 0 e, em seguida, passa o algoritmo de classificação de bolhas para colocá-lo na posição correta em comparação com os outros três números. Por fim, descarta o valor que resta no número 0, pois é o menor dos quatro agora e nunca pode ser o terceiro maior. Quando o loop termina, o número 1 é o terceiro maior, então descartamos os outros e o produzimos.
A parte mais difícil (e a razão pela qual tive variáveis de loop global na primeira encarnação) é comparar dois números para saber se é necessário trocá-los. Para comparar dois bits, podemos transformar uma tabela verdade em uma expressão matemática; meu avanço para Acc !! estava encontrando um algoritmo de comparação que procedia de bits de ordem baixa a alta, pois sem variáveis globais não há como fazer um loop sobre os bits de um número da esquerda para a direita. O bit de ordem mais baixa do acumulador armazena um sinalizador que indica se os dois números devem ser trocados atualmente em consideração.
Eu suspeito que Acc !! é Turing completo, mas não tenho certeza se quero me dar ao trabalho de provar isso.
Aqui está a minha solução com comentários:
1 De acordo com a especificação da pergunta, somente valores de até 1 milhão precisam ser suportados. Fico feliz que ninguém tenha aproveitado isso para uma solução mais fácil - embora não tenha muita certeza de como você faria as comparações.
fonte
Picofuck (seguro)
Picofuck é semelhante ao Smallfuck . Opera em uma fita binária que não está ligada à direita, encadernada à esquerda. Possui os seguintes comandos:
>
mova o ponteiro para a direita<
mova o ponteiro para a esquerda. Se o ponteiro cair da fita, o programa termina.*
virar a ponta do ponteiro(
se o bit no ponteiro estiver0
, pule para o próximo)
)
não faça nada - os parênteses em Picofuck sãoif
blocos, nãowhile
loops..
escreva para stdout o bit no ponteiro como um ascii0
ou1
.,
leia de stdin até encontrarmos um0
ou1
e armazene-o no bit no ponteiro.O código Picofuck é encerrado - uma vez que o final do programa é alcançado, ele continua desde o início.
Além disso, o Picofuck não permite parênteses aninhados. Os parênteses exibidos em um programa Picofuck devem alternar entre
(
e)
, começando com(
e terminando com)
.Intérprete
Escrito em Python 2.7
uso:
python picofuck.py <source_file>
Solução
O seguinte programa python 2.7 gera minha solução, que pode ser encontrada aqui
Posso editar este post mais tarde com uma explicação mais completa de como isso funciona, mas acontece que o Picofuck está completo em Turing.
fonte
PQRS - Seguro! / Solução fornecida
Fundamentos
Todas as instruções implícitas possuem quatro operandos de endereço de memória:
Onde
v
está o tamanho da memória em quartetos.Pᵢ
,Qᵢ
,Rᵢ
,Sᵢ
Estão inteiros em tamanho nativo da sua máquina assinado (por exemplo, 64 bits 16, 32 ou) que nós referimos como palavras.Para cada quarteto
i
, a operação implícita, com[]
denotação indireta, é:Observe que Subleq é um subconjunto do PQRS .
O Subleq foi provado completo, portanto o PQRS também deve estar completo!
Estrutura do Programa
O PQRS define um cabeçalho inicial da seguinte maneira:
H₀ H₁ H₂ H₃
é sempre a primeira instruçãoP₀ Q₀ R₀ S₀
.H₀
aoH₃
precisam ser definidos no momento do carregamento.O PQRS possui E / S rudimentares, mas suficiente para o desafio.
H₄ H₅
: no início do programa, lê no máximoH₅
caracteres ASCII a partir da entrada padrão e salva como palavras no índice emH₄
diante.H₄
eH₅
precisa ser definido no momento do carregamento. Após a leitura,H₅
será definido o número de caracteres lidos (e as palavras salvas).H₆ H₇
: no encerramento do programa, iniciando no índiceH₆
, imprime todos os bytes que compõem asH₇
palavras na saída padrão como caracteres ASCII.H₆
eH₇
precisa ser definido antes do término do programa. Os bytes nulos'\0'
na saída serão ignorados.Terminação
A rescisão é alcançada estabelecendo
Sᵢ
fora dos limitesi < 0
oui ≥ v
.Truques
Os quartetos
Pᵢ Qᵢ Rᵢ Sᵢ
não precisam ser alinhados ou seqüenciais; a ramificação é permitida em intervalos de sub-quarteto.O PQRS tem indireção, portanto, diferentemente do Subleq, há flexibilidade suficiente para implementar sub-rotinas.
O código pode ser auto-modificável!
Intérprete
O intérprete está escrito em C:
Para usar, salve o acima como pqrs.c e compile:
Programa de exemplo
O Echos insere até 40 caracteres, precedido por 'PQRS-'.
Para executar, salve as opções acima como
echo.pqrs
:Executando os casos de teste:
Todos os casos de teste são executados com extrema rapidez, por exemplo, <500 ms.
O desafio
O PQRS pode ser considerado estável; portanto, o desafio começa em 31/10/2015 às 13:00 e termina em 08/11/2015 às 13:00, horário em UTC.
Boa sorte!
Solução
A linguagem é bastante semelhante à usada em "Baby" - a primeira máquina digital eletrônica de programa armazenado do mundo. Nessa página, há um programa para encontrar o fator mais alto de um número inteiro em menos de 32 palavras da memória (CRT!)!
Descobri que escrever a solução em conformidade com as especificações não era compatível com o sistema operacional e a máquina que eu estava usando (um derivado do Linux Ubuntu em hardware um pouco mais antigo). Ele estava apenas solicitando mais memória do que o disponível e o core dumping. Em sistemas operacionais com gerenciamento avançado de memória virtual ou máquinas com pelo menos 8 GB de memória, provavelmente você pode executar a solução por especificações. Eu forneci as duas soluções.
É muito difícil codificar diretamente no PQRS , como escrever linguagem de máquina, talvez até microcódigo. Em vez disso, é mais fácil escrever em um tipo de linguagem assembly do que "compilá-lo". Abaixo está a linguagem assembly anotada para a solução otimizada para executar os casos de teste:
O que ele faz é analisar a entrada, convertendo unário em binário, depois uma classificação de bolha nos números com os valores em ordem decrescente e, finalmente, gera o terceiro maior valor convertendo binário novamente em unário.
Observe que
INC
(incremento) é negativo eDEC
(decremento) é positivo! Onde ele está usandoL#
ouL#+1
comoP-
ouQ-OP
s, o que está acontecendo é que ele está atualizando ponteiros: incrementando, decrementando, trocando etc. O montador foi compilado manualmente no PQRS , substituindo os rótulos pelos deslocamentos. Abaixo está a solução otimizada para PQRS :O código acima pode ser salvo
challenge-optimized.pqrs
para executar os casos de teste.Para completar, aqui está a fonte por especificações:
E solução:
Para executar o acima, você vai precisar para comentar
#define OPTIMIZED
e adicionar#define PER_SPECS
empqrs.c
e recompilar.Este foi um grande desafio - gostei muito do treino mental! Me levou de volta aos meus velhos dias de montagem 6502 ...
Se eu fosse implementar o PQRS como uma linguagem de programação "real", provavelmente adicionaria modos adicionais para acesso direto e duplamente indireto, além do acesso indireto, bem como posição relativa e posição absoluta, ambas com opções de acesso indireto para a ramificação!
fonte
Zinco, rachado! por @Zgarb
Também disponível no GitHub .
Você precisa do Dart 1.12 e do Pub. Apenas corra
pub get
para baixar a única dependência, uma biblioteca de análise.Aqui está a esperança de que este dure mais de 30 minutos! : O
O idioma
O zinco é orientado para redefinir os operadores. Você pode redefinir todos os operadores no idioma facilmente!
A estrutura de um programa típico de zinco se parece com:
Existem apenas dois tipos de dados: números inteiros e conjuntos. Não existe um conjunto literal e conjuntos vazios não são permitidos.
Expressões
A seguir, expressões válidas no Zinc:
Literais
O zinco suporta todos os literais inteiros normais, como
1
e-2
.Variáveis
O zinco tem variáveis (como a maioria dos idiomas). Para referenciá-los, basta usar o nome Mais uma vez, como a maioria dos idiomas!
No entanto, existe uma variável especial chamada
S
que se comporta como a de PythQ
. Quando você o usa pela primeira vez, ele lê uma linha da entrada padrão e a interpreta como um conjunto de números. Por exemplo, a linha de entrada1234231
se transformaria no conjunto{1, 2, 3, 4, 3, 2, 1}
.NOTA IMPORTANTE!!!Em alguns casos, um literal no final de uma substituição de operador é analisado incorretamente, portanto, você deve colocá-lo entre parênteses.
Operações binárias
As seguintes operações binárias são suportadas:
+
:1+1
.-
:1-1
.*
:2*2
./
:4/2
.=
:3=3
.Além disso, a seguinte operação unária também é suportada:
#
:#x
.A precedência é sempre associativa correta. Você pode usar parênteses para substituir isso.
Somente a igualdade e o comprimento funcionam nos sets. Quando você tenta obter o comprimento de um número inteiro, obtém o número de dígitos em sua representação de seqüência de caracteres.
Definir compreensões
Para manipular conjuntos, o zinco definiu suas compreensões. Eles se parecem com isso:
Uma cláusula é uma cláusula when ou uma cláusula de classificação.
A cláusula when se parece
^<expression>
. A expressão após o sinal de intercalação deve resultar em um número inteiro. O uso da cláusula when utilizará apenas os elementos do conjunto queexpression
não sejam zero. Dentro da expressão, a variável_
será configurada para o índice atual no conjunto. É aproximadamente equivalente a este Python:Uma cláusula de classificação , que parece
$<expression>
, classifica o conjunto decrescente pelo valor de<expression>
. É igual a este Python:Aqui estão alguns exemplos de compreensão:
Pegue apenas os elementos do conjunto
s
que são iguais a 5:Classifique o conjunto
s
pelo valor se seus elementos ao quadrado:Substituições
As substituições de operador permitem redefinir os operadores. Eles se parecem com isso:
ou:
No primeiro caso, você pode definir um operador para igualar outro operador. Por exemplo, eu posso definir
+
para realmente subtrair via:Ao fazer isso, você pode redefinir um operador para ser um operador mágico . Existem dois operadores mágicos:
join
pega um conjunto e um número inteiro e une o conteúdo do conjunto. Por exemplo, ingressar{1, 2, 3}
com4
resultará no número inteiro14243
.cut
também pega um conjunto e um número inteiro e particionará o conjunto a cada ocorrência do número inteiro. Usandocut
on{1, 3, 9, 4, 3, 2}
e3
criará{{1}, {9, 4}, {2}}
... MAS qualquer conjunto de elemento único é achatado, portanto o resultado será realmente{1, {9, 4}, 2}
.Aqui está um exemplo que redefine o
+
operador para significarjoin
:Para o último caso, você pode redefinir um operador para a expressão fornecida. Como exemplo, isso define a operação mais para adicionar os valores e, em seguida, adicionar 1:
Mas o que é
+:
? Você pode anexar os dois pontos:
a um operador para sempre usar a versão interna. Este exemplo usa o+
via interno+:
para adicionar os números e, em seguida, adiciona um 1 (lembre-se, tudo é associativo à direita).A substituição do operador de comprimento se parece com:
Observe que quase todas as operações internas (exceto a igualdade) usarão esse operador de comprimento para determinar o comprimento do conjunto. Se você definiu para ser:
toda parte do zinco que trabalha em conjuntos, exceto
=
, operaria apenas no primeiro elemento do conjunto que foi dado.Várias substituições
Você pode substituir vários operadores, separando-os com vírgulas:
Impressão
Você não pode imprimir diretamente nada em zinco. O resultado da expressão a seguir
in
será impresso. Os valores de um conjunto serão concatenados com o separador. Por exemplo, considere o seguinte:Se
expr
for o conjunto{1, 3, {2, 4}}
,1324
será impresso na tela assim que o programa terminar.Juntando tudo
Aqui está um programa simples de zinco que parece adicionar,
2+2
mas faz com que o resultado seja 5:O intérprete
Isso entra em
bin/zinc.dart
:E isso entra
pubspec.yaml
:Solução pretendida
fonte
join
conjunto misto{1,{3,2}}
, haverá um erro? Não consigo instalar o Dart agora, então não consigo me controlar.dart bin/zinc.dart test.znc
, recebo um erro de sintaxe:'file:///D:/Development/languages/zinc/bin/zinc.dart': error: line 323 pos 41: unexpected token '?'
...var input = stdin.readLineSync() ?? '';
-2+#:S
quando determinadoS
, o que cortou os dois zeros à direita. Era assim que eu esperava que fosse resolvido. E^
não é suposto para reverter o conjunto ... que foi um erro ...Sopa de bússola ( rachada por caixa de papelão )
Intérprete: C ++
A sopa de bússola é como uma máquina de Turing com uma fita bidimensional infinita. O principal problema é que a memória de instruções e a memória de dados estão no mesmo espaço, e a saída do programa é todo o conteúdo desse espaço.
Como funciona
Um programa é um bloco de texto bidimensional. O espaço do programa começa com todo o código-fonte colocado com o primeiro caractere em (0,0). O restante do espaço do programa é infinito e é inicializado com caracteres nulos (ASCII 0).
Existem dois ponteiros que podem se mover pelo espaço do programa:
!
caractere ou em (0,0) se isso não existir.x
,X
,y
, eY
. Começa na localização do@
personagem ou em (0,0) se isso não existir.Entrada
O conteúdo do stdin é impresso no espaço do programa, começando no local do
>
caractere ou em (0,0), se isso não existir.Resultado
O programa termina quando o ponteiro de execução é executado irremediavelmente fora dos limites. A saída é todo o conteúdo do espaço do programa naquele momento. É enviado para stdout e 'result.txt'.
Instruções
n
- redireciona o ponteiro de execução para o norte (y negativo)e
- redireciona o ponteiro de execução para o leste (x positivo)s
- redireciona o ponteiro de execução para o sul (positivo y)w
- redireciona o ponteiro de execução para oeste (x negativo)y
- move o ponteiro de dados para o norte (y negativo)X
- move o ponteiro de dados para o leste (x positivo)Y
- move o ponteiro de dados para o sul (y positivo)x
- move o ponteiro de dados para oeste (x negativo)p
- escreve o próximo caractere encontrado pelo ponteiro de execução no ponteiro de dados. Esse personagem não é executado como uma instrução.j
- verifica o próximo caractere encontrado pelo ponteiro de execução contra o caractere abaixo do ponteiro de dados. Esse personagem não é executado como uma instrução. Se eles são iguais, o ponteiro de execução pula sobre o próximo caractere.c
- escreve o caractere nulo no ponteiro de dados.*
- breakpoint - apenas faz com que o intérprete se quebre.Todos os outros caracteres são ignorados pelo ponteiro de execução.
Intérprete
O intérprete toma o arquivo de origem como argumento e insere stdin. Ele possui um depurador escalonável, que você pode chamar com uma instrução de ponto de interrupção no código (
*
). Quando quebrado, o ponteiro de execução é mostrado como ASCII 178 (bloco sombreado mais escuro) e o ponteiro de dados é mostrado como ASCII 177 (bloco sombreado mais claro).Exemplos
Olá Mundo
Gato
Paridade: aceita uma sequência de caracteres terminada por um zero ('0'). Saídas
yes
na primeira linha da saída, se o número de 1s na entrada for ímpar, caso contrário, será emitido|
.Dicas
Você deve usar um bom editor de texto e fazer uso criterioso da funcionalidade da tecla 'Inserir' e usar 'Alt-Drag' para adicionar ou excluir texto em várias linhas ao mesmo tempo.
Solução
Aqui está a minha solução. Não é tão bom quanto o da caixa de papelão, porque eu tive que fazer com que o código fonte se excluísse. Eu também esperava encontrar uma maneira de excluir todo o código e deixar apenas a resposta, mas não consegui.
Minha abordagem foi dividir as diferentes seqüências de
1
s em linhas diferentes, depois classificá-las fazendo com que1
todos "caíssem" até que atingissem outra1
e, finalmente, apagassem tudo, exceto a terceira linha após a entrada.#A#
leituras se1
copia para a última linha da divisão até que a0
seja lida.#B#
verifica por um segundo0
e vai para o norte, chegando a#D#
um. Caso contrário,#C#
inicia uma nova linha de divisão colocando|
após a última e volta para#A#
.#F#
é o código de gravidade. Ele caminha até a última1
da primeira linha e a move até atingir1
ou-
. Se não puder fazer isso, marca a linha como concluída, colocando-a+
antes dela.#G#
está apagando todas as divisões desnecessárias e#H#
está apagando stdin e todo o código entre parênteses.Código:
fonte
c
no começo que não deveria estar lá. Eu consertei isso. Também adicionei minha solução ao problema.Acc! , Cracc'd por ppperry
Essa linguagem possui uma estrutura em loop, matemática básica básica, E / S de caracteres e um acumulador (portanto, o nome). Apenas um acumulador. Assim, o nome.
Afirmações
Os comandos são analisados linha por linha. Existem três tipos de comando:
Count <var> while <cond>
Contagens
<var>
acima de 0, desde que<cond>
é diferente de zero, o que equivale a C-estilofor(<var>=0; <cond>; <var>++)
. O contador de loop pode ser qualquer letra minúscula. A condição pode ser qualquer expressão, não necessariamente envolvendo a variável de loop. O loop é interrompido quando o valor da condição se torna 0.Os loops requerem chaves estilo K&R (em particular, a variante Stroustrup ):
Write <charcode>
Gera um único caractere com o valor ASCII / Unicode fornecido para stdout. O código pode ser qualquer expressão.
Qualquer expressão autônoma é avaliada e atribuída de volta ao acumulador (acessível como
_
). Assim, por exemplo,3
é uma declaração que define o acumulador como 3;_ + 1
incrementa o acumulador; e_ * N
lê um caractere e multiplica o acumulador por seu código.Nota: o acumulador é a única variável que pode ser atribuída diretamente; variáveis de loop e
N
pode ser usado em cálculos, mas não modificado.O acumulador é inicialmente 0.
Expressões
Uma expressão pode incluir literais inteiros, variáveis de loop (
a-z
),_
para o acumulador e o valor especialN
, que lê um caractere e avalia seu código de cada vez que é usado. Nota: isso significa que você só tem uma chance de ler cada personagem; da próxima vez que você usarN
, estará lendo a próxima.Os operadores são:
+
, Adição-
subtração; negação unária*
multiplicação/
divisão inteira%
módulo^
exponenciaçãoParênteses podem ser usados para reforçar a precedência das operações. Qualquer outro caractere em uma expressão é um erro de sintaxe.
Espaço em branco e comentários
Os espaços em branco à esquerda e à direita e as linhas vazias são ignorados. O espaço em branco nos cabeçalhos do loop deve ser exatamente como mostrado, com um único espaço entre o cabeçalho do loop e a chave de abertura também. O espaço em branco dentro das expressões é opcional.
#
inicia um comentário de linha única.Entrada / Saída
Acc! espera uma única linha de caracteres como entrada. Cada caractere de entrada pode ser recuperado em seqüência e seu código processado usando
N
. Tentar ler além do último caractere da linha causa um erro. Um caractere pode ser emitido passando seu código para aWrite
instruçãoIntérprete
O intérprete (escrito em Python 3) traduz o Acc! código no Python e
exec
pronto.fonte
GoToTape (Seguro)
(Anteriormente conhecido como Simp-plex.)
Essa linguagem é simples. O principal controle de fluxo é o goto, a forma mais natural e útil de controle.
Especificação de idioma
Os dados são armazenados em uma fita e em um acumulador. Funciona inteiramente com integrações não assinadas. Cada caractere é comando. A seguir estão todos os comandos:
a
-z
são declarações goto, indo paraA
-Z
, respectivamente.:
: defina o acumulador com o valor ASCII para char da entrada.~
: gera o caractere para o valor ASCII no acumulador.&
: subtraia um do acumulador se for 1 ou mais; caso contrário, adicione um.|
: adicione um ao acumulador.<
: defina o ponteiro de dados para 0.+
: incrementa a célula de dados no ponteiro de dados; mova o ponteiro +1.-
: subtraia um da célula de dados no ponteiro de dados, se for positivo; mova o ponteiro +1.[...]
: execute o código n vezes em que n é o número da fita no ponteiro de dados (não pode ser aninhado)./
: pule a próxima instrução se o acumulador for 0.Intérprete (C ++)
Diverta-se!
Solução
A:+&&&&&&&&&&/gbG&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/a<aB<[|]C[&]-[|]/c<[|]D[&]-[|]/d<[|]+E[&]|||||||||||||||||||||||||||||||||||||||||||||||||~X&/x-[|]/e
fonte
calloc
vez denew char
, escreveu um loop while no estilo C, usou o gerenciamento de memória no estilo C, nos faz recompilar o arquivo C ++ toda vez que alteramos o código e usamos 20 ifs em vez de aswitch
? Não estou reclamando, mas meus olhos estão sangrando agora ...: O #str.c_str()
para obter umchar*
.Essa foi uma péssima idéia, já que quase todas as línguas esotéricas parecem ilegíveis (veja Jelly).
Mas aqui vai:
Pylongolf2 beta6
Empurrando para a pilha
O envio para a pilha atua de maneira diferente do que em outros idiomas.
O código
78
empurra7
e8
na pilha, no entanto, em Pylongolf ele empurra78
.No Pylongolf2, isso é alternável
Ü
.Comandos
Concatenação de cadeias e removendo um padrão Regex de uma cadeia
O símbolo + concatena as strings.
Você pode usar o símbolo - para remover caracteres após um padrão de expressão regular de uma sequência:
Esse código recebe entrada e remove todos os caracteres não alfabéticos, removendo todos os padrões correspondentes
[^a-zA-Z]
.O item selecionado deve ser a regex e o item anterior deve ser a sequência a ser editada.
Instruções If
Para fazer as declarações if, coloque a
=
para comparar o item selecionado e o item seguinte.Isso coloca um
true
ou umfalse
no seu lugar.O comando
?
verifica esse booleano.Se for,
true
não faz nada e o intérprete continua.Se for,
false
o intérprete pula para o¿
personagem mais próximo .Retirado da página do Github.
Intérprete para Pylongolf2 (Java):
fonte
Arco-íris (Nota: Intérprete em breve)
Eu sei que esse desafio expirou.
Rainbow é uma mistura de ... muitas coisas.
Rainbow é uma linguagem baseada em pilha 2D com duas pilhas (como Brain-Flak) e 8 direções (
N NE E SE S SW W NW
). Existem 8 comandos:1
,+
,*
,"
Fazer exatamente o que eles fazem em 1+.!
alterna a pilha ativa.>
gire o IP no sentido horário.,
insira um caractere e pressione-o..
pop e saída de um personagem.No entanto, caracteres no código fonte não são executados imediatamente. Em vez disso,
[The Character in the source code]^[Top Of Stack]
é alimentado na coisa Conjectura de Collatz, e o número de etapas necessárias para alcançar 1 é convertido em um caractere pela tabela ASCII. Este caractere é então executado.No início do programa, o código fonte (exceto o último caractere) é colocado na pilha.
Quando o IP atinge a borda do código-fonte, ele termina.
Apocalipse
nem são dois registradores. Quando um
>
instrução é executada, m é incrementado. O apocalipse é acionado apenas se m exceder n. Quando o Apocalipse acontece, ele:m é inicialmente zero e n é inicialmente o último caractere do código fonte.
Criptografia
Depois de executar qualquer execução, o código fonte é criptografado. O ASCII do 1º caractere é incrementado em um, o 2º é decrementado em um, o terceiro é incrementado em dois, o 4º é decrementado em dois, etc.
fonte