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 . . . . . . . . > . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
字符按以下顺序执行(某些控制流字符除外):
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, ...]
现在IP已再次到达读/写循环。
输入值 'h'
如果输入为'h'
,则差为0,因此IP不会改变其方向。这又是多维数据集,其中所有不相关的字符均已删除。由于此路径包含许多非操作,因此它通过的所有非操作都已被替换&
。IP从问号开始。
. . . .
. ? w .
. . ' e
. . . .
. . . . . . . . . ! . . . . . .
. . . u _ q < . . \ . . . . . .
. . ? & & & / . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
执行的指令是:
'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
现在我们再次进入读/写循环,所以我们完成了。
其他投入
所有其他输入都会产生正的差异,因此IP在问号处向右转。我们仍然需要将l
和和分开o
,所以这就是我们接下来要做的。
分开'l'
和'o'
请记住,两者的差是7 for o
和4 for l
,如果输入是,我们必须结束程序o
。这又是一个多维数据集,不相关的部分替换为a .
,IP交叉的无操作替换为&符。
. . 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
两者之间挑剔的'l'
小号
因此,现在我们知道输入是an l
,但是我们不知道哪个l
。如果是第一个,则需要将另一个压入l
堆栈的底部,但是如果是第二个,则需要压入一个o
。还记得我们-3
在压入第一个堆栈之前将其保存到堆栈的底部l
吗?我们可以用它来分隔两个分支。
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
6 t ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
堆栈开始为 [..., -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
第一 'l'
如果是第一个'l'
,我们需要推另一个'l'
。为了节省字节,我们使用与first相同的字符'l'
。我们可以将堆栈简化为[...]
。这是多维数据集的相关部分,无操作符替换为“&”符号。
p > q '
. . . .
. . . .
. . . .
' . q . . . . . . . . l . . . .
$ W W . . . . . . . . > & & & &
. . ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
执行以下指令:
$'pq'lq
$' no-op
pq no-op
'l Push the character code of l
Stack: [..., 108]
q Send it to the bottom
Stack: [108, ...]
我们即将进入读/写循环,因此我们已经完成了该分支。
第二 'l'
如果输入的是第二个'l'
中'hello'
,该IP的问号向右转。再一次,我们可以简化堆栈,[...]
并且IP起始于?
,这次指向南方。
. . . .
. . . .
. . . .
. . . .
. . . . . . . . . . . . . . . .
. . . u _ q < o ' \ . . . . . .
. . ? . . . . . . & . . . . . .
. . & . . . . . . & . . . . . .
. . . .
& & & &
. . . .
. . . .
执行的指令是:
'oq_
'o Push the character code of 'o'
Stack: [..., 111]
q Move the top item to the bottom
Stack: [111, ...]
_ No-op
IP将再次进入读/写循环,因此我们也完成了该分支。