Cubix, 94 83 82 79 63 56 bytes
p>q'-?w.uh'e@U7.'hqi?oqB-!ul.-..$WWu_q<o'\;>....6t?.../!@
Expanded:
p > q '
- ? w .
u h ' e
@ U 7 .
' h q i ? o q B - ! u l . - . .
$ W W u _ q < o ' \ ; > . . . .
6 t ? . . . / ! @ . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
Notes
- The interpreter disables the input field when the program starts. As such, an infinite stream of input is impossible. This program takes the input character-by-character, so if it weren't for this limitation, it would work properly.
- This program doesn't clear up the stack, and it gets messy very quickly. Since the machine this will be used on apparently can give infinite input streams, it seems reasonable to assume that it also has infinite memory.
- Any and all golfing help is much appreciated.
Try it online
You can try the program here.
Explanation
General idea
The general idea is that we want to read a character, and then check it against varying characters (first h
, then e
, then l
etc.). To keep track of the character we have missed, we keep it at the very bottom of the stack. When we need it, we can easily bring it to the top again.
Read/Write loop
The read-write loop is simply the 5th line. All characters that are not used are replaced by no-ops (.
):
. . . .
. . . .
. . . .
@ . . .
' h q i ? o q B - ! u l . - . .
. . . . _ . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
This can be split up in two parts: Reading and (writing and checking). The first part contains the instructions up to and including the question mark. The second part up is the rest of the line. Because this loops around, we assume we start with a stack of [...]
@
'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
The second part (writing and checking) is linear again. The stack starts as [next-char, ..., input]
. We abstracted the next character, because that changes later in the program.
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.
Now, the IP will start again at the beginning of this loop, resetting the next character to check to h
.
Matching the next character
If the IP made a u-turn (i.e. the character we read and printed matched the next character in 'hello'
), we need to check what character the input was and depending on that, push the next character to the bottom of the stack. After that, we need to return to the read/write loop, without pushing h
to the stack, so we need another way to get there.
First things first: determine what character the input was. The stack looks like this: [..., prev-char, input, 0]
.
. . . .
- ? . .
u h ' e
. . . .
. . . . . . . . . ! u . . . . .
. . . . . . . . . \ ; . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
To compare the input, we use the character code of h
again. Initially, this was because I didn't really know how I was going to handle this and h
is the first character in the string to check for, but it ended up being quite convenient. If we subtract the character code of h from the input, we get -3
if the input is e
, 0
if the input is h
, 4
if the input is l
and 7
if the input is o
.
This is useful, because the ?
command lets us easily separate negative values from positive values and zero. As such, if the IP turns left, the difference was negative, so the input was e
, so the next character should be an l
. If the IP continues going straight, the difference was 0
, so the input was h
, so the next character should be an e
. If the input is an l
or an o
, the IP turns right.
All instructions executed before the aforementioned question mark are:
;!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]
Now the IP changes its direction as detailed above. Let's go over the different possibilities.
Input 'e'
First we'll consider the input e
, which causes the IP to move upwards from the ?
, since the difference is 3. All irrelevant characters have been removed from the cube.
. > q '
. ? . .
. . . .
. . . .
. . q . . . . . . . . l . . . .
$ W W . . . . . . . . > . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
The characters are executed in this order (excluding some control-flow characters):
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, ...]
Now the IP has reached the read/write loop again.
Input 'h'
If the input was 'h'
, the difference is 0, so the IP doesn't change its direction. Here's the cube again, with all irrelevant characters removed. Since this path includes quite a few no-ops, all the no-ops it passes have been replaced by &
. The IP starts at the question mark.
. . . .
. ? w .
. . ' e
. . . .
. . . . . . . . . ! . . . . . .
. . . u _ q < . . \ . . . . . .
. . ? & & & / . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
The instructions executed are:
'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
And now we're entering the read/write loop again, so we're done.
Other inputs
All other inputs result in a positive difference, so the IP turns right at the question mark. We still need to separate the l
and the o
, so that's what we'll do next.
Separating the 'l'
and 'o'
Keep in mind that the difference is 7 for o
and 4 for l
and that we have to end the program if the input was an o
. Here's the cube again with the irrelevant parts replaced by a .
and the no-ops the IP crosses have been replaced by ampersands.
. . 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
Discerning between the two 'l'
s
So, now we've we know that the input was an l
, but we don't know which l
. If it's the first, we need to push another l
to the bottom of the stack, but if it's the second, we need to push an o
. Remember we saved -3
to the bottom of the stack just before we pushed the first l
? We can use that to separate the two branches.
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
6 t ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
The stack starts as [..., -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
First 'l'
If this was the first 'l'
, we need to push another 'l'
. To save bytes, we use the same characters as for the first 'l'
. We can simplify the stack to [...]
. Here's the relevant part of the cube, with no-ops replaced by ampersands.
p > q '
. . . .
. . . .
. . . .
' . q . . . . . . . . l . . . .
$ W W . . . . . . . . > & & & &
. . ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
The following instructions are executed:
$'pq'lq
$' no-op
pq no-op
'l Push the character code of l
Stack: [..., 108]
q Send it to the bottom
Stack: [108, ...]
We're about to enter the read/write loop, so we're done with this branch.
Second 'l'
If the input was the second 'l'
in 'hello'
, the IP turned right at the question mark. Once again, we can simplify the stack to [...]
and the IP starts at ?
, pointing south this time.
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . u _ q < o ' \ . . . . . .
. . ? . . . . . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
The instructions executed are:
'oq_
'o Push the character code of 'o'
Stack: [..., 111]
q Move the top item to the bottom
Stack: [111, ...]
_ No-op
And the IP is about to enter the read/write loop again, so we're done with this branch as well.