Cubix, 94 83 82 79 63 56 bytes
p>q'-?w.uh'e@U7.'hqi?oqB-!ul.-..$WWu_q<o'\;>....6t?.../!@
Expandido:
p > q '
- ? w .
u h ' e
@ U 7 .
' h q i ? o q B - ! u l . - . .
$ W W u _ q < o ' \ ; > . . . .
6 t ? . . . / ! @ . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
Notas
- O intérprete desabilita o campo de entrada quando o programa é iniciado. Como tal, um fluxo infinito de entradas é impossível. Este programa utiliza a entrada caractere por caractere, portanto, se não fosse por essa limitação, funcionaria corretamente.
- Este programa não limpa a pilha e fica confuso muito rapidamente. Como a máquina em que isso será usado aparentemente pode fornecer fluxos de entrada infinitos, parece razoável supor que ele também tenha memória infinita.
- Toda e qualquer ajuda no golfe é muito apreciada.
Experimente online
Você pode experimentar o programa aqui .
Explicação
Ideia geral
A idéia geral é que queremos ler um caractere e depois compará-lo com caracteres variados (primeiro h
, depois e
, l
etc.). Para acompanhar o personagem que perdemos, nós o mantemos no final da pilha. Quando precisamos, podemos facilmente trazê-lo ao topo novamente.
Loop de leitura / gravação
O loop de leitura e escrita é simplesmente a 5 ª linha. Todos os caracteres que não são usados são substituídos por no-ops ( .
):
. . . .
. . . .
. . . .
@ . . .
' h q i ? o q B - ! u l . - . .
. . . . _ . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
Isso pode ser dividido em duas partes: Leitura e (escrita e verificação). A primeira parte contém as instruções até e incluindo o ponto de interrogação. A segunda parte acima é o resto da linha. Como isso ocorre, assumimos que começamos com uma pilha de[...]
@
'hqi?
_
Explanation
'h Push the character code of the h
Stack: [..., 104]
q Send it to the bottom
Stack: [104, ...]
i Read one character of the input (-1 for EOF)
Stack: [104, ..., input]
? Start of condition:
if (input < 0):
@ execute '@', ending the program
if (input = 0):
continue going right
if (input > 0):
_ turn to the right, reflect back ('_') and
turn right again, effectively not changing
the direction at all
A segunda parte (escrita e verificação) é linear novamente. A pilha começa como [next-char, ..., input]
. Nós abstraímos o próximo caractere, porque isso muda mais tarde no programa.
oqB-!ul.- Explanation
o Output the character at the top of the stack
q Send the input to the bottom of the stack
Stack: [input, next-char, ...]
B Reverse the stack
Stack: [..., next-char, input]
- Push the difference of the top two characters, which
is 0 if both are equal, something else otherwise
Stack: [..., next-char, input, diff]
! if (diff = 0):
u make a u-turn to the right
else:
l. execute two no-ops
- push [input - next-char - input], which is disregarded
later, so it effectively is a no-op as well.
Agora, o IP será iniciado novamente no início desse loop, redefinindo o próximo caractere para o qual verificar h
.
Combinando o próximo caractere
Se o IP fez uma inversão de marcha (ou seja, o caractere que lemos e imprimimos corresponde ao próximo caractere 'hello'
), precisamos verificar qual caractere foi a entrada e, dependendo disso, empurrar o próximo caractere para o final da pilha. Depois disso, precisamos retornar ao loop de leitura / gravação, sem empurrar h
para a pilha, por isso precisamos de outra maneira de chegar lá.
Primeiras coisas primeiro: determine qual caractere a entrada foi. A pilha de parecido com este: [..., prev-char, input, 0]
.
. . . .
- ? . .
u h ' e
. . . .
. . . . . . . . . ! u . . . . .
. . . . . . . . . \ ; . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
Para comparar a entrada, usamos o código de caractere de h
novamente. Inicialmente, isso era porque eu realmente não sabia como lidar com isso e h
é o primeiro caractere a ser verificado, mas acabou sendo bastante conveniente. Se subtrairmos o código de caractere h da entrada, obtemos -3
se a entrada é e
, 0
se a entrada é h
, 4
se a entrada é l
e 7
se a entrada é o
.
Isso é útil, porque o ?
comando permite separar facilmente valores negativos de valores positivos e zero. Como tal, se o IP virar à esquerda, a diferença foi negativa, a entrada foi e
, então o próximo caractere deve ser um l
. Se o IP continuar em linha reta, a diferença foi 0
, assim como a entrada h
, o próximo caractere deve ser um e
. Se a entrada é uma l
ou umao
, o IP vira à direita.
Todas as instruções executadas antes do ponto de interrogação acima são:
;!e'h- Explanation
; Delete the top of the stack
Stack: [..., prev-char, input]
! if (input = 0):
e execute 'e' (no-op)
'h Push the character code of h
Stack: [..., prev-char, input, 104]
- Push the difference of the input and 104
Stack: [..., prev-char, input, 104, diff]
Agora, o IP muda de direção, conforme detalhado acima. Vamos examinar as diferentes possibilidades.
Entrada 'e'
Primeiro, consideraremos a entrada e
, que faz com que o IP se mova para cima do ?
, pois a diferença é 3. Todos os caracteres irrelevantes foram removidos do cubo.
. > q '
. ? . .
. . . .
. . . .
. . q . . . . . . . . l . . . .
$ W W . . . . . . . . > . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
Os caracteres são executados nesta ordem (excluindo alguns caracteres de fluxo de controle):
q'l$WWq
q Save the difference (-3) to the bottom of the stack so
we can tell whether the l on the bottom of the stack is
the first or the second l in hello
Stack: [-3, ...]
'l Push the character code of l to the stack
Stack: [-3, ..., 108]
$W no-op
W Sidestep into the loop
q Send the character code to the bottom
Stack: [108, -3, ...]
Agora, o IP atingiu o loop de leitura / gravação novamente.
Entrada 'h'
Se a entrada foi 'h'
, a diferença é 0, portanto o IP não muda de direção. Aqui está o cubo novamente, com todos os caracteres irrelevantes removidos. Como esse caminho inclui algumas no-ops, todas as no-ops pelas quais passou foram substituídas por &
. O IP começa no ponto de interrogação.
. . . .
. ? w .
. . ' e
. . . .
. . . . . . . . . ! . . . . . .
. . . u _ q < . . \ . . . . . .
. . ? & & & / . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
As instruções executadas são:
'e!\?q_
'e Push the character code of the e
Stack: [..., 101]
! if (101 = 0):
\ reflect away (effectively a no-op)
? if (101 > 0):
turn right (always happens)
q Move 101 to the bottom of the stack
Stack: [101, ...]
_ No-op
E agora estamos entrando no loop de leitura / gravação novamente, então terminamos.
Outras entradas
Todas as outras entradas resultam em uma diferença positiva; portanto, o IP vira à direita no ponto de interrogação. Ainda precisamos separar o l
e o o
, e é isso que faremos a seguir.
Separando o 'l'
e'o'
Lembre-se de que a diferença é 7 o
e 4 l
e que precisamos encerrar o programa se a entrada for um o
. Aqui está o cubo novamente, com as partes irrelevantes substituídas por a .
e as não operações que o IP cruza foram substituídas por e comercial.
. . q .
. ? w .
. h ' .
. U 7 .
. . . . . . . . . . . . . - . .
. . . . . . . . . . . . . & . .
. . . . . . / ! @ . . . . & . .
. . . . . . & . . . . . . & . .
. . & .
. . & .
. . & .
. . & .
h7'wq-!@
h no-op
7 Push 7 to the stack
Stack: [..., diff, 7]
'wq Push w to the stack and send it to
the bottom. We don't care about it,
so it's now part of the ellipsis.
Stack: [..., diff, 7]
-! if (diff = 7):
@ End the program
Discernimento entre os dois 'l'
s
Então, agora sabemos que a entrada foi uma l
, mas não sabemos qual l
. Se for o primeiro, precisamos empurrar outro l
para o fundo da pilha, mas se for o segundo, precisamos empurrar um o
. Lembre-se de que salvamos -3
no final da pilha pouco antes de empurrarmos o primeiro l
? Podemos usar isso para separar os dois ramos.
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
6 t ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
A pilha começa como [..., -3 or 140, ...]
Explanation
6t?
6t Take the 6th item from the top and move
it to the top (which is either -3 or 140)
? If that's positive, turn right, otherwise,
turn left
Primeiro 'l'
Se este foi o primeiro 'l'
, precisamos pressionar outro 'l'
. Para salvar bytes, usamos os mesmos caracteres do primeiro 'l'
. Podemos simplificar a pilha para [...]
. Aqui está a parte relevante do cubo, com as no-ops substituídas por e comercial.
p > q '
. . . .
. . . .
. . . .
' . q . . . . . . . . l . . . .
$ W W . . . . . . . . > & & & &
. . ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
As seguintes instruções são executadas:
$'pq'lq
$' no-op
pq no-op
'l Push the character code of l
Stack: [..., 108]
q Send it to the bottom
Stack: [108, ...]
Estamos prestes a inserir o loop de leitura / gravação, por isso terminamos com esse ramo.
Segundo 'l'
Se a entrada foi a segunda 'l'
em 'hello'
, a IP virou à direita no ponto de interrogação. Mais uma vez, podemos simplificar a pilha [...]
e o IP começa em ?
, apontando para o sul dessa vez.
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . u _ q < o ' \ . . . . . .
. . ? . . . . . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
As instruções executadas são:
'oq_
'o Push the character code of 'o'
Stack: [..., 111]
q Move the top item to the bottom
Stack: [111, ...]
_ No-op
E o IP está prestes a entrar no loop de leitura / gravação novamente, por isso também terminamos com esse ramo.