15-112 Fall 2014 Homework 5
Due Sunday, 28-Sep, at 10pm

Read these instructions first!
  1. nondestructiveRotateList(a, n) [5 pts] [autograded]
    Write the function nondestructiveRotateList(a, n) which takes a list a and an integer n, and nondestructively modifies the list so that each element is shifted to the right by n indices (including wraparound). The function should then return this new list. For example:
        nondestructiveRotateList([1,2,3,4], 1) -> [4,1,2,3]
        nondestructiveRotateList([4,3,2,6,5], 2) -> [6, 5, 4, 3, 2]
        nondestructiveRotateList([1,2,3], 0) -> [1,2,3]
        nondestructiveRotateList([1, 2, 3], -1) -> [2, 3, 1]
    

  2. destructiveRotateList(a, n) [5 pts] [autograded]
    This function works the same as the previous function, only here it is destructive. That is, it directly changes the list a, so after the call, that exact list is rotated n indices to the right with wraparound, and a new list is not created. As usual for destructive functions, this function returns None. Also: you may not call the nondestructive version here, and in fact, you may not even create a new list (or tuple or other similar data structure) that is longer than 2 elements! While you must be space-efficient here, we do not expect the most time-efficient approach; anything reasonable (for 15-112) will do.

  3. histogram(a) [10 pts] [autograded]
    Write the function histogram(a) that takes a non-empty list of integers between 0 and 100, inclusive, representing exam scores, and returns a string representing a histogram of that data. The details can be gleaned from this example:
        assert(histogram([73, 62, 91, 74, 100, 77]) == """\
    60-69: *
    70-79: ***
    80-89:
    90++ : **
    """)
    
    Note that the histogram should start with the first range which is non-zero, and end with the last range which is non-zero. So if the lowest score is 72, the first range should be 70-79. And if in the same example the highest score was 78, then the *only* range would be 70-79. Also, the 0-9 range should be 00-09. Do not worry about an empty list, it is guaranteed to contain at least one value.

  4. lookAndSay(a) [10 pts] [autograded]
    First, read about look-and-say numbers here. Then, write the function lookAndSay(a) that takes a list of numbers and returns a list of numbers that results from "reading off" the initial list using the look-and-say method, using tuples for each (count, value) pair. For example:
         lookAndSay([]) == []
         lookAndSay([1,1,1]) == [(3,1)]
         lookAndSay([-1,2,7]) == [(1,-1),(1,2),(1,7)]
         lookAndSay([3,3,8,-10,-10,-10]) == [(2,3),(1,8),(3,-10)]
    

  5. inverseLookAndSay(a) [10 pts] [autograded]
    Write the function inverseLookAndSay(a) that does the inverse of the previous problem, so that, in general:
        inverseLookAndSay(lookAndSay(a)) == a
    
    Or, in particular:
        inverseLookAndSay( [(2,3),(1,8),(3,-10)]) --> [3,3,8,-10,-10,-10]
    

  6. superSimpleCalculator(app, canvas) [30 pts] [manually graded]
    Write the function superSimplecalculator that implements a basic interactive graphics program, as covered here. Your program should work as described in this video. You do not have to match the example in the video perfectly, but you should be quite close, as judged by a quick visual inspection. Note that you may wish to use try/except to handle the errors in eval. Also, as explained in a piazza post, note that you will need to use event.char, which is similar to event.keysym but different for characters like punctuation where there is both a character like "+" and a name like "Plus". In any case, you should use event.char for this problem.

  7. drawPolygonPointsWithUndoRedo(app, canvas) [30 pts] [manually graded]
    Write the function drawPolygonPointsWithUndoRedo that implements a basic interactive graphics program, and work as described in this video. Again, you do not have to match the example in the video perfectly, but you should be quite close, as judged by a quick visual inspection.

  8. Bonus/Optional: drawPolygonPointsWithCentroid(app, canvas) [2 pts] [manually graded]
    First, read this page on centroids. As it says: "the point at which a cardboard cut-out of the region could be perfectly balanced on the tip of a pencil". We will do exactly that here. First, write the function drawPolygonPointsWithCentroid that works like your previous polygon drawing function, only now it also always clearly displays the centroid of the polygon. Then, using your program, draw an interesting, and definitely irregular polygon. Then, take a screenshot and print it out. Then paste or tape it to cardboard (say, from a cereal box, though thicker cardboard may work better). Carefully cut out the polygon outline. Then stick a well-sharpened pencil in your centroid, and see if the cutout shape balances as predicted. For full credit, bring your cutout shape and pencil and show a CA at Monday OH that it indeed balances. For half credit, just write the function with the centroid. Full credit is more fun here, so we hope you do it!

  9. Bonus/Optional: motionAfterEffect(app, canvas) [4 pts] [manually graded]
    Write the function motionAfterEffect, which demonstrates the Motion Aftereffect as shown in the animation on this page. Actually, you are only responsible for the motion in the circle, and not for displaying the image (the Buddha). You also do not need any buttons or to respond to any keypresses (except as noted below) -- just play the animation. You may wish to use the canvas.create_arc method. Also, how to make an animation? You may not use anything but button or keyboard events this week (in particular, no timerFired or other time-based events), so here just advance the animation by one frame each time any key is pressed. In this way, the animation runs when the user simply holds in any key. Have fun!

Here are some hints and clarifications:
  1. How to test a destructive function?
    Say you have a destructive function f(a) and you want to test it. Since it returns None (right?), you can't just do:
       assert(f([1,2,3]) == "whatever we expect")
    Instead, assign it to a variable, call the destructive function, then do your test, like so:
       a = [1,2,3]
       f(a) # destructive
       assert(a == "whatever we expect")

  2. Animation: Relaxed line limit for animations this week
    Remember that there is no line limit just this week just for animations. 20 lines still apply in general, and 25-lines for non-animation graphics (which you might also have, say if you decide to use graphics helper functions for your animations).

  3. Animation parameters
    The parameters to your animations should be (app, canvas), like so:
       def superSimpleCalculator(app, canvas):...

  4. Animations use delete(ALL)
    Some of you are expressing concern over the inefficiency of deleting everything on every step, just to redraw all of it. Don't worry about it. This way is way easier than just changing what changed, and it is plenty fast enough for now. So for now (and for a while), everyone should just use delete(ALL) like we did in our examples.

  5. Animations do not use console input or output
    Animations must get their user input strictly via keypress events, and never via raw_input. And they must show their output strictly using graphics, and not via the console. You can use the console for debugging, but only for debugging. Think about it: when you use a GUI program (which is pretty much the only kind of program you probably use), do you ever see a text console? No!

  6. Calc: BackSpace is a keysym
    The problem correctly stated that you'll need to use event.char in your calculator. But it did not rule out using event.keysym, which in fact you will also need for backspace. Also, note that the keysym is "BackSpace", with an upper-case "S".

  7. Calc: 015 is octal!
    In Python, any number with a leading 0 is considered to be in octal (base 8). So 015 is actually decimal 13. This is also how your calculator will work. It's odd, but correct.

  8. Calc: use integer division
    You're just calling eval, so 18/5 will equal 3, naturally...

  9. Animations are underspecified !
    The animation videos do not specify everything. So you need to fill in the blanks with reasonable assumptions. Please do not ask on piazza for the "answers" to all these design decisions. Just make them, and be reasonable. For example, we do not specify the fonts we used (though we do have a preference for "Arial", though again, we never said that). And for a more technical example, in the calculator, we never say what to do with unused punctuation, such as $. You could make it an error, so don't add it to the text, and turn the text red. Or you could make it not an error, add it to the text, make the text blue, and then upon eval show the runtime error. This was not specified, so you have to choose which design seems to make more sense (to the user, that is).