重写的brainf 99bottles
前两天想起之前写的brainfuck 99bottles还有很大优化空间,就改进了一下。
比起之前的版本,这次的版本有效指令数更少,运行用时更短。这得利于在开始主循环开始前提前保存好一些字符串“常量”,而不是每次用到都重新计算一遍。
这次也加了不少注释;注释中{ }
表示内存纸带示意,其中*
表示指针,' '
表示字符ASCII码," "
表示连续ASCII码。分别包含!=
和==
的连续两行纸带示意是分情况讨论。
->>+++++ ++>++>++++>++>+++>+++++ +
>++++>+++>+++++ +>++++>++>+++++ +++>++
>>+++++ +++++[>+++++ +++++ +<-]
<<[<]>
{ 255 0 *a1=7 a2=2 a3=4 a4=2 a5=3 a6=6 a7=4 a8=3 a9=6 a10=4 a11=2 a12=8 a13=2 0 0 n=110 }
“序列器”
接收一组非零数a1 a2 a3…和一个数n
得到规律如下的一组数:32 a1个n 32 a2个n 32 a3个n … 0 n
[
[>]>[>]>[>+<-] n右移1格
++++[<++++++++>-] 在n左手边第2格写32
<[<]<[<]<[>]>[ 循环ai次
>[>]>[>]>[<+>>+<-] n复制2份,分别放入左手边和右手边
<[<]<[<]<[>]>-]
<<+>->>] 最左侧的255右移1格
{ 13个0 255 0 *0 32 7个110 32 2个110 32 4个110 … 0 110 }
在得到的序列基础上制作字符串
>>----- ----- -->+>+++++ +>-->----- ---->+++++>[-] " botles"
>>+>----- --->>----- ----- -->----- ---->----- ---->++++ " of beer"
>>+>>>+++++ +>----- ->----- ---- " on the"
>>+++++ ++++>----- ----- --->-->-- " wall"
>[-]>[-]<+++++[>+++++++++<-]>->[-]>[-] 逗号
<+++++++[>+++++ +++++ ++<-]+++++ +++++ "\nT"
>>----- ----- --->--->----- ---- "ake"
>>+>>----- ---->>----- ----->+>+++++ ++++> " one down"
>[-]>[-]++++[<+++++ +++++ +>-] 逗号
>>++>----- ----- --->+++++>+++++ " pass"
>>----->++++++>>----- ----- --->++++>+>+++++ ++>>----- ----- " it around"
>[-]>[-]++++[<+++++ +++++ +>-]+++++ +++++ 逗号 换行
>[-]>[-]<+++++ +++[>+++++ +++++<-]>-->+ "No"
>>[-]
[{ 13个0 255 0 0 " botles" 0 " of beer on the wall" 0 ",\nTake one down," 0 " pass it around,\n" 0 "No" 0 *0 }]
<<[<]<[<]<[<]<[<]<[<]<<+++++ +++++<+++++ ++++
<- continue变量为0时,循环退出
{ … 0 0 *continue=255 十位=9 个位=9 0 0 " botles" 0 … }
初始化结束
[ 主循环 while(continue)
输出瓶数
>[<<+>>-]<<[>>+<<<+>-] 复制十位
{ … 十位 *0 255 十位 个位 … }
<[ 如果十位非零
>++++++[<++++++++>-] 加48('0')
<.[-] 输出并清理
]
>>>>[>+>+<<-]>[<+>-] 复制个位
{ … 255 十位 个位 *0 个位 … }
++++++[>++++++++<-] 加48('0')
>.[-] 输出并清理
{ … 255 十位 个位 0 *0 32 'b' 'o' 't' 'l' 'e' 's' … }
>.>.>.>..>.>.[<] 输出" bottle"
判断瓶数是否不等于1
{ … 255 十位 个位 0 *flag=0 … }
<<<[>>>-<] 如果十位不等于0就设置flag
{ … 255 十位!=0 个位 *0 flag=255 … }
{ … 255 *十位==0 个位 0 flag=0 … }
<<<[<]>[<]>>>- 统一指针位置,个位减1
{ … 255 十位 *个位减1 0 flag … }
[>>[+]-<] 如果个位减1不等于0就设置flag
{ … 255 十位 个位减1!=0 *0 flag=255 … }
{ … 255 十位 *个位减1==0 0 flag … }
<<<[<]>>>+ 统一指针位置,还原个位
{ … 255 十位 *个位 0 flag … }
>>[<->+] flag左移1格
{ … 255 十位 个位 flag *0 … }
<[ 如果有flag
{ … 个位 *flag 0 32 'b' 'o' 't' 'l' 'e' 's' 0 … }
>>[>]<.[<] 输出's',返回
]
{ … 个位 flag!=0 *0 " bottles" 0 " of beer on the wall" 0 44 10 … }
{ … 个位 *flag==0 0 " bottles" 0 " of beer on the wall" 0 44 10 … }
>>[>]>[.>]>.>. 输出" of beer on the wall" 逗号 换行
<<<[<]<[<]< 指针返回
重复“输出瓶数”
(由于flag占了临时单元格,有一些小改动)
{ … 0 0 255 十位 个位 *flag … }
<<[<<+>>-]<<[>>+<<<+>-]
{ … 十位 *0 255 十位 个位 … }
<[>++++++[<++++++++>-]<.[-]]
{ … *0 0 255 十位 个位 … }
>>>>[<<<+<+>>>>-]<<<[>>>+<<<-]
{ … 个位 *0 255 十位 个位 … }
++++++[<++++++++>-]<.[-]
{ … *0 0 255 十位 个位 flag 0 " botles" 0 … }
>>>>>>>.>.>.>..>.>.[<] 输出" bottle"
<[>>[>]<.[<]<+] 如果有flag就输出's',清空flag
{ … *0 0 " botles" 0 " of beer on the wall" 0 44 10 … }
>>[>]>.>.>.>.>.>.>.>. 输出" of beer"
[>]>++. 把逗号变成句点,输出
{ … 0 0 " botles" 0 " of beer on the wall" 0 *46 10 "Take one down" 44 32 0 "pass it around" 44 10 0 … }
>[.>]>[.>] 输出"\nTake one down" 等
<[<]<[<]<[<]<[<] 指针返回
{ … 十位 个位 0 *0 … }
瓶数减1
<- 设置else flag
{ … 十位 个位 *else=255 0 … }
<[ 如果个位非0
- 个位减1
>+]>[ else
<+++++++++<- 个位设为9,十位减1
>>+>]
{ … 十位 个位 0 *0 … }
判断瓶数是否不等于0 更新continue变量
<<<<+ 清空continue
<<- 255用于对齐
{ … *255 0 continue=0 十位 个位 … }
>>>[<-<] 如果十位==0就设置continue
{ … 255 *0 continue=255 十位!=0 个位 … }
{ … 255 0 continue=0 *十位==0 个位 … }
<[>]<[>] 统一指针位置
{ … 255 *0 continue 十位 个位 … }
>>>[<<[+]-<] 如果个位==0就设置continue
{ … 255 *0 continue=255 十位 个位!=0 … }
{ … 255 0 continue=0 十位 *个位==0 … }
<<<<[<]>[<]>[<]> 统一指针位置
{ … *255 0 continue 十位 个位 … }
>->[<+] 在continue左边设flag,如果continue已设置就清除flag
{ … 255 *flag=0 continue!=0 … }
{ … 255 flag=255 *continue==0 … }
<[<]>+ 统一指针位置,清除对齐用的255
{ … *0 flag=!continue continue … }
>>[ 如果有continue
输出瓶数
>[<<+>>-]<<[>>+<<<+>-]
<[>++++++[<++++++++>-]<.[-]]
>>>>[>+>+<<-]>[<+>-]
++++++[>++++++++<-]>.[-]
{ … continue 十位 个位 0 *0 … }
<<<<[+] 暂时清除continue
]
- 暂时将continue的位置设为255
{ … flag=!continue *255 十位 个位 0 0 … }
<[ 如果有flag
>+ 还原continue
{ … flag=!continue *continue=0 十位 个位 0 0 … 0 … 0 … 0 "pass it around" 44 10 0 "No" }
>>>>>[>]>[>]>[>]>[>]>.>. 输出"No"
<<<[<]<[<]<[<]<[<]<<<< 指针返回
<+ 清除flag
{ … *0 continue=0 十位 … }
]
>- continue暂时减1,稍后会还原
{ … 0 *continue减1 十位 个位 0 0 " botles" … }
>>>>>.>.>.>..>.>.[<] 输出" bottle"
判断瓶数是否不等于1
这里用到continue所在的单元格来对齐指针,所以要求不能为0
<<<[>>>-<]
<<<[<]>[<]>>>-[>>[+]-<]
<<<[<]>>>+
>>[<->+]
{ … 十位 个位 flag *0 " botles" 0 … }
<[>>[>]<.[<]<+] 如果是则输出's',清除flag
{ … *0 0 " botles" 0 " of beer on the wall" 0 46 10 }
>>[>]>[.>] 输出" of beer on the wall"
>.-- 输出句点,然后把它改回逗号
{ … 0 " botles" 0 " of beer on the wall" 0 *44 10 }
>.. 输出两个换行
<<<[<]<[<]< 指针返回
{ … continue减1 十位 个位 *0 … }
<<<+ 还原刚才减1的continue变量
{ … *continue 十位 个位 0 … }
] 主循环结束
{ … *continue=0 十位=0 个位=0 … }
输出最后一段
{ … *0 0 0 0 0 " botles" 0 " of beer on the wall" 0 44 10 … }
>+++++ +++++[>+++++ +++>+++++ +++++ +<<-]
{ … 0 *0 80 110 0 " botles" }
>--.>+.>>.>.>.>..>.>.>.>>[.>]>.>. 输出"No bottles of beer on the wall" 逗号 换行
{ … "No" 0 " botles" 0 " of beer on the wall" 0 44 *10 … }
<<<[<]<[<]<<.>.>>.>.>.>..>.>.>.>>.>.>.>.>.>.>.>.[>]>++.>. 输出"No bottles of beer" 句点 换行
{ … "No" 0 " botles" 0 " of beer on the wall" 0 46 *10 … }
<<<[<]<[<]<<<+++++ +++++[
<<<<< <<<+++++ ++
>+++++ +++++ +
>+++
>+++++ +++++ ++
>+++++ +++++
>++++
>+++++ +++++ ++
>+++++ +
>-]
{ … 70 110 30 120 100 40 120 60 *0 "No" … }
<---<+<++++<++++<----<++<+<+
{ … *'G' 'o' 32 't' 'h' 44 'y' '9' 0 "No" … }
.>.>.>.<<.>.>.>.---.<<.>-.+.<<.>>--.>.>.<<<. "Go to the store" 逗号 空格
{ … 'G' 'o' *32 'r' 'e' 44 'y' '9' 0 "No" … }
>>---.<+++.>>>.<<<<.>--.<<.--.>>>+++.<<.<.++.>>-.>.>. "buy some more" 逗号
[-]+++++ +++++.>>.. 换行 "99"
{ … 'G' 'o' 32 'r' 'e' 10 'y' *'9' 0 "No" 0 " botles" 0 " of beer on the wall" 0 46 10 … }
>>>>>.>.>.>..>.>.>.>>[.>]>.>. " bottles of beer on the wall" 句点 换行