BrainF ** K,396个 391字节
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
我无法抗拒这样做的诱惑。至少三角形的尖端朝下。
输入是一串数字字符,后跟一个换行符。
输出将在每行上包含一个尾随空格。
例子:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
说明
由于从功能的角度来解释代码相当困难,因此我们可以从磁带在不同时间的状态的角度来看它。这里的核心思想是将我们输出的三角形初始化为一个紧密堆积的数组(对于BF,无论如何),该数组的大小在每次循环迭代时缩小1。另一个重要的思想是,我们255
用来指示可以在磁带上搜索的“占位符”。
初始化
这是最简单的步骤。在程序开始时,我们执行以下操作:
>+>>++++[-<++++++++>]->
这将使磁带进入以下状态(其中>N<
指示指针在磁带上的位置)
[ 0 1 32 255 >0< 0 0 ...]
这里的第一个数字是“缓冲区”位置。我们不会长期使用它,但是使小操作更简单并复制数据很有用。
第二个数字是我们将在每一行的开头(从第一行开始)输出的空格数。第一行将没有前导空格。
第三个数字是我们输出的空格字符。
第四个数字是占位符255,因此我们可以相对轻松地返回此位置。
输入值
从这个位置,我们将阅读所有字符。在此步骤结束时,我们希望处于以下情况:
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
其中,a b c d e f ...
表示输入的数字字符的字符串(不是换行符)。
我们通过以下方式完成此任务:
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
这有一些细微差别。首先,我们将在获取每个字符时输出它们,然后在其后输出一个空格。其次,我们不想将ASCII值复制到磁带上,而是要复制实际的数字。第三,我们想在碰到换行符时停下来,并让自己处于一个好的位置。
说我们的输入是6723
。然后,在阅读第一篇文章时6
,我们的磁带如下所示:
[ 0 1 32 255 >54< 0 0 ...]
我们使用来检查该值是否等于10
(ASCII换行符),----------[++++++++++
。然后,我们打印出该值,并从输入值中同时减去48,然后在其旁边的值(>>++++++++[-<++++<------>>]<
)上加上32,继续进行操作:
[ 0 1 32 255 6 >32< 0 ...]
请注意,在整个过程中,我们可以假设输入右边的所有数字均为0 -这意味着,如果我们使用右边的值来计算6 * 8
and ,就不会有破坏任何先前状态的危险4 * 8
。
现在,我们输出刚生成的空格字符,并接受一个新的输入,删除我们在那里计算的空格。最终,输入将由新行终止,并且循环将退出,并在新行的原处保留255
(,----------]-
)。这是我们用来导航磁带的第二个占位符。在我们的场景中,此时的磁带正好是这样的:
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
计算方式
这种工作方式是,255
每次循环迭代时,占位符之间的数字列表将缩小一。当它只剩下1位数字时,我们就完成了,应该立即停止操作(请注意,此时,该列表中的每个数字都已经输出,因此我们不必担心再次输出它)。
现在,我们使用此技巧来导航到第一个255
占位符:<+[-<+]-
。这样可以有效地在磁带的左侧搜索a 255
,而这两者之间没有任何改变。现在,我们已经移动了指针,我们可以检查退出条件:如果列表中只有一位数字,则右边两个空格的单元格将保留255
。因此,我们对此进行检查并开始循环:>>+[-<<
循环的第一步是输出换行符。因此,我们移到第一个单元格(我们的缓冲单元),向其添加10并输出。下一步是输出所有前导空格字符。输出它们后,我们增加前导空格数的计数。这些步骤通过以下步骤完成:
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
这使我们处于这种状态:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
我们的下一步是将列表中的第一个值复制到第二个占位符之后255
:
[[->+]->>+<<<+[-<+]->]
我们基本上是通过在占位符之间来回跳来完成此操作255
的,而将我们留在这里:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
现在,我们开始循环,遍历列表的其余部分,并在单击时停止255
:>+[-<
此时,最左边的数字始终为0。因此,由于我们喜欢它们,255
因此在其中弹出了一个占位符,以便可以返回到列表中的位置。下一步是将列表中的第二个位置移动到我们将第一个位置移动到第二个占位符之后的位置255
。这些步骤通过以下步骤完成:
->
[[->+]->+>>+<<<<+[-<+]->]
让我们离开这里:[ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
现在,6
和7
都已移动到可以进行计算的位置。我们需要的两个副本,7
因为列表中的下一个数字也将需要它。该7
立即之后255
服务于这个目的,而其他7
将被计算消耗。
首先,我们将两个数字相加:
<+>->+[->+]->>
[->+<]>
离开我们这里:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
接下来的步骤组合是最复杂的。我们需要查看所指向的数字是否大于10,如果是,则减去10
。实际上,我们要做的是从中减去10,然后看它是否0
在减法的任何点都命中。如果是这样,我们10
稍后再添加。最后,我们应该将模的总和设为10。
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
至此,我们已经完成了目标。我们的模数总和为10!此外,无论数字是否大于10,我们都会在这里结束:
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
我们的下一个目标是输出这个新的总和,在其后加上一个空格,然后将其重新添加到我们的列表中。我们使用我们以前的255
-hopping并将其加到48
总和上的技术来完成所有这些工作,因此我将不做详细介绍。
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
我们在这里:[ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
请注意我们如何255
在新注入的对象之后放置一个额外的占位符,3
以免在列表中失去位置。此时,我们已经输出了总和及其空间,因此我们需要清理并恢复为该循环的下一个迭代将起作用的状态。我们需要清除51
和32
单元格,将7
一次移至右侧,然后导航到列表占位符,以便我们可以重新开始。
[-]<[-]<<<[->+<]<<+[-<+]
现在,我们在这里:[ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
下一个迭代正是我们想要的位置。因此,请检查255,然后继续!(>+]
)
当我们退出循环时,我们将拥有一个全新的列表-由上一个列表的总和组成。第一次,它看起来像这样:
[ 0 2 32 255 3 9 5 0 >0< ]
现在,我们要在新列表中重复整个过程,因此我们255
向左下拉并重新开始!我们需要使用进行一些清理>>[-]<<
,然后使用删除占位符<-
。之后,我们将与输入后的位置完全相同,因此我们可以做同样的检查:<+[-<+]->>+
和繁荣!我们有完整的循环!我们需要的只是结束括号,结束时我们已经输出了所有内容,因此我们完成了:]
。