我的代码分为几个部分。
设置构造磁带以包含一些数据
遍历所有FizzBuzzes
如果未找到FizzBuzz并打印新行,则打印编号
做到这一点非常困难,我开始与基本的Brainfuck运算符一起创建我可以使用的工具。在弄清楚如何“搜索”磁带上的值,将值复制/移动到另一个位置以及其他一些有用的东西之后,我决定采用这种方法。
磁带
在设置部分之后,这是我的磁带的样子:
从上到下分别表示:
100 =要循环的次数
10 =换行符
0 =计数器,我们要多少当前位置。
0 =布尔值,指示是否已找到FizzBuzz(以了解是否应打印数字)
用于将数字转换为字符串算法的空空间
然后有一个可配置的序列:
0 =自上次打印以来已经进行了多少次迭代
3/5 =多少次迭代,直到我们将要打印此文本
文本
空的空间来表示文本的结尾
最后:
253 = FizzBuzz序列的结尾
常规代码中的方法
该代码不会分别执行“经典”模运算迭代,它可以被认为是在执行以下操作:
int fizz = 3;
int fizzUp = 0;
int buzz = 5;
int buzzUp = 0;
boolean printed = false;
for (int i = 1; i <= 100; i++) {
printed = false;
fizz--;
fizzUp++;
if (fizz == 0) {
print("Fizz");
printed = true;
while (fizzUp > 0) {
fizzUp--;
fizz++;
}
}
// Same for buzz as for fizz
if (!printed) {
print(i);
}
print("\n");
}
主要问题我的Brainfuck代码可读性强吗? (我知道,那是Brainfuck ...)我试图添加大量注释来描述代码的作用(因为一旦我实际上认为什么比原因更重要)。
这样构造磁带的好决定吗?
“ Fizz”和“ Buzz”文本的设置是否可以更有效?
其他方法可以更有效吗?
其他任何方法赞赏的评论
++++++++++[>++++++++++<-]> Initialize 100 (number of times to perform FizzBuzz)
TAPE MEANINGS
255 Start
254 A Fizz or Buzz text to print
253 End of Fizzes and Buzzes
252 Currently processed FizzBuzz calculation
TAPE OVERVIEW
Remaining Iterations
10 for Line Break
255 Start Marker
Counter
Boolean 1 or 0 for whether or not a fizzbuzz matches current counter
Some empty space for converting counter to string
Any Number of Sequences of the following
254 Indicator for FizzBuzz sequence
Counter
Countdown until next text output
Text any number of characters
Zero
Zero
254 and 253 marker to indicate the end of sequences
>++++++++++ Line break
>- Start marker
>>>>>>>>>>>>>>>> Empty space for counter to string conversion
SETUP Create the Fizz and Buzz sequences on the tape
FIZZ
--> Create indicator
+++++++[->++++++++++<]> Create F
[->+>+>+>+<<<<] Copy 4x F
+++ Set modulo operator to 3
>>+++>>> Adjust second letter to I
++++++++[-<++++<++++<++++>>>] Make the last three lowercase to Fiff
+++++[-<++++<++++>>] Modify the last two F to Z by adding 20
>> Leave two zeros at the end
BUZZ
--> Create indicator
++++++[->+++++++++++<]> Create B
[->+>+>+>+<<<<] Copy 4x B
+++++ Set modulo operator to 5
>>+>++++++>++++++> Adjust BBBB to BCHH
++++++++[-<++++<++++<++++>>>] Make lower case
++++++[-<+++<+++<+++>>>] Adjust Bchh to Buzz
>> Leave two zeros at the end
-->--- Mark the ending with 254 and 253
END OF SETUP
ALGORITHM START
+[-<+]- Go backwards to the 255 mark
<
[
+[->+]- Go forward to the start position 255 marker
<<->> Decrease countdown
>+ Increase counter
>[-] Reset boolean for if we have found a match or not
++[-->++]--> Find next 254 and go one step beyond it
Loop through all 254s
+++[--- Make sure that we are not at 253 (end)
++[--<++]-- Find last value 254
-- Change marker to 252 to indicate that we're processing it
>> Go to the countdown
-< Decrease fizzbuzz countdown
+> Increase fizzbuzz counter
If current marker is NOT zero
[
++++[----<++++]-- Find value 252 and change to 254
[>] Position to a place that is zero to avoid repeat
++[-->++]-- < Find NEXT 254 marker and stop right before it
]
>++
Check if we are positioned on a 254 already then if skip this
[--
We have a match so find start position and mark match
+[-<+]- >> Find 255 marker and go to the boolean
[-]+ Set boolean to 1 whatever the previous value is
++++[---->++++]-- Find value 252 and change to 254
>[->+<] Reset the current FizzBuzz countdown
>>[.>] Print the text
++[-->++] Go to next 254 change to 256 to break loop
]
-->
+++ # Detect if we are at the 253 end
]
---
ALL FIZZBUZZES PROCESSED
Use the boolean to check whether or not to print the number
+[-<+]- Go back to the 255 marker
>> Go to boolean
-[ If boolean is zero then print the number
+>>>
+[-<+]- Go back to the 255 marker
>> We are positioned after the counter
Code taken from StackOverflow below for printing a number
>++++++++++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-
<+>]>+>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->++++++++
<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]
End of StackOverflow code
+[-<+]->> Locate the 255 marker and goto the boolean
]+
Boolean is always one here so print new line
[-]<<<.>>> Print new line
+[-<+]- Go back to the 255 marker
<< Go to the countdown to find out if we should go another round
]
压缩了典型的Brainfuckish版本的代码:
++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++
++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<++++<++++<++++>>>]++++
+[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++
++++>++++++>++++++++[-<++++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>-->
---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+
+++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[
->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[-<+]->>>++++++++++<<[-
>+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]>
+>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++
+++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[
-<+]-<<]
#1 楼
简化由于在Brainduck项目中实现了while循环的一些分析(由于回顾了“ Hello,Brainfuck”,我得以开展工作),我设法找到了一堆总是执行x次的循环。通过扩展这些循环(将其内容复制粘贴x次并删除该循环),可以进行几种简化。
布尔值peek-a-boo。 Wheeeere是布尔值吗?
+[-<+]->> Locate the 255 marker and goto the boolean
该循环始终执行两次,这意味着该循环可以扩展为
+-<+-<+->>
,而后者又可以简化为<<>>
当然可以完全删除。因此,可以用以下注释替换:cursor is now located on the boolean
]+
Boolean is always one here so print new line
[-]<<<.>>> Print new line
难怪当您在
+
之后执行]
时,布尔值始终是1。由于该值始终为1,因此循环始终执行一次,因此可以将代码简化为:]
Boolean is now zero so just print the new line
<<<.>>> Print new line
布尔值,标记,布尔值,邓布利多!
-[ If boolean is zero then print the number
+>>>
+[-<+]- Go back to the 255 marker
>> We are positioned after the counter
“我们位于计数器后面”与“我们位于布尔值上”(现在的值为零)相同。这段代码从布尔值开始,布尔值位于255标记的右边两步,然后向右移动三步,仅返回到255标记...因为总是执行此向后循环五次,这可以简化。首先,展开循环:然后删除彼此抵消的
+-
,剩下的就是: +>>>
+-<+-<+-<+-<+-<+- Go back to the 255 marker
>> We are positioned after the counter
找到252并更改为254
+>>>
<<<<< Go back to the 255 marker
>> We are positioned after the counter
此循环执行了两次,可以简化为:
+
在我们快要到达的时候查找254
++++[----<++++]-- Find value 252 and change to 254
你猜怎么了!?您的253恰好位于254值之后的一步,这意味着“查找最后一个值254”循环仅执行一次,这意味着简化了时间:
<<++ Go left to value 252 and change to 254
直接进入倒数计时,不要更改它,不要收集$ 200
+++[--- Make sure that we are not at 253 (end)
++[--<++]-- Find last value 254
-- Change marker to 252 to indicate that we're processing it
BF代码
><
与>>-<+>
是同一件事,因此将其更改为: /> +++[--- Make sure that we are not at 253 (end)
<-- Go to 254 marker and change to 252 to indicate that we are processing it
重置布尔值
>> Go to the countdown
-< Decrease fizzbuzz countdown
+> Increase fizzbuzz counter
布尔值在每个循环结束时重置,无需重置还要在开始时将其更改为:
>+ Increase fizzbuzz counter
>- Decrease fizzbuzz countdown
查找255标记和倒计时
>+ Increase counter
>[-] Reset boolean for if we have found a match or not
>我的分析在这里发现了一些有趣的东西,第一次完成“前进到255起始位置标记”循环,该循环只执行了一次,而其他所有时间都恰好执行了两次。这给了我一个线索,在这里可以进行重构,从简单地用
>+>-
替换单个<
开始,使循环始终精确地执行两次。然后我想到,在循环结束时,代码如下:
>+> Increase counter
总是执行两次“返回到255标记”,这意味着我们再次扩展和简化:
ALGORITHM START
+[-<+]- Go backwards to the 255 mark
<
[
+[->+]- Go forward to the start position 255 marker
,然后:
+[-<+]- Go backwards to the 255 mark
<< Go to the countdown
[
+[->+]- Go forward to the start position 255 marker
现在,回到大循环的开始,让我们看一下:
<<<.>>> Print new line
+[-<+]- Go back to the 255 marker
<< Go to the countdown to find out if we should go another round
考虑到第一个
<<
总是在倒数,我们可以做[
,即当我们已经处于倒数计时时,只需先对255标记进行罚款就可以进入倒计时。因此,将其替换为:<<<.>>> Print new line
+-<+-<+- Go back to the 255 marker
<< Go to the countdown to find out if we should go another round
澄清注释
<<<. Print new line
< Go to the countdown to find out if we should go another round
“避免重复”注释不是很好,因为随后循环,仅一次执行一次就足够了。但是,如果字符串本身包含神奇的254值,那么我们将遇到问题。因此,请澄清此注释:
[
+[->+]- Go forward to the start position 255 marker
<<->> Decrease countdown
内存利用率
内存利用率似乎相当不错,总体上仅使用了39个存储单元。但是,这是
[
->> Decrease countdown
是不必要的多余空间。可以简化为:
[>] Position to a place that is zero to avoid repeat
++[-->++]-- < Find NEXT 254 marker and stop right before it
还请注意每5条指令的空格使其更具可读性。
其他简化方式降低了灵活性
由于FizzBuzz的结尾为100,因此只能进行这种简化。如果您想更多地使用FizzBuzz,则无法简化此部分。
SO代码打印数字可以简化为:
[>] Go to a zero to avoid repeat in case there is a 254 value in the string
通过这种简化,可以通过更改为:
>>>>>>>>>>>>>>>> Empty space for counter to string conversion
2变为1(两个零变为1)
当前在Fizz或Buzz字符串之后始终有两个零。可以很容易地将其更改为只有一个零,这可以在此代码中进行一些简化:
匹配”情况:
>>>>> >>>>> >
它具有以前的样子,但可以提供更大的灵活性,可以扫描下一个254值。
结果代码
结果代码的非最小化版本,没有其他降低灵活性的简化,源代码中有631条Brainfuck指令,运行时执行了152267:
Code taken from StackOverflow below for printing a number
>++++++++++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<
[->->+<<]>[-]>[<++++++[->++++++++<]
>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]
End of StackOverflow code
所得代码的最小化版本,并具有减少了灵活性的其他简化功能,共548个字符:(正在执行的运行时指令为143808)
>>>>> >>>>> Empty space for counter to string conversion
评论
\ $ \ begingroup \ $
我不介意对此答案一见倾心。现象。 ++
\ $ \ endgroup \ $
–RubberDuck
2015年9月7日下午13:46
#2 楼
您应该在“磁带的含义”之后“初始化100”。我认为它是实际代码的一部分,而解释则是解释代码的一种“标题”。
我同意在bf中评论“什么”变得更加重要,但是您仍然应该时不时地解释“为什么”。为什么以您的方式构建“ Fizz”和“ Buzz”字符串的背后原因并不明显。一个简单的“这比直接创建字母更有效”。评论将有很长的路要走。也没有迹象表明为什么要在每个字符串的末尾保留两个零。
我不知道这个哈希标记在做什么。这有点令人困惑。 bf中任何不是有效运算符的内容都是注释。您不要在其他地方使用哈希来注释,也不要在此处这样做。
+++ # Detect if we are at the 253 end
总而言之,这是我眼中最可读的。但是,不要忽略我对实际代码的注释,以表明它做得正确。说实话,我不知道。我必须精读Turing机器并花一些时间写一些简单的东西,才能以正确的心态来理解这一点。我主要是想发布一个答案,以便它可能促使其他人认真研究它。
评论
\ $ \ begingroup \ $
附言不要用脑袋做。 = P
\ $ \ endgroup \ $
–RubberDuck
2014年9月1日19:31
\ $ \ begingroup \ $
对,用lolcode做到!
\ $ \ endgroup \ $
–马修·金登(Mathieu Guindon)♦
2014年9月1日19:32
\ $ \ begingroup \ $
我想,如果其他人要看看它,那可能就是我...但是要花一些时间...得先让我的Brainfuck Sudoku Solver!
\ $ \ endgroup \ $
–西蒙·福斯伯格
2014年11月17日在22:29
评论
噢,天哪,BF做了些严肃的东西?“ +++++++ [-> ++++++++++++ <]创建F”正确吗?当然,当您应该做相反的事情时,您将先增加然后移动。 (是的,我对此非常重视,brainfuck是我高度认可的一种教育语言。)
@Kayla如果您对FizzBuzz认真的话,是的。
我不认为“不要使用bf”。在这里算作评论。
@RubberDuck在写这篇文章时是为了学习,并想知道我可以在BF做些什么,可惜没有。