跳至正文
LNN的博客!

重写的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" 句点 换行

评论区

加载基于 GitHub issues 的 utteranc.es 评论区组件……