(2015-05-08) Evolution of FizzBuzz

I know I've not posted for some time now and I have a few things I want to post about, but can't quite just yet (as they aren't finished).

So, instead, I'll make an interim post on how my coding skills have developed.

I am in now way suggesting that I am actually any good, just that compared to where I was when I originally started this blog, I've come a long way.

My original FizzBuzz post (https://edgley.org/Fizzbuzz/) seems like a life time ago now, but it's when I first started really looking in to bash

Having looked back and cringed a little bit at my inexperience, I decided I'd have another go at writing a FizzBuzz (this time in multiple languages, including bash).

## Normal Mode
for (( x=1; x <= 100; x++ )); do
        fizz=$( echo "${x} % 3" | bc )
	buzz=$( echo "${x} % 5" | bc )
	(( fizz == 0 )) && printf "fizz"
	(( buzz == 0 )) && printf "buzz"
	(( fizz != 0 && buzz != 0 )) && printf "%i" "${x}"
	printf "\n"
done

I love C style for loops; particularly in cases like this. I'd previously used brace expansion {1..100}, which isn't worse or better, but much less transferrable to other languages.

I also prefer the shorthand (( )) test braces over [ ] or [[ ]] because you can write variables again in C style (ie without the $ identifier), but they are only really good for mathmatical comarisons (as they allow for better expression handling, like =>, <=, == etc).

The above attempt was considered "Normal Mode" because I used the modulous command (x % y) to determine remainders; the hard mode version was to simply not use modulous. Instead, you can use division:

## Hard Mode
for (( x=1; x <= 100; x++ )); do
	fizz=$(( x / 3 * 3 ))
	buzz=$(( x / 5 * 5 ))
	(( fizz == x )) && printf "fizz"
	(( buzz == x )) && printf "buzz"
	(( fizz != x && buzz != x )) && printf "%i" "${x}"
	printf "\n"
done

It actually looks a bit cleaner in this case, because I no longer need to use the external "bc" command. Bash very handily (purely in this case, it's a nightmare in most others) doesn't calculate floats, so when we divide a number that should have a decimal, multiplying that number by the divisor should give us a number that wasn't the original. THe only changes needed was the fizz and buzz varaible calculations and then the comparison of them against the original number instead of 0.

That wasn't the end of it though, there is also a "God Mode", which requires not using division. This took a bit longer to work out (and is actually what I did in my original post):

## God Mode
for (( x=1; x <= 100; x++ )); do
        for (( j=${x}; j >= 0; j -= 3 )); do
                fizz=0
                (( j == 0 )) && fizz=1 && break
        done
        for (( j=${x}; j >= 0; j -= 5 )); do
                buzz=0
                (( j == 0 )) && buzz=1 && break
        done
        (( fizz == 1 )) && printf "fizz"
        (( buzz == 1 )) && printf "buzz"
        (( fizz != 1 && buzz != 1 )) && printf "%i" "${x}"
        printf "\n"
done

So this time, we are using subtraction. While bash doesn't do floats, it's fine with negative integers. So what we do is for each number we look at, we subtract 3 and 5 until it is 0 or less. If it's 0, then the number is divisible by 3 or 5, if it's less than it's not. This is essentially long handed division.

Looking back at my past attempt, how I actually worked it out is a little bit obscure. I do some weird for loops inside the main one, instead of using subtraction, I actually use multiplication. Which is kind of novel, particularlly as I hadn't seen anyone else do that in the Newgrounds thread. I don't know why I though it was the best idea, but that's what I did. The main critism I have of myself though, is that I hard limited all of it. The above code will continue to work past 100, with just a single value change (in the first line). In my previous attempt, I would have had to redo all three for loops and work out how many 3's and 5's go in to the total number.

I was also using redundant if statements (with else clauses) when I really didn't need to.

So for fun, here's how I would do it usig the same logic as I did back then (you can directly compare this with my previous code):

## God Mode Alternative
i=100
for (( x=1; x <= i; x++ )); do
	for (( j=0; j <= i; j += 3 )); do
		fizz=0
		(( j == x )) && fizz=1 && break
	done
	for (( j=0; j <= i; j += 5 )); do
		buzz=0
		(( j == x )) && buzz=1 && break
	done
	(( fizz == 1 )) && printf "fizz"
	(( buzz == 1 )) && printf "buzz"
	(( fizz != 1 && buzz != 1 )) && printf "%i" "${x}"
	printf "\n"
done

I realise I'm still putting extra limits in the inner for loops (hence the need to declare the total initially), but this time I actually break out of the loops when a match is found, which speeds up the output a little bit. I also don't print anything until the end (and instead I just set switches) so it's easier to get the output I want.

Edit: 2015/05/21 {

I noticed a very simple change that I could make to the above to increase performance somewhat; instead of iterating all the way up to i, j would only iterate up to x. We know if j is higher than x, it will never be a fizz or a buzz, so we can just stop there. It also means you don't have to declare i (as we are only defining 100 once now anyway):

## God Mode Alternative
for (( x=1; x <= 100; x++ )); do
        for (( j=0; j <= x; j += 3 )); do
                fizz=0
                (( j == x )) && fizz=1 && break
        done
        for (( j=0; j <= x; j += 5 )); do
                buzz=0
                (( j == x )) && buzz=1 && break
        done
        (( fizz == 1 )) && printf "fizz"
        (( buzz == 1 )) && printf "buzz"
        (( fizz != 1 && buzz != 1 )) && printf "%i" "${x}"
        printf "\n"
done

}

The biggest change though, by far, is my ability to write this function. The normal mode and hard mode took about 2 minutes to work out and write the required code. The God Mode attempt took maybe 10 minutes, just to work out the logic behind the loop and then another 2 minutes to write the code. The hardest thing to work out was that I needed to do the subtraction before the comparision. Finally, the God Mode Alternative attempt took maybe 2 minutes, as I had already worked out the logic previously, and just required me to rewrite the code.

I also have a working FizzBuzz function in awk, basic, c, c++, forth, php, perl, python, sh and vim script.

Just for comparision, here's the normal mode in sh (I used dash to test it):

for i in `seq 1 100`; do
	fizz=`echo "$i % 3" | bc`
	buzz=`echo "$i % 5" | bc`
	[ $fizz -eq 0 ] && printf "fizz"
	[ $buzz -eq 0 ] && printf "buzz"
	[ $fizz -ne 0 ] && [ $buzz -ne 0 ] && printf "%i" ${i}
	printf "\n"
done

I don't like standard sh that much, as you can't write consistent code as easily as bash (although bash has plenty of it's own issues).