Escreva um programa que produz seu nível de espelho

31

Existem 95 caracteres ASCII imprimíveis :

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

Na fonte Consolas (o bloco de código Stack Exchange padrão), alguns dos caracteres têm espelhos em torno de um eixo vertical de simetria:

  • Esses pares de caracteres são espelhos um do outro: () [] {} <> /\
  • Esses personagens são espelhos de si mesmos: ! "'*+-.8:=AHIMOTUVWXY^_ovwx|(Observe que o espaço é um).
  • Estes não têm espelhos: #$%&,012345679;?@BCDEFGJKLNPQRSZ`abcdefghijklmnpqrstuyz~

( i, l, 0, #, E, provavelmente, outros personagens são seus próprios espelhos em algumas fontes, mas vamos ficar com as formas Consolas.)

Diz-se que uma corda é um espelho de si mesma se for feita apenas com os 39 caracteres de espelho , organizados de modo que a corda tenha uma linha vertical central de simetria. Assim ](A--A)[é um espelho de si mesmo, mas ](A--A(]não é.

Escreva um programa uniforme de uma linha que seja um espelho de si mesmo. Quando N cópias da metade esquerda tiverem sido anexadas a ele e N cópias da metade direita tiver sido anexadas a ele, ele deverá gerar N + 1. N é um número inteiro não negativo.

Por exemplo, se o programa foi ](A--A)[(metade esquerda:, ](A-metade direita:) -A)[, então:

  • A execução ](A--A)[deve sair 1. (N = 0)
  • A execução ](A-](A--A)[-A)[deve sair 2. (N = 1)
  • A execução ](A-](A-](A--A)[-A)[-A)[deve sair 3. (N = 2)
  • A execução ](A-](A-](A-](A--A)[-A)[-A)[-A)[deve sair 4. (N = 3)
  • . . .
  • A execução ](A-](A-](A-](A-](A-](A-](A-](A-](A-](A--A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[deve sair 10. (N = 9)
  • etc.

Regras

  • Saída para stdout ou a alternativa mais próxima do seu idioma. Pode haver uma nova linha opcional à direita. Nenhuma entrada deve ser tomada.
  • Teoricamente, o processo deve funcionar para N até 2 15 -1 ou mais, com memória e poder de computação suficientes.
  • É necessário um programa completo, não apenas um comando REPL .

O programa inicial mais curto (caso N = 0) em bytes vence.

Passatempos de Calvin
fonte
Em algumas fontes, #é a sua própria relação também, mas, você está certo, não em consolas.
SuperJedi224
1
É possível usar repls? Em outras palavras: devemos escrever um programa válido completo ou uma expressão é suficiente? Estou pensando na entrada Haskell, que funcionaria ao executar no ghci, mas não é um programa completo válido.
Bakuriu
@Bakuriu É necessário um programa completo. A resposta Haskell é inválida.
Hobbies de Calvin
4
Por que os espelhos 'b' e 'd' não são um do outro? Isso torna meu plano impossível: P
Thijs ter Haar
1
@ThijsterHaar Na verdade, eu não considerei isso, mas parece que suas formas de Consolas são um pouco diferentes, desculpe: P
Calvin's Hobbies

Respostas:

20

Pip, 12 8 4 bytes

Agora com 66% menos bytes!

x++x
  • xé uma variável pré-inicializada para "". No contexto numérico, isso se torna 0.
  • A primeira metade, sem a final +, faz uma expressão da forma x+x+...+x. Esta é uma declaração válida que não faz nada.
  • A segunda metade, incluindo a final +da primeira metade, faz uma expressão da forma ++x+x+...+x. ++xincrementa xpara 1, e o restante adiciona a ele N vezes. Como as expressões são avaliadas da esquerda para a direita no Pip, é garantido que o incremento ocorra primeiro e o resultado é igual ao número de níveis de espelho.
  • No final, o valor dessa expressão é impresso automaticamente.

Infelizmente, o Pip não funciona bem ao processar grandes expressões: esta solução causa um maximum recursion depth exceedederro para N acima de 500 ou mais. Aqui está uma solução anterior que não funciona, por 8 bytes :

x++oo++x

Mais sobre Pip

DLosc
fonte
OK, a menos que alguém poste uma resposta de 2 bytes, parece que você colocou essa na mala. A propósito, não sei se você executou com N = 32767 , mas a saída real é Fatal error: maximum recursion depth exceeded while calling a Python object.
Dennis
@ Dennis Sim, eu me deparei com isso, na verdade - começa bem cedo, por volta de 600, se não antes. O motivo é que as expressões são avaliadas pela avaliação recursiva de todas as subexpressões primeiro, portanto x+x+...+xgera O (N) profundidade de recursão. Talvez isso invalide esta resposta. Vou adicionar uma nota.
DLosc
O limite de recursão é facilmente ajustável em Python, não é?
Dennis
@ Dennis Sim, embora existam avisos terríveis sobre o que ele fará com o seu sistema se você o definir muito alto, por isso nunca tentei. ;) Além disso, não é possível configurá-lo no Pip , por isso parece meio trapaça para mim. Se você quiser experimentar, no entanto, eu estaria interessado em ouvir os resultados.
DLosc
Eu tentei. Na minha máquina, aumentar o limite de recursão para 20000 já segfaults. Mas como a resposta precisa funcionar apenas com memória e poder de computação suficientes , isso não deve ser um problema.
Dennis
34

GolfScript, 10 bytes

!:{)::(}:!

Experimente online com o Web Golfscript: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

O Web GolfScript tem um limite de 1024 caracteres, mas o interpretador Ruby manipula N = 32767 perfeitamente:

$ curl -Ss http://www.golfscript.com/golfscript/golfscript.rb > golfscript.rb
$ echo '"!:{):"32768*":(}:!"32768*' | ruby golfscript.rb > mirror-level-32767.gs
$ ruby golfscript.rb mirror-level-32767.gs
32768

Como funciona

Sem nenhuma entrada, o GolfScript inicialmente possui uma string vazia na pilha.

Na primeira metade esquerda, acontece o seguinte:

  • !aplica NOT lógico à string vazia. Isso empurra 1.

  • :{salva o inteiro na pilha na variável {.

    Sim, esse é um identificador válido, embora não haja maneira de recuperar o valor armazenado.

  • ) incrementa o número inteiro na pilha.

  • : é uma instrução incompleta.

Nas metades esquerdas subsequentes, acontece o seguinte:

  • :!(onde :fica uma sobra de antes) salva o número inteiro na pilha na variável !.

    Sim, esse também é um identificador válido. Isso quebra o !comando, mas não o usamos mais.

  • :{, )E :trabalho como antes.

Na primeira metade direita, acontece o seguinte:

  • ::(onde :fica uma sobra de antes) salva o número inteiro na pilha na variável :.

    Sim, mesmo esse é um identificador válido. Assim como com {, não há como recuperar o valor armazenado.

  • ( diminui o número inteiro na pilha, produzindo o número de metades esquerdas.

  • }, pois é incomparável e finaliza a execução imediatamente.

    Este é um recurso não documentado. Eu os chamo de super-comentários .

O código restante é simplesmente ignorado.

Dennis
fonte
Parece realmente estranho ter uma inigualável }na segunda metade do seu código em uma competição de espelhos.
ballesta25
É um truque comum nas variantes do palíndromo. Em "\""/", a quarta citação dupla também não teria comparação, pois a segunda foi escapada.
Dennis
27

Código da máquina Z80, 8 6 bytes *

<8ww8> * Assume certas condições ao entrar no Amstrad BASIC

<   INC A         // A=A+1
8w  JR C, #77     ## C is unset unless A has overflowed, does nothing

w   LD (HL), A    // Saves A to memory location in HL (randomly initialised)
8>  JR C, #3E     ## C is still unset, does nothing

Aé inicialmente 0 quando inserido no BASIC. Incrementa A n vezes e depois escreve n vezes no mesmo local de memória (que é definido como BASIC em um local ligeiramente aleatório)! A JRoperação Jump Relative nunca faz nada, já que o Csinalizador está sempre desmarcado; portanto, é usado para "comentar" o seguinte byte! Esta versão é um pouco trapaceira, assumindo-se certas condições de entrada, como a entrada de garantias BASIC que Asão sempre 0. A localização de (HL)não é garantida como segura e, de fato, é provavelmente uma localização perigosa. O código abaixo é muito mais robusto e é por isso que é muito mais longo.

Código da máquina Z80, 30 bytes

Como ASCII: o!.ww.!>A=o>{))((}<o=A<!.ww.!o

Basicamente, a primeira metade garante a criação de um valor zero e a segunda metade o incrementa e grava na memória. Na versão expandida abaixo## denota código que não serve para nada na metade do espelho.

o   LD L, A       ## 
!.w LD HL, #772E  // Load specific address to not corrupt random memory!
w   LD (HL), A    ## Save random contents of A to memory
.!  LD L, #21     ## 
>A  LD A, #41     // A=#41
=   DEC A         // A=#40
o   LD L, A       // L=#40
>{  LD A, #7B     ## 
)   ADD HL, HL    // HL=#EE80
)   ADD HL, HL    // HL=#DD00. L=#00 at this point

((  JR Z, #28     ## 
}   LD A, L       // A=L
<   INC A         // A=L+1
o   LD L, A       // L=L+1
=   DEC A         // A=L
A   LD B, C       ## 
<   INC A         // A=L+1
!.w LD HL, #772E  // Load address back into HL
w   LD (HL), A    // Save contents of A to memory
.!  LD L, #21     ## 
o   LD L, A       // L=A

Repartição das instruções permitidas:

n   op    description
--  ----  -----------
28  LD    LoaD 8-bit or 16-bit register
3   DEC   DECrement 8-bit or 16-bit register
1   INC   INCrement 8-bit or 16-bit register
1   ADD   ADD 8-bit or 16-bit register

Available but useless instructions:
3   JR    Jump Relative to signed 8-bit offset
1   DAA   Decimal Adjust Accumulator (treats the A register as two decimal digits
          instead of two hexadecimal digits and adjusts it if necessary)
1   CPL   1s ComPLement A
1   HALT  HALT the CPU until an interrupt is received

Das 39 instruções permitidas, 28 são operações de carregamento (o bloco de 0x40 a 0x7F são LDinstruções de byte único ), a maioria das quais não ajuda aqui! A única instrução de carregamento na memória ainda permitida é o LD (HL), Aque significa que tenho que armazenar o valor A. Como Aé o único registro que resta com uma INCinstrução permitida, isso é realmente bastante útil!

Não consigo carregar Acom 0x00 porque o ASCII 0x00 não é um caractere permitido! Todos os valores disponíveis estão longe de 0 e todas as instruções matemáticas e lógicas foram proibidas! Exceto ... eu ainda posso fazer ADD HL, HL, adicione 16 bits HLa si mesmo! Além de carregar diretamente os valores (sem uso aqui!), INCrementing Ae DECrementingA , Lou HLé a única maneira que tenho de alterar o valor de um registro! Na verdade, existe uma instrução especializada que pode ser útil no primeiro semestre, mas é difícil trabalhar no segundo semestre, e uma instrução complementar que é quase inútil aqui e ocuparia apenas espaço.

Então, eu achei o valor mais próximo de 0 que eu pude: 0x41. Como isso é perto de 0? Em binário, é 0x01000001. Então eu diminuo, carrego Le faço ADD HL, HLduas vezes! Lagora é zero, no qual carrego de volta A! Infelizmente, o código ASCII para ADD HL, HLé )agora preciso usar (duas vezes. Felizmente, (é JR Z, e, onde eé o próximo byte. Portanto, ele devora o segundo byte e eu só preciso garantir que ele não faça nada, tomando cuidado com a Zbandeira! A última instrução para afetar a Zflag foi DEC A(contra-intuitivamente, ADD HL, HLnão a altera) e, como eu sei que Aera 0x40 naquele momento, é garantido que Znão está definido.

A primeira instrução na segunda metade JR Z, #28 não fará nada nas primeiras 255 vezes, porque o sinalizador Z só pode ser definido se A tiver excedido de 255 para 0. Depois disso, a saída estará errada, no entanto, pois ele está salvando valores de 8 bits de qualquer maneira que não deveria importar. O código não deve ser expandido mais de 255 vezes.

O código deve ser executado como um trecho, pois todas as formas disponíveis de retorno limpo foram desabilitadas. Todas as instruções RETurn estão acima de 0x80 e as poucas operações de salto permitidas só podem pular para um deslocamento positivo, porque todos os valores negativos de 8 bits também foram proibidos!

CJ Dennis
fonte
6
O QUE. O QUE É ISSO.
Cloudfeet 29/05
4
Agora eu já vi essa resposta, usando GolfScript / J / etc. parece trapaça. : p
cloudfeet
Existem processadores compatíveis com Z80 com um registro A de 16 bits? Estou perguntando uma vez que a pergunta exige que o código funcione para N = 32767 .
Dennis
1
@Dennis Para que um programa funcione para N = 32767, ele deve ter pelo menos 2 x 32767 ou 65534 bytes. O Z80 pode endereçar apenas 65536 bytes de memória, tornando isso uma tarefa impossível, pois não acredito que possa tornar o programa menor que 6 bytes! O Aregistro é sempre de 8 bits, caso contrário, o processador não seria compatível com o Z80. Eu diria que, dada a memória e o poder de computação suficientes , foram cobertos aqui!
CJ Dennis
1
@ Dennis Você entende por que nenhum processador compatível com Z80 terá um Aregistro de nada além de 8 bits? Mudá-lo para 16 bits quebraria o código contando com 255 + 1 = 0, por exemplo. Você precisaria inventar uma CPU, vamos chamá-la de Z160, que usa um registro de 16 bits padrão, mas ainda usa as mesmas instruções de 8 bits do Z80. Esquisito!
CJ Dennis
19

J, 16 14 bytes

(_=_)]++[(_=_)

Usos:

   (_=_)]++[(_=_)
1
   (_=_)]+(_=_)]++[(_=_)+[(_=_)
2
   (_=_)]+(_=_)]+(_=_)]++[(_=_)+[(_=_)+[(_=_)
3

Explicação:

  • J avalia da direita para a esquerda.

  • (_=_)é o inf equals infque é verdadeiro, tem um valor de 1, então a expressão se torna 1+]...[+1. ( (8=8)também funcionaria, mas isso parece mais legal. :))

  • [e ]retorne os argumentos esquerdo e direito, respectivamente, se eles tiverem 2 argumentos. Se eles recebem apenas 1, retornam isso.

  • +adiciona os 2 argumentos. Se obtiver apenas 1, retornará isso.

Agora vamos avaliar uma expressão de nível 3 (da direita para a esquerda):

(_=_)]+(_=_)]++[(_=_)+[(_=_)  NB. (_=_) is 1

1]+1]+1]++[1+[1+[1  NB. unary [, binary +

1]+1]+1]++[1+[2  NB. unary [, binary +

1]+1]+1]++[3  NB. unary [, unary +

1]+1]+1]+3  NB. unary +, binary ]

1]+1]+3  NB. unary +, binary ]

1]+3  NB. unary +, binary ]

3

Como vemos, a metade direita 1é adicionada e o lado esquerdo 1é omitido, resultando no número inteiro desejadoN , o nível do espelho.

Experimente online aqui.

randomra
fonte
12

Haskell, 42 bytes

(8-8)-(-(8-8)^(8-8))--((8-8)^(8-8)-)-(8-8)

Felizmente, um comentário de linha em Haskell (-> --) é espelhado e metade dele (-> -) é uma função válida. O resto é matemática para obter os números 0e 1. Basicamente, temos (0)-(-1)um comentário N=0e um prefixo(0)-(-1)- em cada etapa.

Se números de ponto flutuante são permitidos para saída, podemos construir a 1partir8/8 e seguir com 26 bytes:

Haskell, 26 bytes

(8-8)-(-8/8)--(8\8-)-(8-8)

Saídas 1.0, 2.0etc.

nimi
fonte
2
Isso é tecnicamente inválido, pois deve ser um programa completo.
Hobbies de Calvin
@ Calvin'sHobbies: Entendo. Temos consenso sobre os requisitos mínimos para um programa completo? Eu procurei meta, mas só encontrei uma discussão sobre funções, não programas. Dependendo da definição de um programa completo, posso consertar minha solução.
Nimi 29/05
Eu o chamaria de programa completo se você puder salvá-lo em um arquivo program.hse depois executar $ runhaskell program.hsna linha de comando e ver a saída. Eu não conheço Haskell, então não posso dizer exatamente o que precisa mudar.
Hobbies de Calvin
2
@ Calvin'sHobbies: runhaskellé um script de shell que configura algum ambiente e finalmente chama ghco compilador Haskell. Você pode executar o meu código diretamente com ghc: ghc -e "(8-8)-(-8/8)--(8\8-)-(8-8)". Isso inicia, ghcque avalia o código fornecido como argumento, imprime o resultado e sai. Sem REPL, sem interação. É claro que isso adicionaria +1 à contagem de bytes de -e.
nimi 29/05
@nimi: -enão contribui para a pontuação neste caso. Nós não contamos bytes para perl -Eou gcc -std=c99também.
Dennis
11

CJam, 14 bytes

]X+:+OooO+:+X[

Experimente on-line no intérprete CJam: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Observe que esse código termina com uma mensagem de erro. Usando o interpretador Java, essa mensagem de erro pode ser suprimida fechando ou redirecionando o STDERR.1 1

Como funciona

Nas metades esquerdas, acontece o seguinte:

  • ] quebra a pilha inteira em uma matriz.

  • Xanexa 1a essa matriz.

  • :+ calcula a soma de todos os elementos da matriz.

  • Oo imprime o conteúdo da matriz vazia (ou seja, nada).

Na primeira metade direita, acontece o seguinte:

  • o imprime o número inteiro na pilha, que é a saída desejada.

  • O+ tenta anexar uma matriz vazia ao item mais alto da pilha.

    No entanto, a pilha estava vazia antes de empurrar O. Isso falha e finaliza a execução do programa.

O código restante é simplesmente ignorado.

1 De acordo com a meta enquete Os envios devem ser autorizados a sair com um erro? , isso é permitido.

Dennis
fonte
Eu ficaria cético em aceitar isso devido ao erro, mas como não está ganhando, não estou muito preocupado.
Hobbies de Calvin
Tarefas como essa são surpreendentemente difíceis no CJam, considerando que é uma linguagem de golfe. Mesmo um erro de sintaxe (por exemplo, um operador indefinido) em um bloco não executado impedirá a execução de todo o programa. Ainda estou tentando me livrar do erro.
Dennis