"""
 fizzbuzz.py

 Playing around with the Fizz Buzz coding task;
 see for example http://wiki.c2.com/?FizzBuzzTest .

 tested with python 3.*

 Jim Mahoney | cs.marlboro.college | Nov 2019 | MIT License
"""

# -------------------------------------------------
print("-- imperative monolith --")

# Here I'm taking advantage of "or"'s shortcircuit trick.
# See for example 
# codereview.stackexchange.com/questions/9751/
# ultra-beginner-python-fizzbuzz-am-i-missing-something

for i in range(1,101):
    msg = ''
    if i % 3 == 0:
        msg = msg + 'Fizz'
    if i % 5 == 0:
        msg = msg + 'Buzz'
    print(msg or i)

# -----------------------------------
print("-- functions with doctests --")

def divides(small, big):
    """ return True if big / small is an integer,
        i.e. if small goes into big an integer number of times
        i.e. if small divides big 
        >>> divides(5, 25)
        True
        >>> divides(25, 5)
        False
        >>> divides(3, 7)
        False
    """
    return big % small == 0

def fizzbuzz(i):
    """ Return 'Fizz', 'Buzz', 'FizzBuzz', or i
        depending on whether i is divisible by 3, 5, both, or neither. 
        >>> fizzbuzz(1)
        '1'
        >>> fizzbuzz(9)
        'Fizz'
        >>> fizzbuzz(10)
        'Buzz'
        >>> fizzbuzz(15)
        'FizzBuzz'
    """
    if divides(3, i) and divides(5, i):
        return 'FizzBuzz'
    if divides(3, i):
        return 'Fizz'
    if divides(5, i):
        return 'Buzz'
    return str(i)

def main():
    for i in range(1,101):
        print(fizzbuzz(i))

if __name__ == '__main__':
    import doctest
    doctest.testmod()
    main()

# -------------------------------------
print("-- objects --")

class FBInt:
    """ An integer i that as a string is 
        'Fizz', 'Buzz', 'FizzBuzz', or str(i). """
    def __init__(self, i):
        self.i = i
    def __str__(self):
        result = ''
        if self.i % 3 == 0:
            result = result = 'Fizz'
        if self.i % 5 == 0:
            result = result = 'Buzz'
        if result:
            return result
        else:
            return str(self.i)

class FizzBuzz:
    """ A looper for the FizzBuzz problem """
    def __init__(self, low=1, high=100):
        self.low = low
        self.high = high
    def __str__(self):
        result = ''
        for i in range(self.low, self.high + 1):
            result = result + str(FBInt(i)) + "\n"
        return result

print(FizzBuzz(1, 100))

# -----------------------------------------------------
print('-- functional --')

# See https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions
# and https://docs.python.org/3/library/functions.html#map
# (Just one python statement!)

print('\n'.join(
        map( lambda i: 'FizzBuzz' if i % 15 == 0 else \
                       'Fizz'     if i %  3 == 0 else \
                       'Buzz'     if i %  5 == 0 else \
                        str(i),
          range(1, 101))))