9
\$\begingroup\$

Recently I did a lot of practice problems in brainfuck to learn better about how to use it (and to get more competent in general). Today I write a program to manipulate the input such that every word (separated by comma ,) is printed in reverse, while the commas are kept in place, which I'm quite proud of. Example provided in the statement: Input: Hello,world\0 Output: olleH,dlrow

Feel free to rip my code (and comments as well) apart and give some pointers on how my code could be improved!

>, 1:read
[ ~a:varchar a:in
[>+>+<<-] a:0 b:c:in
>>>>++++[<+++++ +++++ +>-]<[<->-] a:0 b:in [c:in-44]
<[[-]<[<+>-]>>] if c then a:in else
<[<<[.<]>[>]>.>]< print reverse then comma
, redo a':read ]
<[.<] print reverse
\$\endgroup\$
  • 4
    \$\begingroup\$ Wohoo, more Brainfuck to review! I promise to take a look given enough time! \$\endgroup\$ – Simon Forsberg Feb 17 '18 at 12:38
4
\$\begingroup\$

Upon learning more brainfuck, I've learned that my loop that subtracts 44 could be improved:

Before

>> tmp2=0 ++++[< tmp1=0 +++++ +++++ + >-] tmp1 is 44
<[<->-] subtract tmp1 from ptr

After

>  tmp1=0 ++++[< ptr    ----- ----- - >-]

This prevents actually creating the value 44 and performing an additional ~44 operations.

\$\endgroup\$
4
\$\begingroup\$

Optimizations

The additional memory in c-44 isn't necessary, as you can just subtract 4 times eleven directly from c.

Comment consistency

Apart from the minimal optimization your code is fine. Your comments aren't, to be honest.

There isn't a best-practice or a style guide for brainfuck as far as I know, but the problem stems from the inconsistency. In the first line, it starts with 1:read. It's not completely clear what that means, so I'll go with "read into cell 1". 1 immediately gets renamed to a:

[ ~a:varchar a:in

The squiggly line (~) and the varchar aren't self-explaining, but the a:in is. So we get the expectation that <var>:<value> will be a pattern.

That pattern breaks down in the next line, where a:0 (follows the pattern), but b:c:in:

[>+>+<<-] a:0 b:c:in

The line afterwards introduces brackets, which are valid brainfuck instructions:

>>>>++++[<+++++ +++++ +>-]<[<->-] a:0 b:in [c:in-44]

We've now mixed comments and code. It's nod bad in this case, since we're on d:0 either way, but it's an error waiting to happen.

However, the real kicker is the next line

<[[-]<[<+>-]>>] if c then a:in else

It's missing b:(in or 0) c:0 d:0, which is essential for the line afterwards, since we're at position c or d after this line. If you really want to manage this style, I'd suggest to

  • add an asterisk to the current cell and
  • use a fixed starting position for the comments:
[-][
Used names:

  a : current cell at beginning of loop
  b : cell after a to contain a copy of a
  c : cell after b to subtract 44 from a
  d : cell after c as helper to subtract 44 from c
  in: current loop input

  *<cell>: current cell
 *?<cell>: cell position depends on values
]

>,                        *a:in
[                         *a:in
[>+>+<<-]                 *a:0        b:in         c:in
>>>++++[<----- ----- ->-]  a:0        b:in         c:(in minus 44)   *d:0
<[[-]<[<+>-]>>]            a:(c?in:0) b:(c?0:44) *?c:0              *?d:0
.....

I wouldn't recommend that to be honest, as it gets hard to manage after a while. However, it's consistent.

Documentation can be full text

But we can just comment our code like in a regular programming language:

[-]
[
This program reverses the words in a list of comma separated words.
It's memory usage is bound by the input string.
]

We leave the initial cell empty so that every word is 0 limited:

>,

[
    Our initial loop cell A contains the input which we immediately
    shove into the next two cells B and C:

    [>+>+<<-]

    A : 0      (current position)
    B : input
    C : input
    D : temporarily 4 to subtract 44 from C

    We now subtract 44 from C:
    >>>++++[<----- ----- ->-]

    If our input was NOT a comma (44) C won't be zero and we move
    B back into A and set B and C to zero:

    <[[-]<[<+>-]>>]

    We're now either at position C (if C was zero) or position D
    (if C wasn't zero); if C was zero then B will contain a comma
    and A is zero; the next loop will therefore get executed

    Otherwise we're at position D and simply move back to position
    B to write the next letter of the word

    <[<<[.<]>[>]>.>]<
,]

The last word is limited by zero so we just print the letters backwards:
<[.<]

This is an exaggeration, but you can be as verbose as you like. This kind of commenting has a big draw back, though: it's easy to accidentally enter a comma or period by mistake and end up with broken code.

Conclusion

All in all, well done. The if-else-logic is a nice brain teaser, to be honest, which makes an proper comments a lot more important.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.