3
\$\begingroup\$

The intro

Yesterday I learned of the existence of Befunge. See my (sort of) related question about a Befunge interpreter in Python. And it made me want to learn the language, and what do programmers do when they learn a new language? They make a FizzBuzz of course!

The following program prints all FizzBuzz's from 1 until 100. I don't think this implementation is the best, since I repeat quite a lot of code and there are many empty fields in my program.

You can check it with an online interpreter:

befunge_online_1 or befunge_online_2

The explanation

  1. Read "!zzuBzziF" to stack
  2. >:#,_ While loop to print stack untill stack is empty
  3. Go down at the end of the line with v
  4. Then it prints a newline ,*52,*84<
  5. +1 Add 1 to top of the stack
  6. : copy top of stack (current fizzbuz number)
  7. *5*2*25 push 100 to stack
  8. go down v and go right >
  9. `| Checks if current fizzbuz number is bigger than 100
    • if bigger @ end program
    • if not bigger go down
  10. >:3% copy stack and modulus with 3
  11. Check modulo |
    • if modulo 3 == 0 print Fizz >"zziF",,,, and add 1 on top of the stack
    • if not modulo 3 == 0 add 0 to top of the stack
  12. go down v and swap top of stack \ so top op stack is current fizzbuzz number again
  13. %5:< copy stack and modulus with 5
  14. Check modulo |
    • if modulo 5 == 0 print Buzz ,,,,"Buzz"< swap stack \ and add 1 on top of it
    • if not modulo 5 == 0 swap stack \ and add 0 on top of it
  15. go down v and go right >
  16. Check if there was a Buzz with |
    • if there was a Buzz burn top of the stack with $ go to step 18
    • if there was no Buzz go down
  17. Check if there was a Fizz with |
    • if there was a Fizz do nothing
    • if there was no Fizz copy and print the current number :.
  18. go up and ^ and skip following with #
  19. go right > and go up ^ and go to step 4

The code

"!zzuBzziF">:#,_   v
v*2*5*52:+1,*52,*84<
  >@             > ^
>`|   >            v
  >:3%|            0
      >"zziF",,,, 1v
 v\            <   \
 0             |%5:<
 v1\ ,,,,"Buzz"< #  
   >$            ^  
 > |>            ^  
   >|               
    >:.          ^  

The output

FizzBuzz!
1  
2  
Fizz
4  
Buzz
Fizz 
7  
8  
Fizz 
Buzz
11  
Fizz 
13  
14  
FizzBuzz
...
98
Fizz
Buzz

The question

As stated above, I really don't think my implementation is the best, and am curious how other people would solve this problem.

My current doubts about the code:

  1. I repeat code, for example prints. Can they be reworked into functions?
  2. It feels quite large. Can this be condensed?
  3. Readability of the code. Do other people understand the steps I've taken?

I therefore invite you all to burn it down!

\$\endgroup\$
1
\$\begingroup\$

Here's mine, done basically without consulting yours.

v    >          0v    >              v >\#v_:.v
0>:3%|           >\:5%|              >:|  >   v
>    >"zziF",,,,1^    >"zzuB",,,,\1+\^ >\"!",$v
 ^+1 _@#-**455: ,*25                          <

My strategy for writing it was just to write the very simplest code possible — the body of the main loop is just

if (i divisible by 3) "Fizz"
if (i divisible by 5) "Buzz"
if (i equals 0) "!"

and then throw a loop around that. So I started by writing just

     >          v   >          v >    v
0>:3%|          >:5%|          >:|    v
>    >"zziF",,,,^   >"zzuB",,,,^ >"!",v
 ^+1 _@#-**455:                       <

But this is missing three pieces: (1) there should be a newline after each line; (2) there should be a :. to print i whenever we don't print Fizz or Buzz; and (3) we need to avoid printing i whenever we did print Fizz or Buzz.

(1) is easy to fix; we just add ,*25 to the "carriage return" code along the bottom of the loop.

(3) is awkward. I made an abortive attempt to squeeze a recomputation of something like ::3%!\5%!+#v_:. (read left-to-right) into the "carriage return" line before realizing that computing logical AND ("i mod 3 AND i mod 5") is awkward in Befunge, and I would have to add a fifth line if I wanted to branch again here with #v_. So it makes sense to do what you did and keep track of whether we've printed "Fizz" or "Buzz" as we print them. This lengthens the loop body by a few characters (most of which are \).

With (3) out of the way, (2) is easy to squeeze into the blank rectangle in the upper right. As a bonus, if we just printed "!", then we know we don't need to test for :.!


As for your code: It's definitely more convoluted than mine! :D But in Befunge, this is not necessarily a bad thing.

There are some infelicities; for example you use *2*5*52:+1,*52,*84 where I would have used **455:+1,*52 — I don't understand why you bother printing that space character with *84 since it comes at the end of a line. Possibly a vestige of an earlier version of the code?

On the right-hand side you have a # jumping over a 5. If you were trying to be obfuscated, then you could replace this with a codepath that just runs straight through the 5 and then corrects with a $ further up. You have plenty of white space where a $ could fit in.

Rather than always using

 >A
>|
 >B

consider using

  >A
>#^_B

where it saves you a line. In my long-rusted experience, Befunge idiom still values "small number of lines" over "small number of columns" — the language may be 2D but it's still written by line-oriented chauvinists. :)


Can they be reworked into functions? — No. :) Befunge-93 has no concept of the (non-#) GOTO, and as a corollary it has no GOSUB and no RETURN. I can imagine a programming idiom that applies a binary search tree of "line numbers" down the left side of the program and can "GOTO" a line whose number is specified on the stack; but this would be way overengineered for FizzBuzz.

Can this be condensed? — Yes. :)

Do other people understand the steps I've taken? — Yes. It's pretty straightforward. :)

\$\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.