CMU 15-112 Fall 2016: Fundamentals of Programming and Computer Science
Lab 10 (Due Thursday 3-Nov, at 10pm, no extensions or grace days)



  1. @noError decorator [20 pts] [autograded]
    Write the @noError function decorator so that the following test function works properly:
    def testNoErrorDecorator(): print("Testing @noError decorator...", end="") @noError def f(x, y): return x/y assert(f(1, 5) == 1/5) assert(f(1, 0) == None) @noError def g(): return 1/0 assert(g() == None) @noError def h(n): if (n == 0): return 1 else: return h(n+1) assert(h(0) == 1) assert(h(-1) == 1) assert(h(1) == None) print("Passed!")
    You may notice that a function decorated with @noError behaves the same, except if the original function would crash (technically, raise an exception), the decorated function instead just returns None. Be sure not to hardcode the number of parameters, so that your decorator works for a function no matter how many parameters it takes.

  2. findLargestFile(path) [40 pts] [autograded]
    Without using os.walk, write the recursive function findLargestFile(path), which takes a string path to a folder, returning the full path to the largest file in the folder (and all its subfolders). If there are no files, the empty string ("") is returned. Do not worry if the supplied path is not valid or is not a folder.

    Hint: to solve this, you may need the function os.path.getsize(path), which returns the size of the given file.

    Another hint: if it is more convenient, findLargestFile can be non-recursive so long as it calls a recursive helper function. To help test your code, here are some assertions for use with sampleFiles (available in sampleFiles.zip):
    assert(findLargestFile("sampleFiles/folderA") ==
                           "sampleFiles/folderA/folderC/giftwrap.txt")
    assert(findLargestFile("sampleFiles/folderB") ==
                           "sampleFiles/folderB/folderH/driving.txt")
    assert(findLargestFile("sampleFiles/folderB/folderF") == "")
    
    Note: regarding efficiency, it is overtly inefficient to call os.path.getsize(path) more than once for any given file. One way to manage this is to use a helper function that not only returns the largest file for a given path, but returns it in a tuple along with other information that may be of use (hint, hint). Then findLargestFile is a non-recursive wrapper function that calls that helper function.

    Also note: also regarding efficiency, it is overtly inefficient to create a list of files, say using listFiles. So you may not use listFiles here. Instead, you must compute the largestFile as you go, though perhaps returning it in a tuple to a wrapper function, as the previous note suggests.

    Finally: you may resolve ties as you wish.

  3. runMickeyFractalViewer() [40 pts] [manually graded]
    Below the #ignore_rest line, write a function mickeyFace(canvas, xc, yc, r) that draws a circular-shaped face of a Mickey-like character, without ears. This function takes as input a canvas to draw on, the (xc, yc) coordinates of the center of the face, and the radius r of the face. While you need not be pixel-perfect, try to make the face as close as possible to the one in the image below. Hint: to draw the mouth, you should use the function create_arc(...) of Tkinter. For more information about this function see http://infohost.nmt.edu/tcc/help/pubs/tkinter/canvas.html.

    Also below the #ignore_rest line, and exploiting your previous function mickeyFace, write a function fractalMickeyMouse(canvas, xc, yc, r, level) that recursively draws a character with the face you previously defined, and a recursively downsized version of that same face as ears. Your function will take as parameter a canvas to draw on, the (xc, yc) coordinates of the center of the face, the radius r of the face, and an integer level representing the maximum depth of recursion. The radius of each ear is exactly half the radius of the face. The following figure shows an example of a Fractal Mickey Mouse with maximum recursion level (depth) of 6.

    Also below the #ignore_rest line, write the function runMickeyFractalViewer() that behaves similarly to the Sierpinsky Triangle example in the course notes, where pressing arrows changes the depth of the recursion (though of course here you'll display recursive Mickey Mouses and not Sierpinsky Triangles).