Fifty Fizzbuzzes

An Extreme Programming Exercise by Vi Hart

One of the many things I learned from Evelyn Eastmond in my time working with her is this technique for deeply exploring, releasing yourself from preconceptions, thinking in new ways.

You make 50 of something. In one big marathon. (Maybe spaced over a few days, but it's important to exhaust your possibilities to break and illuminate habits, rather than making habits as with making a thing a week.)

50 is a LOT, and it takes you on this weird journey of ups and downs and complexifying and simplifying and combining and taking apart. It can be oddly emotional and intense.

This technique was meant for artists, but my research group has used it for VR stuff and programming language design too. So now to learn python, over the weekend I made 50 implementations of fizzbuzz.

Fizzbuzz is a classic simple programming exercise and common interview question based on a classic kids game, where you take turns counting, but if the number is divisible by 3 you say "fizz", and if it's divisible for 5 you say "buzz", and if it's divisible by both you say "fizzbuzz".

  • Ok, so this is a jupyter notebook, so if you want to run stuff you'll need to download this and open it, for which you might need https://www.anaconda.com/download/
  • To run the examples, click in the box and press ctrl+enter.
  • Each numbered section is independently runnable unless otherwise noted.(For sections with multiple boxes you might have to run the parts above it for it to work.)
  • If things break or get weird, try kernel -> restart & clear output
  • ...but things are going to get weird no matter what.
  • Feel free to skip around. Some have visuals, some have sound. 48 is a complete text adventure.

1: The Obvious

The first way that came to mind would be to do it in order like you play the game: for each number, check if it's divisible by 3 or 5:

In [ ]:
for i in range(1,101):
    if i%3!=0 and i%5!=0: print(i)
    if i%3==0 and i%5!=0: print("fizz")
    if i%3!=0 and i%5==0: print("buzz")
    if i%3==0 and i%5==0: print("fizzbuzz")

2: Simple elif

Let's elif it up and take out redundancies:

In [ ]:
for i in range(1,101):
    if i%3!=0 and i%5!=0: print(i)
    elif i%3==0 and i%5!=0: print("fizz")
    elif i%3!=0: print("buzz")
    else: print("fizzbuzz")

3: Conserving Modulus

There's something I don't like about testing the divisibility more than once. There's only two variables here.

Also, I don't like how there's a separate state for fizzbuzz, we should be able to combine the fizz and the buzz.

In [ ]:
for i in range(1,101):
    div3 = bool(i%3)
    div5 = bool(i%5)
    print(div3*div5*str(i)+(not div3)*"fizz"+(not div5)*"buzz")

4: One Line Fizzbuzz

It's hard not to want to make a one line version.

In [ ]:
for i in range(1,101): print(bool(i%3)*bool(i%5)*str(i)+(not bool(i%3))*"fizz"+(not bool(i%5))*"buzz")

The line is a bit long though.

5: Least Common Multiple

The fizz/buzz pattern is only 15 things long. Why should we do all this tricky modulusing when the computer could save some trouble and just loop through the pattern?

In [ ]:
for i in range (1,100,15):
    print(i, i+1, "fizz", i+3, "buzz", 
          "fizz", i+6, i+7, "fizz", "buzz", 
          i+10, "fizz", i+12, i+13, "fizzbuzz")

Sure it doesn't stop right at 100, but it's good enough for me.

6: Just Print It

Actually, if you really want the fastest running code I don't see why you wouldn't just do this:

In [ ]:
print("1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz buzz")

Just because you can do algorithms to it, doesn't mean you always should. Maybe for our application speed is more important than short code.

7: Use Fizzbuzz File

Actually, let's go ahead and save our fizzbuzz output, now that we know we'll probably be reusing it a lot:

In [ ]:
with open("fizzbuzzresult.txt", "w") as fizzfile:
    fizzfile.write("1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz buzz")

Great! Now we're ready to do fizzbuzz the dependent way.

In [ ]:
with open("fizzbuzzresult.txt", "r") as fizzfile: 
    fizztext = fizzfile.read()
    print(fizztext)

8: Convolutedly Use File Dependencies

(dependent on above example)

Seems a shame not to loop over anything though. Maybe we can make it into a list by splitting it on the spaces. Then we can loop over the list and print the values one by one instead of just printing the list, for no reason other than to look like we did something.

Note the added benefit that unlike our earlier for loops, we can range this one from 0 to 100 instead of 1 to 101!

In [ ]:
with open("fizzbuzzresult.txt", "r") as fizzfile:
    fizzlist = fizzfile.read().split(" ")

for i in range(0,100):
    print(fizzlist[i])

9: Multiple Refinements of a List

Well, if we're going to do a list, I've got a better way. Let's start from scratch this time.

Rather than thinking about getting each value correct in order, like you would when playing the kid's game, let's do some iterations over the entire list.

We'll start by listing the numbers, then overwrite the multiples of 3 to be "fizz", and so on.

In [ ]:
listbuzz= []

for i in range(1,101): listbuzz.append(i)
for i in range(2,101,3): listbuzz[i] = "fizz"
for i in range(4,101,5): listbuzz[i] = "buzz"
for i in range(14,101,15): listbuzz[i] = "fizzbuzz"
    
listbuzz

As you can see, the order of operations matters. But what if we wanted to start with fizzbuzzes?

10: Conservation of Fizzbuzz

We'll start with a list of "fizzbuzz", and we want to conserve the letters.

First we slice the buzz off of fizzbuzzes that are multiples of three (but not of 15). Then we slice the fizz off of fizzbuzzes that are multiples of five (but not of 15). Finally, we replace all the fizzbuzzes that aren't multiples of five or three.

In [ ]:
listzz= []

for i in range(1,101): listzz.append("fizzbuzz")
    
for i in range(2,101,3): 
    if (i+1)%15 != 0: listzz[i] = listzz[i][:4]
for i in range(4,101,5): 
    if (i+1)%15 != 0: listzz[i] = listzz[i][4:]

for i in range(0,100):
    if ((i+1)%3 != 0) and ((i+1)%5 != 0):
        listzz[i] = i+1
        
listzz

There's something fun about starting with all fizzbuzzes, but all the mods and checking for divisibility is confusing, especially what with the i+1s and zero indexing.

11: Iterate and Protect

What if we started with a list of all fizzbuzzes, and then can't add any more, so we delete the parts we don't need, and we make little shields to protect the good parts from deletion?

(Note that "None" is the shield. It's a shield of nothingness.)

In [ ]:
lizz = []
shield = []

# Make everything fizzbuzz:

for i in range(0,100): lizz.append("fizzbuzz"), shield.append(4)

# add shields to fizz, buzz, and fizzbuzzes we want to keep:

for i in range(14,100,15): shield[i] = None
for i in range(2,101,3): 
    lizz[i] = lizz[i][:shield[i]]
    shield[i]= None
for i in range(4,101,5): 
    lizz[i] = lizz[i][shield[i]:]
    shield[i]= None

# delete unprotected fizzbuzzes:
    
for i in range(0,100):
    lizz[i] = lizz[i][shield[i]:shield[i]]
    if lizz[i] == "": lizz[i] = i+1
        
lizz

It's fun to try avoiding certain functions or syntax.

12: No Mods Allowed

When I first heard this problem (which is apparently common in coding interviews? I dunno I've never done one), I knew I'd want to use % if it were in the languages I know, but I was just learning python and could only guess as to whether % is mod like I'm used to.

So I want to check for divisibility, without using mod. But the very first lesson in intro python was about types and casting. So I can divide, and check if the float result is the same as the integer result.

Also, let's use an if/else tree.

In [ ]:
for i in range (1,101):
    if i/3 == int(i/3): 
        if i/5 == int(i/5): print("fizzbuzz")
        else: print("fizz")
    else:  
        if i/5 == int(i/5): print("buzz")
        else: print(i)

13: No For Loops

Actually, I don't think the first python class I took even taught for loops. It did teach while True loops with break, though!

In [ ]:
n = 0
count = 100

while True:
    if n == count: break
    n += 1
    if n/3 == int(n/3): 
        if n/5 == int(n/5): print("fizzbuzz")
        else: print("fizz")
    else:  
        if n/5 == int(n/5): print("buzz")
        else: print(n)  

14: Functions and Math

What about functions? Let's use functions. Cool programmers use functions, right?

At the same time, I'm going to try and math my way out of repeating the exact same comparison tests every time.

In [ ]:
def fizzify(n):
    if n%3+n%5 == 0: return "fizzbuzz"
    elif n%3==0: return "fizz"
    elif n%5==0: return "buzz"
    else: return n
    
for i in range(1,100): print(fizzify(i))

Yes, I do like that better!

15: Too Many Functions

Let's add more functions! Let's get weird!

In [ ]:
def num(a):
    if a%3 and a%5 != 0: return str(a)
    else: return ""

def fizz(a):
    if a%3 == 0: return "fizz"
    else: return ""
    
def buzz(a):
    if a%5 == 0: return "buzz"
    else: return ""

def fizzy(n):
    return num(n) + fizz(n) + buzz(n)
    
def fizzbuzz():
    for i in range(1,101): print(fizzy(i))
        
fizzbuzz()

We've now gone through a fizzbuzz amount of fizzbuzzes!

Only 35 more to go.

Let's relax the constraints.

16: Leverage User Knowledge

What if instead of calculating the answer ourself, we crowdsourced? Let's leverage the knowledge of the user!

We'll just ask them for the answers, over and over.

In [ ]:
fizzle = []
for i in range(0,100): fizzle.append(i+1)

print("Hello! \n\nLet's play a game. It's called fizzbuzz. \n\n It works like this:")
print("If the number is divisible by 3, say \'fizz\'. If it's divisible by 5, say \'buzz\'.")
print("If it's divisible by both, say \'fizzbuzz\', and neither, then just say the number.")
print("\nready?\n")


for i in range(1,101): 
    print("how about",i,"?")
    fizzle[i+1] = input()
    print("good work! let's do another!")

    
print("You Win!")
print(fizzle)

Ok, no one is going to play that to the end, and they're going to get some wrong.

17: Fizzbuzz Game

How about you can just do some random ones until you're tired? And let's make it a bit more polished, with an intro and a quit function, and motivation so that our crowdsourcing has a better chance of getting us our data.

In [ ]:
import random

encouragements = ["great!", "amazing!", "that's the ticket!", "wow!", "You're wonderful!"]

def encourage():
    print(encouragements[random.randint(0, len(encouragements)-1)],"\n")

fuzzle = []
for i in range(0,100): fuzzle.append(i+1)

ask = input("Hello! Would you like to play a game? Y/N: ").lower()

while ask == "n": ask = input("oh come on it'll be fun! Play a game y/n? ")
    
if ask == ("y" or "yes"): 
    print("Hooray! Let's play!")
else: 
    print("I'll take that as a yes.")
    
print("You can quit any time by typing q.\n")

print("Here's the game: \n")
print("If the number is divisible by 3, say \'fizz\'. If it's divisible by 5, say \'buzz\'.")
print("If it's divisible by both, say \'fizzbuzz\', and neither, then just say the number.\n\n")

input("ready? ")

while ask != "q":
    a = random.randint(1,101)
    print("How about",a,"?")
    ask = input()
    if ask.lower() == "q": break
    fuzzle[a-1] = ask
    encourage()

print("Thank you for playing!!!")
print(fuzzle)

The first time I tested this game I got the following fizzbuzz result:

[1, '', 3, 4, 5, 6, 7, 8, 9, 10, 11, 'fizz', 13, 14, 15, 16, '', 18, 'nineteen', 20, 21, 22, 23, 24, 25, 26, 'fizz', 28, 29, 'fizzbuzz', 31, 32, 'fizz', 'thertyfour', 35, 36, 37, 'thirtyeight', 39, 40, 41, 42, 'fizz', 44, 45, 46, 'fourtyseven', 48, 49, 50, 'fizz', 52, 53, 54, 55, 56, 'fizz', 'fiftyeight', 'fizz', 60, 61, 62, 63, 64, 65, 66, 'sixtyseven', '', 69, 70, 71, 'fizz', 73, 'buzz', 'fizzbuss', 76, 77, 78, 79, 80, 81, 'eightyto', '83', 84, 85, 'fizz', 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

Not bad, not bad.

18: Fizzbuzz Game with Judginess

Now, maybe we could make the game more fun while also increasing accuracy if we compare the new fizzbuzz list we're creating to a known good list. Does it count? Sure.

In [ ]:
import random

correctBuzz = [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz', 'fizz', 22, 23, 'fizz', 'buzz', 26, 'fizz', 28, 29, 'fizzbuzz', 31, 32, 'fizz', 34, 'buzz', 'fizz', 37, 38, 'fizz', 'buzz', 41, 'fizz', 43, 44, 'fizzbuzz', 46, 47, 'fizz', 49, 'buzz', 'fizz', 52, 53, 'fizz', 'buzz', 56, 'fizz', 58, 59, 'fizzbuzz', 61, 62, 'fizz', 64, 'buzz', 'fizz', 67, 68, 'fizz', 'buzz', 71, 'fizz', 73, 74, 'fizzbuzz', 76, 77, 'fizz', 79, 'buzz', 'fizz', 82, 83, 'fizz', 'buzz', 86, 'fizz', 88, 89, 'fizzbuzz', 91, 92, 'fizz', 94, 'buzz', 'fizz', 97, 98, 'fizz', 'buzz']

encouragements = ["great!", "amazing!", "that's the ticket!", "wow!", "You're wonderful!"]
boos = ["nope", "oh come on", "wrong!!!", "try again."]

def encourage():
    print(encouragements[random.randint(0, len(encouragements)-1)],"\n")

def boo():
    print(boos[random.randint(0, len(boos)-1)],"\n")

buzzle = []
for i in range(0,100): buzzle.append(i+1)

ask = input("Hello! Would you like to play a game? Y/N: ").lower()

while ask == "n": ask = input("oh come on it'll be fun! Play a game y/n? ")
    
if ask == ("y" or "yes"): 
    print("Hooray! Let's play!")
else: 
    print("I'll take that as a yes.")
    
print("You can quit any time by typing q.\n")

print("Here's the game: \n")
print("If the number is divisible by 3, say \'fizz\'. If it's divisible by 5, say \'buzz\'.")
print("If it's divisible by both, say \'fizzbuzz\', and neither, then just repeat the number.\n\n")

input("ready? ")

while ask != "q":
    a = random.randint(1,101)
    print("How about",a,"?")
    ask = input()
    if ask.lower() == "q": break
    if ask == str(correctBuzz[a-1]):
        buzzle[a-1] = ask
        encourage()
    else:
        boo()

print("Thank you for playing!!!")
print(buzzle)

19: Fizzbuzz Game with Point Multipliers

Let's try one more game version, this time allowing faster answering and with a points system.

We'll even have point multipliers and an end state!

(And we'll struggle with what exactly and how Python does the whole function global local variable thing and how to get around it!)

In [ ]:
import random

bizlet = []
for i in range(0,100): bizlet.append(0)

points = 0
streak = 0
streakMult = 1
encouragements = ["great!", "amazing!", "that's the ticket!", "wow!", "You're wonderful!"]
boos = ["nope", "oh come on", "wrong!!!", "try again."]

def right(points, streak, streakMult):
    bizlet[a-1] = ask
    print(encouragements[random.randint(0, len(encouragements)-1)],"\n")
    streak += 1
    if streak == 3: 
        streakMult = 2
        print("THREE IN A ROW!\nPOINTS MULTIPLIER x2")
    elif streak == 5: 
        streakMult = 3
        print("!!!FIVE IN A ROW!!!!\n!!!POINTS MULTIPLIER x3!!!")
    elif streak == 10: 
        streakMult = 5
        print("!!!!!!!!!!!!!!!\n!!!TEN IN A ROW!!!!\n!!!POINTS MULTIPLIER x5!!!\n!!!!!!!!!!!!!!!")
    elif streak == 15: 
        streakMult = 15
        print("FIZZBUZZ STREAK BONUS"*15)
    points += 5*streakMult
    print("score:", points)
    return points, streak, streakMult

def wrong(points, streak, streakMult):
    print(boos[random.randint(0, len(boos)-1)],"\n")
    streak = 0
    print("score:", points)
    return points, streak, streakMult
    
def win():
    print("\n*******\n*YOU WIN!*\n*******\n\nYour final score is: ",score)

ask = input("Hello! Would you like to play a game? Y/N: ").lower()

while ask == "n": ask = input("oh come on it'll be fun! Play a game y/n? ")
    
if ask == ("y" or "yes"): 
    print("Hooray! Let's play!")
else: 
    print("I'll take that as a yes.")
    
print("You can quit any time by typing q.\n")

print("Here's the game: \n")
print("If the number is divisible by 3, enter \'a\'. \nIf it's divisible by 5, enter \'s\'.")
print("If it's divisible by both, enter \'d\', \nand if it's neither, then just hit enter.\n\n")

input("ready? ")

while ask != "q":
    if not(0 in bizlet): win()
    a = random.randint(1,101)
    print("How about",a,"?")
    ask = input()
    if ask.lower() == "q": break
    if ask == "":
        if a%3!=0 and a%5!=0: 
            points, streak, streakMult = right(points, streak, streakMult)
        else: 
            points, streak, streakMult = wrong(points, streak, streakMult)
    elif ask == "a":
        if a%3==0 and a%5!=0: 
            points, streak, streakMult = right(points, streak, streakMult)
        else: 
            points, streak, streakMult = wrong(points, streak, streakMult)
    elif ask == "s":
        if a%3!=0 and a%5==0: 
            points, streak, streakMult = right(points, streak, streakMult)
        else: 
            points, streak, streakMult = wrong(points, streak, streakMult)
    elif ask == "d":
        if a%3+a%5 == 0: 
            points, streak, streakMult = right(points, streak, streakMult)
        else: 
            points, streak, streakMult = wrong(points, streak, streakMult)
    else:
        print("enter for normal, a for divisible by 3, s for divisible by 5, d for both, q to quit.")

print("Thank you for playing!!!")
print(bizlet)

That was a long one!

20. Minimalist

How about something more minimal:

In [ ]:
print("fizzbuzz\n"*100)

So it's not 100% accurate. So sue me.

21: Random Guesses

Let's just take a random guess for each. Who will be able to tell the difference, really?

In [ ]:
import random

for i in range(1,100):
    r = random.randint(1,10)
    if r < 6: print(i)
    elif r < 8: print("fizz")
    elif r < 10: print("buzz")
    else: print("fizzbuzz")

Maybe we can predict the correct answer using a more analytical approach.

22: Linear Regression

Let's start with simple linear regression. This means we'll need a data set, say, the first 20 correct answers.

In [ ]:
import pandas as pd
datafizz = [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz']
numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
fizzframe = pd.DataFrame({"number": numbers, "answer": datafizz})
fizzframe

Hmm, the data set has all these non-number values. Well, we'll just throw those out of course, they are clearly garbage data.

I'm sure there's a better way to do this, but let's try:

In [ ]:
ff = fizzframe
j = 0
for i in range(0,20):
    if type(ff.iloc[j,1]) == str: 
        ff = ff.drop(ff.index[j])
    else: j+=1
ff

Ah, those look like datums that we can do data analysis to!

I wonder if we can find a corellation between the number and anwser that will allow the creation of a predictive model?

Let's take a visual look at our data.

In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline

plt.scatter(ff.number, ff.answer,  color='red')
plt.xlabel("number")
plt.ylabel("correct fizzification")
plt.show()

Looks pretty promising! Let's see if linear regression can help us fill in those gaps.

In [ ]:
from sklearn import linear_model
regr = linear_model.LinearRegression()
x = ff[["number"]]
y = ff[["answer"]]
regr.fit (x, y)

print ('Coefficients: ', regr.coef_)
print ('Intercept: ',regr.intercept_)

plt.scatter(ff.number, ff.answer,  color='red')
plt.plot(x, regr.coef_[0][0]*x + regr.intercept_[0], '-r', color='pink')
plt.xlabel("number")
plt.ylabel("correct fizzbuzzification")

Wow, that's a remarkable fit! It's things like this that let us know machine learning is magic that humans will never understand and that will develop consciousness all by itself.

Now let's use it to predict the value of fizzbuzzification for the full range of 1 through 100.

In [ ]:
for i in range(0,100): 
    prediction = regr.coef_[0][0]*i + regr.intercept_[0]
    print(prediction)

Because our machines are so smart because they learned so much, we know that just because our puny human minds think "that doesn't look like fizzbuzz" doesn't mean we're right. We can be sure that the above is the correct fizzbuzz, better than what humans can predict.

23: Linear Regression with Veneer

...but let's throw some fizzes and buzzes in there just to be sure it looks real fizzbuzzy.

In [ ]:
#dependent on running 22

for i in range(0,51,3): 
    prediction = regr.coef_[0][0]*i + regr.intercept_[0]
    print(prediction)
    print("fizz")
    print("buzz")

Yesss, yes, there we go.

24: Simple Answer

Let's step back a moment. Really fizzbuzz should be this nice simple answer, regardless of whether it's this strange concept called "correct".

In [ ]:
for i in range(1,101): print(i,i%3*"FIZZ",i%5*"BUZZ")

25: BUZZY FIZZY BUZZ BUZZ FIZZ BUZZ

In [ ]:
for i in range(1,101): print(i%2*"fizz",i%3*"FIZZ",i%4*"buzz",i%5*"BUZZ",i%6*"fizzbuzz",i%7*"FIZZBUZZ")

26: Fizz Fuzz

In [ ]:
for i in range (1,51):
    print(i*"f"+"izz"*(not bool(i%3))+"uzz"*(not bool(i%5)))

27: Mod Mod Mod Mod Mod

This one's actually correct:

In [ ]:
for i in range (1,101):
    print(str(i)*(not(i+1)%3%2)*(not(i+1)%5%4%3%2) + 
          "fizz"*((i+1)%3%2) + 
          "buzz"*((i+1)%5%4%3%2))

28: Backspace

For every line, print number, fi(zz), and bu(zz)! Then backspace over the parts you don't want.

I haven't used \b before but it seems to also be able to delete itself? So you can't stack them? Not exactly sure what's up but that's why it's fibu and not all four letters.

In [ ]:
for i in range(1,101):
    print(
        str(i) + 
        (i+1)%3%2*(int((i+10)/10)+2)*"\b" + 
        (i+1)%5%4%3%2*(int((i+10)/10)+2)*(i%3)*"\b" + 
        "fi" +
        i%3*"\b"*2 +
        "bu" +
        i%5*"\b"*2
    )

So there's some mistakes. Mistakes are part of life. We must embrace them and move on!

29: Beep Buzz

I heard that you can use an escape sequence to sound the computer bell. Let's test out this \a bell function, for an auralization of where the fizzes and buzzes are in the sequence!

Note the logic we can use if we aren't differentiating between fizzez, buzzez, and fizzbuzzez.

In [ ]:
for i in range(1,101): 
    if (i%3 and i%5)==0: print(i,"bing!\a")
    else: print(i)

It is not making the noises though, so I don't know if I'm doing it wrong or if this computer or jupyter notebooks doesn't do it? Hmm! Also I imagine to the human ear it is all happening at once.

30: Auralization

Let's look up how to play stuff with timing, and making different tones!

And by "look up", I mean this is mostly going to be a copy+paste job. I have no idea how to do audio in a python jupyter notebook, but I think I can modify someone else's thing to fizzbuzz.

Then we can make fizz, buzz, and fizzbuzz sound different!

In [ ]:
#mostly from https://ipython-books.github.io/117-creating-a-sound-synthesizer-in-the-notebook/

import numpy as np
import matplotlib.pyplot as plt
from IPython.display import (
    Audio, display, clear_output)
from ipywidgets import widgets
from functools import partial
%matplotlib inline

rate = 16000.
duration = 2
t = np.linspace(
    0., duration, int(rate * duration))

#ok now just gotta modify their synth function to play more than one tone

audioFizz = []

def synth(f):
    for i in range(0,len(f)):
        x = np.sin(f[i] * 2. * np.pi * t)
        display(Audio(x, rate=rate, autoplay=True))

for i in range(1,21): 
    if i%3+i%5 == 0: audioFizz.append(800)
    elif i%3==0: audioFizz.append(600)
    elif i%5==0: audioFizz.append(700)
    else: audioFizz.append(220)

synth(audioFizz)    

Sooooooo... I guess it plays them all at once, eh. Or tries to, and then loads out of order. I spared your ears and computer by limiting it to 20 instead of 100.

I'll have to figure out how the audio thingy actually works, but in the mean time:

31: Vizualization

Let's go back to our datavis graphs, since I understand the tools better.

We'll plot the numbers, but give fizz a fizzy boost, and buzz a dip down. For both, it'll even out to a small dip down.

In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline

fizzbee = []

for i in range(0,100): 
    fizzbee.append(i+1)
    if (i+1)%3 == 0: fizzbee[i] += 10
    if (i+1)%5 == 0: fizzbee[i] -= 20

plt.plot(range(1,101), fizzbee)

Maybe it would be more accurate to make all fizzes and buzzes the same value, rather than relative to the numbers?

But which value should we choose? How about something negative.

In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline

fuzzbee = []

for i in range(0,100): 
    fuzzbee.append(i+1)
    if (i+1)%3 == 0: fuzzbee[i] = -10
    if (i+1)%5 == 0: fuzzbee[i] = -20
    if (i+1)%15 == 0: fuzzbee[i] = -30

plt.plot(range(1,101), fuzzbee)

Ah, yes, I like that better.

Let's go ahead and bar graph the stats, too.

Might as well vary the logic on the fizzbuzz part, too.

In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline

n, f, b, fb = 0,0,0,0

for i in range(1,101):
    if (i%3 and i%5) != 0: n+=1
    elif i%5 != 0: f+=1
    elif i%3 != 0: b+=1
    else: fb+=1
        
labels = ('number','fizz','buzz','fizzbuzz')
datums = (n,f,b,fb)
        
plt.bar(labels,datums)

32 Auralization Attempt 2

Let's try this again. I'm going to take a closer look at this audio display function to see what kind of input it actually wants, and see if we can concatenate all the audiobits.

In [ ]:
import numpy as np
from IPython.display import (
    Audio, display, clear_output)

rate = 16000.
duration = 0.25
t = np.linspace(
    0., duration, int(rate * duration))

audioFuzz = []

def synth(f):
    x = np.sin(f[0] * 2. * np.pi * t)
    for i in range(0,len(f)):
        x = np.append(x, np.sin(f[i] * 2. * np.pi * t))
        print(len(x))
        print(x)
    display(Audio(x, rate=rate, autoplay=True))

for i in range(1,101): 
    if i%3+i%5 == 0: audioFuzz.append(800)
    elif i%3==0: audioFuzz.append(600)
    elif i%5==0: audioFuzz.append(700)
    else: audioFuzz.append(220+i)

synth(audioFuzz)    

Yes, that's more like it!

33: RGBuzz

Well, I don't know how to do much in the way of graphics, but I know how to plot graphs. So let's use a bar graph to represent fizzbuzz in color.

In [ ]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

rgcount = []
rg1 = []
for i in range(0,100):
    rgcount.append(i)
    rg1.append(1)

rgbuzz = plt.bar(rgcount,rg1)

for i in range(1,100):
    if i%3+i%5 == 0: rgbuzz[i].set_color("yellow")
    elif i%3==0: rgbuzz[i].set_color("red")
    elif i%5==0: rgbuzz[i].set_color("orange")
    else: rgbuzz[i].set_color("grey")

34: Text Color

Now that I think of it, let's learn how to format text, and do classic fizzbuzz but with formatting.

Uhh these codes are ridiculous but ok?

In [ ]:
R  = '\033[31m' # red
G  = '\033[32m' # green
O  = '\033[33m' # orange
B  = '\033[34m' # blue

for i in range(1,101):
    if i%3!=0 and i%5!=0: print(B+str(i))
    elif i%3==0 and i%5!=0: print(R+"fizz")
    elif i%3!=0: print(O+"buzz")
    else: print(G+"fizzbuzz")

Not bad. I'd like that in a block please.

35: Color Fuzz Block

Let's add some more and put them all close together for color time. I'm also going to have two shades of blue for numbers so that when they're together they don't blend together.

In [ ]:
R  = '\033[31m' # red
G  = '\033[32m' # green
O  = '\033[33m' # orange
B  = '\033[34m' # blue
D  = '\033[36m' # lighter blueish

fizzString = ""

for i in range(1,501):
    if i%3!=0 and i%5!=0 and i%2!=0: fizzString += (B+str(i))
    elif i%3!=0 and i%5!=0: fizzString += (D+str(i))
    elif i%3==0 and i%5!=0: fizzString += (R+"fizz")
    elif i%3!=0: fizzString += (O+"buzz")
    else: fizzString += (G+"fizzbuzz")
        
print(fizzString)

35: Time to learn to draw Rectangles?

In [ ]:
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
%matplotlib inline

rect = mpatches.Rectangle((1,1),.5,1.5)

plt.show()

Nope, can't figure it out. Why is searching for simple things the hardest?

But I did find a 2d histogram thing that has rectangles, let's try that:

In [ ]:
import matplotlib.pyplot as plt
import numpy as np

histfizz = []

for i in range(1,100):
    if i%3+i%5 == 0: histfizz.append(0.2)
    elif i%3==0: histfizz.append(0.4)
    elif i%5==0: histfizz.append(0.7)
    else: histfizz.append(0.9)

plt.hist2d(histfizz,histfizz)

plt.show()

Yep, it's rectangles, we win.

36: User Set Fizz Fuzz

Why always 5 and 3? Why fizz and buzz? Let's let the user decide what numbers are special and what we call them.

Notice the checks to make sure their selected numbers are in a useful range and are not mutual multiplicabits.

In [ ]:
input("hello, would you like to play fizzbuzz?")
input("Great. I don't know how to play fizzbuzz, so how about you make up a new game?")

gameName=""
num1=""
num2=""
say1=""
say2=""

while gameName == "":
    gameName = input("what do you want to call the new game? ")
    while len(gameName)<6:
        gameName = input("Maybe a longer name?")
    
say1=gameName[:len(gameName)//2]
say2=gameName[len(gameName)//2:]

print("\ngreat! let's play", gameName,"\nNow all we need are rules.")

while True:
    num1 = input("pick a smallish integer: ")
    if num1.isdigit() == True:
        if int(num1) < 2:
            print("not that small!")
        elif int(num1) > 40:
            print("that's a little big, don't you think?")
        else: break
    else: print("counting numbers only, please")
        
num1=int(num1)

print("\nok,", num1, "will do. \nNow,")

while True:
    num2 = input("pick another: ")
    if str.isdigit(num2) == True:
        num2=int(num2)
        if num2 < 2:
            print("\nnot that small!\n")
        elif num2 > 100/num1:
            print("\nthat's a little big, don't you think?\n")
        elif (num1%num2) * (num2%num1) == 0:
            print("\nno no no, now one is a factor of the other.\n")
        else: break
    else: print("counting numbers only please!!!")
        
print("\nsure,", num2, "it is.")
print("\n\nReady to play",gameName,"?\n\n")

for i in range(1,101):
    if i%num1!=0 and i%num2!=0: print(i)
    elif i%num1==0 and i%num2!=0: print(say1)
    elif i%num1!=0: print(say2)
    else: print(gameName)
        
print("\n\nI WIN!!!!")

38: Classy Fizzbuzz

I gotta learn how to write a class! Let's do fizzbuzz the classy way!

In [ ]:
class fizzclass(object):
    def __init__(self,num1=3,num2=5,text1="fizz",text2="buzz"):
        self.num1 = num1
        self.num2 = num2
        self.text1 = text1
        self.text2 = text2
        
    def rules(self):
        print("multiples of",self.num1,"are",self.text1,
             "\nmultiples of",self.num2,"are",self.text2,
             "\nmultiples of both are",self.text1+self.text2)
        
    def run(self, n=100):
        for i in range(1, n+1):
            if i%self.num1 + i%self.num2 == 0: print(self.text1+self.text2)
            elif i%self.num2==0: print(self.text1)
            elif i%self.num1==0: print(self.text2)
            else: print(i)
        
fizzobject = fizzclass()
fizzobject.rules()
fizzobject.run()

Using the fizzclass class, we can create anything in the class of fizzbuzz-type games.

In [ ]:
blipblop = fizzclass(4,7,"blip","blop")
blipblop.run(30)
In [ ]:
ohwhy = fizzclass(1,2,"oh ","why!")
ohwhy.run(5)

ah, so classy!

39: Fizz Bizz Wuzz

Why just two numbers? Let's allow any number of special multiples.

In [ ]:
class fuzzclass(object):
    def __init__(self,numbers = [3,5],text = ["fizz","buzz"]):
        self.numbers = numbers
        self.text = text
        
    def rules(self):
        i=0
        while i < len(self.numbers):
            print("multiples of",self.numbers[i],"are:",self.text[i])
            i+=1
        print("multiples of both",self.numbers[0],"and", self.numbers[1], 
              "are:", self.text[0]+self.text[1], "\nand so on.\n")
        
    def run(self, n=100):
        for i in range(1, n+1):
            fuzzstring = ""
            for j in range(len(self.numbers)):
                if i%self.numbers[j] == 0:
                    fuzzstring += self.text[j]
            if fuzzstring != "": print(fuzzstring.capitalize())
            else: print(i)
                
wuzz = fuzzclass()
wuzz.numbers = [3,5,7]
wuzz.text = ["fizz", "bizz", "wuzz"]

wuzz.rules()
wuzz.run()

Let's try a more extreme example!

In [ ]:
wooz=fuzzclass([2,3,4,5,6,7,8,9],["tu","re","fo","fiv","ix","eve","ate","ine"])
wooz.run(50)

Or an artsier one:

In [ ]:
poemnums=[1,2,3,4,5,6,7,8,9,10]
poemwords=["i"," don't"," think"," know"," have"," that"," wish"," why"," or"," anything"]
poem = fuzzclass(poemnums,poemwords)
poem.run(30)

Let's take this poem thing to the next level.

40: Fizz Poem Friend

Let's make a poem bot that bases its fizz-style poem off of user input.

In [ ]:
#first I'll borrow the fuzzclass, with some modifications

class foezzclass(object):
    def __init__(self,numbers = [3,5],text = ["fizz","buzz"]):
        self.numbers = numbers
        self.text = text
        
    def run(self, n=100):
        for i in range(1, n+1):
            fuzzstring = ""
            for j in range(len(self.numbers)):
                if i%self.numbers[j] == 0:
                    fuzzstring += self.text[j]+" "
            if fuzzstring != "": print(fuzzstring.capitalize())
            else: print("")

#I wonder how many lines our poem should be?

poemLength = 50
maxPoem = 50
                
#Now for some user interaction!

instring = ""
while instring == "": instring = input("Hi! How are you? ")
instring += " "+input("Ah! I see! Tell me more. ")
instring += " "+input("Well, I am very good at keeping secrets.")

poemWords = instring.split(" ")

if len(poemWords)>maxPoem: poemWords = poemWords[:maxPoem]

poemNums = []
for i in range(len(poemWords)): poemNums.append(i+2)

if len(poemWords)<50: poemLength = len(poemWords) + 3
    
input("I feel like I'm starting to understand you.")
print("\nI wrote you this poem: \n")
    
botpoem = foezzclass(poemNums,poemWords)
botpoem.run(poemLength)

I like this game. But let's step back again:

41: Factors

maybe the word for every number should be its factors, something like the second example in section 39, but accommodating for the fact that we run out of words for primes.

The tricky part is making sure we keep track of how much we've converted into words and how much might be a multiplicative remainder.

In [ ]:
#we've got to modify fuzzclass so that 9 is "fizzfizzfizz" and such

class factorname(object):
    def __init__(self,numbers = [3,5],text = ["fizz","buzz"]):
        self.numbers = numbers
        self.text = text
        
    def run(self, n=100):
        for i in range(1, n+1):
            fuzzstring = ""
            accountedFor=1
            for j in range(len(self.numbers)):
                k = i
                while k%self.numbers[j] == 0:
                    fuzzstring += self.text[j]
                    accountedFor *= self.numbers[j]
                    k = k/self.numbers[j]
            if fuzzstring != "": 
                if i-accountedFor != 0: fuzzstring += str(int(i/accountedFor))
                print(fuzzstring.capitalize())
            else: print(i)
                
primeWords = ["two","three","five","seven","eleven","thirteen","seventeen","nineteen"]
primeNums = [2,3,5,7,11,13,17,19]

primeFizz = factorname(primeNums,primeWords)
primeFizz.run(200)

(Note that the above does not find prime numbers, and the single numbers aren't necessarily prime, they just don't have named factors.)

42: Froodbeeb

In [ ]:
for i in range(1,51):
    if i==42: print("\033[31m *****DON'T PANIC*****"'\033[30m')
    elif i%3!=0 and i%5!=0: print(i)
    elif i%5!=0: print("frood")
    elif i%3!=0: print("beeb")
    else: print("hoopy frood beeblebrox")

43: Text Adventure Dungeon

In [ ]:
import random

monsters = ["bats","bears","dungeon mice","fizz snakes", "buzzbees", "growlumps", "wolfizzes", "robots", "buzzdemons"]
adj = ["evil","demonic","angry","slimy","buzzing","fizzing","hairy","giant"]
acc = ["", "q", "f", "b", "fb"]
win = [0]
for i in range(1,101):
    if i%3+i%5 == 0: win.append("fb")
    elif i%5==0: win.append("b")
    elif i%3==0: win.append("f")
    else: win.append("")

def fight(a,r,m):
    while a not in acc: input("enter to walk through, f for Fizz, b for Buzz, fb to dual wield: ")
    if a == win[r]:
        if a == "": print("\nYou walk through the illusory",m)
        elif a == "f": print("\nYou sword the", m,"to death!")
        elif a == "b": print("\nYou stab every single one of the",m)
        else: print("\nYou dual wield to victory over the",m)
        return True
    else:
        if a == "": print("\nOH NO, turns out the",m,"aren't illusions!")
        else: print("\nYou try to defeat the", m,"but are wielding the wrong weapon!")
        print("\n\nYOU DIE\n")
        return False

#Start game

ask = input("Dare you descend into Fizz Dungeon? Y/N: ").lower()

while ask == "n": ask = input("Too scared? Come on. Play a game y/n? ")
    
if ask == ("y" or "yes"): 
    print("\nBEWARE! YOU ARE ENTERING FIZZ DUNGEON!\n")
else: 
    print("\nFizz dungeon is full of mysteries. \nYou cannot resist, despite the danger.\n")

print("Traveler, it is unlikely you will survive FIZZ DUNGEON.")

a = input("ready? ")

while True:

    print("\n\n***FIZZ DUNGEON***\n\n")


    print("You descend into fizz dungeon with naught but your wits and your trusty sword Fizz. ")
    print("\nYou see a small dagger on the ground.")

    input("\nThe dagger seems to have an inscription on it.")

    print("\nIt says \'Buzz\' in elven script. You decide to keep it. You can wield it by typing \'b\'.")

    a = input("\nDescend to the first floor?")
    while a == "b": a=input("you flail around wildly with the dagger.")

    print("\nYou cannot resist the call of the dungeon, and descend into the first floor.\n\n1\n There is a large face suspended in the middle of the room, that seems to mirror your own. You say to yourself: this can't be real!")

    a=input("\nPress enter to walk safely through the illusion: ")
    while a not in acc: a=input("just enter, not anything else.")
    if a == "b":
        print("\nYou swing your dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break
    if a == "f":
        print("\nYou swing your sword wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break
        
    print("\nAs you step through the illusion, it disperses in a cold fog that makes you shiver to your core.")
    
    print("\n2\nYou enter the second room, and two giant eyes stare back at you. They blink when you blink. You realize they are another illusion, of your own eyes.")

    a=input("Press enter to walk safely through the illusion: ")
    while a not in acc: a=input("just enter, not anything else.")
    if a == "b":
        print("\nYou swing your dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break
    if a == "f":
        print("\nYou swing your sword wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break    
    if a == "fb":
        print("\nYou swing your sword and dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break
        
    print("\nYou made it to room 3!")
    print("You see three skeletons. You can smell their rotting flesh, hear the scrape of their bones.")
    print("Your trusty sword Fizz might be up to the task!")
    a=input("type \'f\' to use your sword Fizz: ")
    
    while a not in acc: a=input("use enter, f, b, or fb.")
    if a == "b":
        print("\nYou try to sneak up and dagger a skeleton with Buzz, but fail. Another skeleton grabs you and you get eated. \n\nYOU DIE")
        break
    elif a == "": 
        print("\nYou attempt to walk through the skeletons and they find you a convenient, defenseless snack.\n\n YOU DIE")
        break  
    elif a == "fb":
        print("\nYou swing your sword and dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        break
    elif a == "f":
        print("Bones crunch and fly as you gallantly slice apart the three skeletons.")
    
    room = 4
    while room<101:
        print(room)
        print("You made it to room", room,"!")
        mon = adj[random.randint(0, len(adj)-1)] + " " + monsters[random.randint(0, len(monsters)-1)]
        print("You see",room,mon,". How will you get past?")
        a = input()
        success = fight(a,room,mon)
        if not success: break
        room += 1
    if success: print("You have escaped Fizz Dungeon!!!")

print("Thank you for playing!!!")

44: Inverse Fizzbuzz

In [ ]:
for i in range(1,101):
    if i%3 == 0 or i%5 == 0: print(i)
    else: print("fizzbuzz")

45: Sets

Let's use some set operations! I want to ampersand something!

In [ ]:
numberSet = set()
fizzSet = set()
buzzSet = set()
    
for i in range(1,101): 
    numberSet.add(i)
    if i%3 == 0: fizzSet.add(i)
    if i%5 == 0: buzzSet.add(i)
        
fizzbuzzSet = fizzSet & buzzSet   # <---- AMPERSAND SET INTERSECTION! :D
numberSet -= (fizzSet.union(buzzSet))
fizzSet -= fizzbuzzSet
buzzSet -= fizzbuzzSet

setSet = [numberSet,fizzSet,buzzSet,fizzbuzzSet]
setDict = [0,'fizz','buzz','fizzbuzz']

for i in range(0,101):
    for j in range(4):
        if i in setSet[j]: 
            if setDict[j] != 0: print(setDict[j])
            else: print(i)

46: Venn Fizz Buzz

I do like venndiagrams, and apparently matplotlib has them?

MUST VENN MY FIZZBUZZ

ok I guess this version doesn't come with venns? I dunno, can't get itto work. we'll just MAKE OUR OWN AND IT WILL BE BEAUTIFUL

In [ ]:
numberSet = set()
fizzSet = set()
buzzSet = set()
    
for i in range(1,101): 
    numberSet.add(i)
    if i%3 == 0: fizzSet.add(i)
    if i%5 == 0: buzzSet.add(i)
        
fizzbuzzSet = fizzSet & buzzSet
numberSet -= (fizzSet.union(buzzSet))
fizzSet -= fizzbuzzSet
buzzSet -= fizzbuzzSet

print("                                                         ")
print("         fizz                           buzz             ")
print("     ----------------      -------------------    ")
print('   /                   \\ /                    \\   ')
print('  |  ',fizzSet)
print('  |                    |  |                     |')
print('  |                   |    |                     |')
print('  |                   |',fizzbuzzSet)
print('  |                    |   /                     |')
print("  \\                     /\\      ",buzzSet)
print("   \\                   /  \\                   /")
print("      -----------------      -----------------")
print("")
print(numberSet)

Yes, so beautiful.

Also I clearly don't know a lot about how to python sets because I have no idea how to get anything out of them.

47: Do I remember how to dataframe?

apparently not. But this is why we do things 50 times, and also search the same things on stack overflow over and over.

also logic!

In [ ]:
import pandas as pd

numberData = []
fizzData = []
buzzData = []
fizzbuzzData = []

for i in range(0,101):
    div3 = not bool(i%3)
    div5 = not bool(i%5)
    numberData.append(not div3 or div5)
    fizzData.append(div3 and not div5)
    buzzData.append(not div3 and div5)
    fizzbuzzData.append(div3 and div5) 
    
setFrame = pd.DataFrame({'number':numberData,'fizz':fizzData,'buzz':buzzData,'fizzbuzz':fizzbuzzData})
setFrame

48: Text Adventure with Sound

First, let's create some sound effects!

I'm going to modify our old synth function and play with new noises:

In [ ]:
import random
import numpy as np
from IPython.display import (
    Audio, display, clear_output)

# create synth stuff:

def play(freqs):
    rate = 16000.
    duration = freqs[0]
    t = np.linspace(
        0., duration, int(rate * duration))
    x = np.sin(freqs[0] * 2. * np.pi * t)
    for i in range(1,len(freqs)):
        x = np.append(x, np.sin(freqs[i] * 2. * np.pi * t))
    display(Audio(x, rate=rate, autoplay=True))
    
# Make new sounds!!!
bling = [0.1,350,450,530,700]
bloo = [1,200,190,180]

footsteps = [0.006]
for i in range(5): #number of footsteps
    for i in range(1,31): footsteps.append(random.randint(int(8+100*(1/i)), int(200+ 500*(1/i))))
    for i in range(1,21): footsteps.append(0)

shiny = [0.1,960,1450]

buzzfx = [0.05]
for i in range(10):
    buzzfx.append(random.randint(100,2000))
    
fizzfx = [0.05]
for i in range(5):
    fizzfx.append(200 + 40*(i%2))
    
enterfx = [0.05]
for i in range(10):
    enterfx.append(i*100)

play(enterfx)

Now let's integrate some of our new sounds into our dungeon fizz adventure!

Dungeon Fizz Adventure

In [ ]:
import random
import numpy as np
from IPython.display import (
    Audio, display, clear_output)

# create synth stuff:

def play(freqs):
    rate = 16000.
    duration = freqs[0]
    t = np.linspace(
        0., duration, int(rate * duration))
    x = np.sin(freqs[0] * 2. * np.pi * t)
    for i in range(1,len(freqs)):
        x = np.append(x, np.sin(freqs[i] * 2. * np.pi * t))
    display(Audio(x, rate=rate, autoplay=True))
    
# Create sounds:

bling = [0.1,350,450,530,700]
bloo = [1,200,190,180]
shiny = [0.1,960,1450]

footsteps = [0.006]
for i in range(5): #number of footsteps
    for i in range(1,31): footsteps.append(random.randint(int(8+100*(1/i)), int(200+ 500*(1/i))))
    for i in range(1,21): footsteps.append(0)
    
audioFuzz = [0.20]
for i in range(1,75): 
    if i%3+i%5 == 0: audioFuzz.append(800)
    elif i%3==0: audioFuzz.append(600)
    elif i%5==0: audioFuzz.append(700)
    else: audioFuzz.append(220+i)
        
buzzfx = [0.05]
for i in range(10):
    buzzfx.append(random.randint(100,2000))

# Set up monster types

monsters = ["bats","bears","dungeon mice","fizz snakes", "buzzbees", "growlumps", "wolfizzes", "robots", "buzzdemons", "fizzfoxes", "owls", "ligers", "spiders", "buglets", "fleas", "brains"]
adj = ["", "", "evil","sticky","demonic","angry","slimy","wobbly","buzzing","fizzing","hairy","giant", "horrifying", "growling", "drooling", "scary", "floating", "flying", "crawling", "red", "black", "purple"]
verb = ["growl", "stare", "ooze", "buzz", "fizz"]
adv = ["", "", "angrily", "demonically", "agressively", "spookily", "with contempt", "sneakily"]

#acceptable inputs
acc = ["", "f", "b", "fb", "q"]

#fizzbuzz for winning strategy for each level
win = [0]
for i in range(1,101):
    if i%3+i%5 == 0: win.append("fb")
    elif i%5==0: win.append("b")
    elif i%3==0: win.append("f")
    else: win.append("")

#Fight on each level. (input, room, monster)
def fight(a,r,m):
    while a not in acc: 
        a = input("enter to walk through, f for Fizz, b for Buzz, fb to dual wield, q to quit: ")
        print("The", m, verb[random.randint(0, len(verb)-1)], adv[random.randint(0, len(adv)-1)]) 
    if a == "q":
        return False
    if a == win[r]:
        play(bling)
        if a == "": 
            print("\nYou walk through the illusory",m)
        else:
            if a == "f": 
                print("\nYou sword the", m,"to death!")
            elif a == "b": 
                print("\nYou stab every single one of the",m)
            else: 
                print("\nYou dual wield to victory over the",m)
        return True
    else:
        play(bloo)
        if a == "": print("\nOH NO, turns out the",m,"aren't illusions!")
        else: print("\nYou try to defeat the", m,"but are wielding the wrong weapon!")
        return False
    
# death sequence and ask to play again

def death():
    print("\n\nYOU DIE\n")
    play(bloo)
    a = input("Dare you attempt the dungeon again? y/n: ")
    if a.lower() == ("y" or "yes"): 
        descend()
    else:
        return


# oh, let's make the meat of the game a function?

def descend(): 

    print("\n\n***FIZZ DUNGEON***\n\n")
        
    # The first three rooms are done by hand as a tutorial:

    print("\nYou cannot resist the call of the dungeon, and descend into the first floor with your trusty sword Fizz and your new dagger Buzz.\n")
    play(footsteps)
    print("\n1\n There is a large face suspended in the middle of the room, that seems to mirror your own. You say to yourself: this can't be real!")

    a=input("\nPress enter to walk safely through the illusion: ")
    while a not in acc: a=input("just enter, not anything else.")
    if a == "b":
        print("\nYou swing your dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()
        return
    elif a == "f":
        print("\nYou swing your sword wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death() 
        return
    elif a == "fb":
        print("\nYou swing your sword and dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()
        return
    elif a == "q":
        return
          
    play(bling)    
    print("\nAs you step through the illusion, it disperses in a cold fog that makes you shiver to your core.")
    
    print("\n2\nYou enter the second room, and two giant eyes stare back at you. They blink when you blink. \n\nYou realize they are another illusion, of your own eyes.")

    a=input("Press enter to walk safely through the illusion: ")
    while a not in acc: a=input("just enter, not anything else.")
    if a == "b":
        print("\nYou swing your dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()
        return
    elif a == "f":
        print("\nYou swing your sword wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()  
        return
    elif a == "fb":
        print("\nYou swing your sword and dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()
        return
    elif a == "q":
        return
        
    play(bling)    
    print("\nYou made it to room 3!")
    print("You see three skeletons. You can smell their rotting flesh, hear the scrape of their bones.")
    print("Your trusty sword Fizz might be up to the task!")
    a=input("type \'f\' to use your sword Fizz: ")
    
    while a not in acc: a=input("use enter, f, b, or fb.")
    if a == "b":
        print("\nYou try to sneak up and dagger a skeleton with Buzz, but fail. Another skeleton grabs you and you get eated. \n\nYOU DIE")
        death()
        return
    elif a == "": 
        print("\nYou attempt to walk through the skeletons and they find you a convenient, defenseless snack.\n\n YOU DIE")
        death() 
        return
    elif a == "fb":
        print("\nYou swing your sword and dagger wildly at the illusion and accidentally stab yourself. \n\nYOU DIE")
        death()
        return
    elif a == "q":
        return
    elif a == "f":
        print("Bones crunch and fly as you gallantly slice apart the three skeletons.")
        play(bling)

    # Here's where we loop over the rooms 4-100 with random monsters
        
    room = 4
    while room<101:
        print(room)
        print("You made it to room", room,"!")
        m = adj[random.randint(0, len(adj)-1)] + " " + monsters[random.randint(0, len(monsters)-1)]
        print("You see",room,m,". How will you get past?")
        print("The", m, verb[random.randint(0, len(verb)-1)], adv[random.randint(0, len(adv)-1)]+".")  
        a = input()
        success = fight(a,room,m)
        if not success: 
            death()
            return
        room += 1
    if success: 
        print("You have escaped Fizz Dungeon!!!")
        play(audioFuzz) 
    return
    
#Start game

play(audioFuzz) 

ask = input("Dare you descend into Fizz Dungeon? Y/N: ").lower()

while ask == "n": ask = input("Too scared? Come on. Play a game y/n? ")
    
if ask == ("y" or "yes"): 
    print("\nBEWARE! YOU ARE ENTERING FIZZ DUNGEON!\n")
else: 
    print("\nFizz dungeon is full of mysteries. \nYou cannot resist, despite the danger.\n")

print("Traveler, it is unlikely you will survive FIZZ DUNGEON.")

play(footsteps)

a = input("ready? ")

while a == ("n" or "no"): print("Just let me know when you're ready. How bout now? ")

play(footsteps)
print("You descend into fizz dungeon with naught but your wits and your trusty sword Fizz. ")
print("\nYou see a small dagger on the ground.")

input("\nThe dagger seems to have an inscription on it.")
play(shiny)
print("\nIt says \'Buzz\' in elven script. You decide to keep it. You can wield it by typing \'b\'.")

a = input("\nIT IS TIME TO DESCEND TO THE FIRST FLOOR.")
while a == "b": 
    play(buzzfx)
    a=input("you flail around wildly with the dagger.")

descend()

print("Thank you for playing!!!")

A classic for the ages.

Let's scale back a bit though, I feel like our fizzbuzzes are starting to suffer from feature bloat.

49: Data Analysis Predictor

Let's forget games and get computer science serious by analyzing the data again.

We'll start with just the first 20 correct outputs as a dataframe, and do dataframe analysises to it!

In [ ]:
import pandas as pd
fizz20 =pd.DataFrame([1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16, 17, 'fizz', 19, 'buzz'])

fizz20.describe()

As we can see, according to data analysis techniques fizzbuzz trends towards 'fizz', and so we can more accurately represent fizzbuzz by leveraging this statistical inevitability:

In [ ]:
for i in range(100): print(fizz20.mode())

Are those weird extra zeroes because I don't remember how to get just that cell of the dataframe? Or because I don't know the best method to just get the mode without a dataframe around it?

No!

Those are not zeroes, they are fizzy bubbles rising to victory because WE PREDICTED FIZZBUZZ USING DATASCIENCE!!!!

(Innaccuracies you say? Well of course statistical methods are never 100% accurate, they're STATISTICAL. That's what that means. But in the long run we've got to trust the computer, which isn't plagued by biased opinions like "where's buzz, there should be more buzz" or "this just doesn't look right to me". Your perception is only human, it's not your fault!)

Ok, it is finally time for:

50: The Fizzbuzz To End All Fizzbuzzes

In [ ]:
lamentationPre = ["Goodbye ", 'I cry at the thought this could be the last ', "Alas! ", "We weep for ", 'Ah, what a beautiful ',"Rest in peace, dear ", "Like a butterfly emerged too early in spring appears ", "God have mercy on "]
lamentationSuf = [", farewell.", ", life is so fragile!", ", alas! alas!", ". How could the universe allow this to happen?", ", you were loved.", ". Why? Why?", ", such is the human condition.", ", a bubble in the stream.", ", we will try to carry on nonetheless."]
for i in range(1,101):
        print(
            lamentationPre[i%len(lamentationPre)] +
            str(i)*bool(i%3*i%5) +
            'Fizz'*bool(not i%3) +
            'Buzz'*bool(not i%5) +
            lamentationSuf[i%len(lamentationSuf)] +
            "\n"
        )