Homework 3

Due Tuesday 12-Sep, at 10:00pm


To start

  1. Create a folder named ‘hw3’
  2. Download hw3.py to that folder
  3. Edit hw3.py and modify the functions as required
  4. When you have completed and fully tested hw3, submit hw3.py to Gradescope. For this hw, you may submit up to 15 times, but only your last submission counts.

Some important notes

  1. This homework is solo. You may not collaborate or discuss it with anyone outside of the course, and your options for discussing with other students currently taking the course are limited. See the academic honesty policy for more details.
  2. After you submit to Gradescope, make sure you check your score. If you aren’t sure how to do this, then ask a CA or Professor.
  3. There is no partial credit on Gradescope testcases. Your Gradescope score is your Gradescope score.
  4. Read the last bullet point again. Seriously, we won’t go back later and increase your Gradescope score for any reason. Even if you worked really hard and it was only a minor error…
  5. Do not hardcode the test cases in your solutions.
  6. The starter hw3.py file includes test functions to help you test on your own before you submit to Gradescope. When you run your file, problems will be tested in order. If you wish to temporarily bypass specific tests (say, because you have not yet completed some functions), you can comment out individual test function calls at the bottom of your file in main(). However, be sure to uncomment and test everything together before you submit! Ask a CA if you need help with this.
  7. Remember the course’s academic integrity policy. Solving the homework yourself is your best preparation for exams and quizzes; cheating or short-cutting your learning process in order to improve your homework score will actually hurt your course grade long-term.

Limitations

Do not convert strings to lists, use lists or recursion this week. The autograder (or a manual CA review later) will reject your submission entirely if you do.

A Note About Style Grading

Starting with this assignment, we will be grading your code based on whether it follows the 15-112 style guide. We may deduct up to 10 points from your overall grade for style errors. We highly recommend that you try to write clean code with good style all along, rather than fixing your style issues at the end. Good style helps you code faster and with fewer bugs. It is totally worth it. In any case, style grading starts this week, so please use good style from now on!

A Note About Testing

You will notice that the skeleton file only includes testcases for some of the functions you are writing. You should write testcases for the others. (You can find some nice ways to test in the write-up below, but you will need to translate those to actual testcases.)


Problems

  1. consonantCount(s) [5 pts]
    Write the function consonantCount(s), that takes a string s, and returns the number of consonants in s, ignoring case, so "B" and "b" are both consonants. The consonants are all of the English letters except "a", "e", "i", "o", and "u". So, for example:
    assert(consonantCount("Abc def!!! a? yzyzyz!") == 10)

  2. isFloat(n) [10 pts]
    We have seen in some lecture notes that if we want to read a float from the user, we use the function input() to read a string from the user and then use the function float() to convert that string to a float number. We also learned that if the user enters an invalid number, our program will crash. Now we don't like programs that crash. So, we would like to check if a string can be a float before we attempt to convert it to a float. This way, if the string is not float, we can print an error message and exit gracefully instead of crashing the program. If would be nice to have a function called isFloat that takes an input of string and returns back True if the input is a valid float and False if it is not. We can use this function in our programs as given below:
    inp = input("Enter your QPA: ") if( not isFloat(inp)): print ()"You entered a value that is not a valid QPA. Exiting gracefully :)") exit() else: # we can safely decode the float now qpa = float(inp)
    Your task is to write the isFloat function that checks the string passed to it for validity of being a float number. If the input is a valid float number, it should return True, otherwise, it should return False. We will be calling the function as shown in the above example, so make sure the return values, function name, and input parameters are appropriate. You should NOT use a try/except structure for this function.

  3. applyVigenereCipher(msg, key) [10 pts]
    Background: As you have learned in CS Academy, a Caesar Cipher takes a message and a shift, and encodes each letter by shifting it by the given amount. We can strengthen this by changing the amount we shift each letter by. For example, say we have the message 'ABC' and we use the shifts 3,4,5. Then we shift 'A' by 3 to get 'D', we shift 'B' by 4 to get 'F', and we shift 'C' by 5 to get 'H'. So the encoded message is 'DFH'. Next, instead of listing the shifts as numbers, we can encode the shifts themselves in a string which we will call the key. Here, 'A' is 0, 'B' is 1, and so on. So the shifts 3,4,5 will be represented by the key 'DEF'. Finally, what happens if our key is shorter than our message? In that case, we will repeat the key until it is as long or longer than the message. For example, if we have the message 'FGHIJ' and the key 'AB', we first repeat the key to get 'ABABAB'. Now encode the message as just described with this key. A Vigenere Cipher works in this way. It takes a message and a key, repeats the key until it is at least as long as the message, and then uses the key to find the shift for each corresponding letter in the message. With this in mind, write the function applyVigenereCipher(msg, key) which returns the encoded message that results from perfoming a Vigenere Cipher on msg with the given key. Some notes:
    • The message may be uppercase or lowercase. As usual, preserve the case when you shift letters.
    • The key is always uppercase.
    • The message can contain non-letter characters, and these are not shifted, so they appear in the result exactly as they did in the original message.
    assert(applyVigenereCipher("FGHIJ", "AB") == "FHHJJ")

  4. topScorer(data) [15 pts]
    Write the function topScorer(data) that takes a multi-line string encoding scores as csv data for some kind of competition with players receiving scores, so each line has comma-separated values. The first value on each line is the name of the player (which you can assume has no integers in it), and each value after that is an individual score (which you can assume is a non-negative integer). You should add all the scores for that player, and then return the player with the highest total score. If there is a tie, return all the tied players in a comma-separated string with the names in the same order they appeared in the original data. If nobody wins (there is no data), return None (not the string "None"). So, for example:
    data = '''\ Fred,10,20,30,40 Wilma,10,20,30 ''' assert(topScorer(data) == 'Fred') data = '''\ Fred,10,20,30 Wilma,10,20,30,40 ''' assert(topScorer(data) == 'Wilma') data = '''\ Fred,11,20,30 Wilma,10,20,30,1 ''' assert(topScorer(data) == 'Fred,Wilma') assert(topScorer('') == None)
    Hint: you may want to use both splitlines() and split(',') here!

  5. mostFrequentSubstring(text, n) [20 pts]
    Given a string text your task is to find the most frequently occuring substring of a given length. In the event of a tie between two substrings, follow alphabetic order. Consider the following example in which the length is three (n = 3) and the text is just baababacb. The most frequent substring would then be aba because this is the substring with size 3 that appears most often in the whole text (it appears twice) while the other six different substrings appear only once (baa ; aab ; bab ; bac ; acb). You can assume length >= 0. Here are more examples:
    assert(mostFrequentSubstring("baababacb", 3) == "aba") assert(mostFrequentSubstring("thequickbrownfoxjumpsoverthelazydog", 1) == "o") assert(mostFrequentSubstring("testingthecodetofindtheerrortestandtestagain", 4) == "test")

  6. patternedMessage(message, pattern) [25 pts]
    Write the function patternedMessage(message, pattern) that takes two strings, a message and a pattern, and returns a string produced by replacing the non-whitespace characters in the pattern with the non-whitespace characters in the message (where any leading or trailing newlines in the pattern are first removed). As a first example:

    callresult
    patternedMessage("Go Pirates!!!", """
    ***************
    ******   ******
    ***************
    """)
    
    GoPirates!!!GoP
    irates   !!!GoP
    irates!!!GoPira
    

    Here, the message is "Go Pirates!!!" and the pattern is a block of asterisks with a few missing in the middle. Notice how the whitespace in the pattern is preserved, but the whitespace in the message is removed. Again, note that any leading or trailing newlines in the pattern are removed.

    Here is another example:

    callresult
    patternedMessage("Three Diamonds!","""
        *     *     *
       ***   ***   ***
      ***** ***** *****
       ***   ***   ***
        *     *     *
    """)
    
        T     h     r
       eeD   iam   ond
      s!Thr eeDia monds
       !Th   ree   Dia
        m     o     n
    

    Hint: While you may solve this how you wish, our sample solution did not use replace in any way. Instead, we started with the empty string, and built up the result character by character. How did we determine the next character? Using both the message and the pattern in some way...

    And here is one last example, just for fun:

    patternedMessage("Go Steelers!",
    """
                              oooo$$$$$$$$$$$$oooo
                          oo$$$$$$$$$$$$$$$$$$$$$$$$o
                       oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o         o$   $$ o$
       o $ oo        o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o       $$ $$ $$o$
    oo $ $ '$      o$$$$$$$$$    $$$$$$$$$$$$$    $$$$$$$$$o       $$$o$$o$
    '$$$$$$o$     o$$$$$$$$$      $$$$$$$$$$$      $$$$$$$$$$o    $$$$$$$$
      $$$$$$$    $$$$$$$$$$$      $$$$$$$$$$$      $$$$$$$$$$$$$$$$$$$$$$$
      $$$$$$$$$$$$$$$$$$$$$$$    $$$$$$$$$$$$$    $$$$$$$$$$$$$$  '$$$
       '$$$'$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     '$$$
        $$$   o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     '$$$o
       o$$'   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$       $$$o
       $$$    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$' '$$$$$$ooooo$$$$o
      o$$$oooo$$$$$  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$   o$$$$$$$$$$$$$$$$$
      $$$$$$$$'$$$$   $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$     $$$$'
     ''''       $$$$    '$$$$$$$$$$$$$$$$$$$$$$$$$$$$'      o$$$
                '$$$o     '$$$$$$$$$$$$$$$$$$'$$'         $$$
                  $$$o          '$$'$$$$$$'           o$$$
                   $$$$o                                o$$$'
                    '$$$$o      o$$$$$$o'$$$$o        o$$$$
                      '$$$$$oo     '$$$$o$$$$$o   o$$$$'
                         '$$$$$oooo  '$$$o$$$$$$$$$'
                            '$$$$$$$oo $$$$$$$$$$
                                    '$$$$$$$$$$$
                                        $$$$$$$$$$$$
                                         $$$$$$$$$$'
                                          '$$$'
    """)
    

    Returns this:

                              GoSteelers!GoSteeler
                          s!GoSteelers!GoSteelers!GoS
                       teelers!GoSteelers!GoSteelers!GoS         te   el er
       s ! Go        Steelers!GoSteelers!GoSteelers!GoSteel       er s! GoSt
    ee l e rs      !GoSteeler    s!GoSteelers!    GoSteelers       !GoSteel
    ers!GoSte     elers!GoSt      eelers!GoSt      eelers!GoSt    eelers!G
      oSteele    rs!GoSteele      rs!GoSteele      rs!GoSteelers!GoSteeler
      s!GoSteelers!GoSteelers    !GoSteelers!G    oSteelers!GoSt  eele
       rs!GoSteelers!GoSteelers!GoSteelers!GoSteelers!GoSteel     ers!
        GoS   teelers!GoSteelers!GoSteelers!GoSteelers!GoSteelers     !GoSt
       eele   rs!GoSteelers!GoSteelers!GoSteelers!GoSteelers!GoSt       eele
       rs!    GoSteelers!GoSteelers!GoSteelers!GoSteelers!Go Steelers!GoSteele
      rs!GoSteelers  !GoSteelers!GoSteelers!GoSteelers!GoS   teelers!GoSteelers
      !GoSteelers!G   oSteelers!GoSteelers!GoSteelers!Go     Steel
     ers!       GoSt    eelers!GoSteelers!GoSteelers!G      oSte
                elers     !GoSteelers!GoSteelers!         GoS
                  teel          ers!GoSteel           ers!
                   GoSte                                elers
                    !GoSte      elers!GoSteele        rs!Go
                      Steelers     !GoSteelers!   GoStee
                         lers!GoSte  elers!GoSteeler
                            s!GoSteele rs!GoSteel
                                    ers!GoSteele
                                        rs!GoSteeler
                                         s!GoSteeler
                                          s!GoS

  7. BONUS: bonusGetEvalSteps(expr)[2 pts]
    Write the function bonusGetEvalSteps(expr), that takes a string containing a simple arithmetic expression, and returns a multi-line string containing the step-by-step (one operator at a time) evaluation of that expression. For example, this call:
    bonusGetEvalSteps("2+3*4-8**3%3")
    
    produces this result (which is a single multi-line string):
    2+3*4-8**3%3 = 2+3*4-512%3
                 = 2+12-512%3
                 = 2+12-2
                 = 14-2
                 = 12
    
    Here are some considerations and hints:
    • You are only responsible for legal input as described below. Numbers are limited to non-negative integers.
    • Operators are limited to +, -, *, //, %, and **.
    • All operators are binary, so they take two operands. So there are no unary operators, meaning "-5" is not a legal input. For that, you'd need "0-5".
    • In fact, the previous restriction is even stronger: no intermediate value of expr can be negative! So "1-2+3" is not legal, since it would be converted first into "-1+3" which is not legal. So you can safely ignore all such cases.
    • There are no parentheses.
    • Operators must be evaluated by precedence (** first, then *,//,%, then +,-).
    • Equal-precedence operators are evaluated left-to-right.
    • Evaluation proceeds until a single integer with no operators remains after the equals sign.
    • The equal signs must all be stacked directly over each other.
    • You may write this however you wish, though you may want to write a helper function that finds the next operator to be applied, and another helper function that just applies a single operator. Something like that. In any case, top-down design is crucial here. And don't forget to thoroughly test your helper functions before using them!
    • In our sample solution, we used very few string methods, just "find" and "isdigit". You may use others, but you should not spin your wheels trying to find that awesome string method that will make this problem remarkably easier, as that method does not exist.
    • For this function, as any other function, you may not use the eval function, so you will have to write your own equivalent just for the kinds of simple expressions you will deal with here. Eval is dangerous and should be avoided, as it can lead to serious bugs or security holes.

  8. BONUS: Crack the 112 code [2 pts]
    Your task is to discover our secret encoding scheme and to write the functions bonusEncode112(s) and bonusDecode112(s) that can bonusEncode and decode strings using it. Here's the one (an only) example we can give you:
    originalMessage = """In 15-112 at CMU, zealous learners study the diverse facets of programming. With joy, excitement and hard work, they quickly delve into algorithms, languages, and more, honing their skills to become the best programmers. """ # be careful with the end-of-lines encodedMessage = """___________ | o o. o| | oo o.oo | | o . | | oo . o| | oo .o o| | o o.o o| | oo . o| | oo . o| | oo . o | | o . | | oo . o| | ooo .o | | o . | | o . oo| | o o.o o| | o o .o o| | o o.o | | o . | | oooo. o | | oo .o o| | oo . o| | oo o.o | | oo o.ooo| | ooo .o o| | ooo . oo| | o . | | oo o.o | | oo .o o| | oo . o| | ooo . o | | oo o.oo | | oo .o o| | ooo . o | | ooo . oo| | o . | | ooo . oo| | ooo .o | | ooo .o o| | oo .o | | oooo. o| | o . | | ooo .o | | oo o. | | oo .o o| | o . | | oo .o | | oo o. o| | ooo .oo | | oo .o o| | ooo . o | | ooo . oo| | oo .o o| | o . | | oo .oo | | oo . o| | oo . oo| | oo .o o| | ooo .o | | ooo . oo| | o . | | oo o.ooo| | oo .oo | | o . | | ooo . | | ooo . o | | oo o.ooo| | oo .ooo| | ooo . o | | oo . o| | oo o.o o| | oo o.o o| | oo o. o| | oo o.oo | | oo .ooo| | o o.oo | | o . | | o. o | | o o .ooo| | oo o. o| | ooo .o | | oo o. | | o . | | oo o. o | | oo o.ooo| | oooo. o| | o o.o | | o . | | oo .o o| | oooo. | | oo . oo| | oo o. o| | ooo .o | | oo .o o| | oo o.o o| | oo .o o| | oo o.oo | | ooo .o | | o . | | oo . o| | oo o.oo | | oo .o | | o . | | oo o. | | oo . o| | ooo . o | | oo .o | | o . | | ooo .ooo| | oo o.ooo| | ooo . o | | oo o. oo| | o o.o | | o . | | ooo .o | | oo o. | | oo .o o| | oooo. o| | o . | | ooo . o| | ooo .o o| | oo o. o| | oo . oo| | oo o. oo| | oo o.o | | oooo. o| | o . | | oo .o | | oo .o o| | oo o.o | | ooo .oo | | oo .o o| | o . | | oo o. o| | oo o.oo | | ooo .o | | oo o.ooo| | o . | | oo . o| | oo o.o | | oo .ooo| | oo o.ooo| | ooo . o | | oo o. o| | ooo .o | | oo o. | | oo o.o o| | ooo . oo| | o o.o | | o . | | oo o.o | | oo . o| | oo o.oo | | oo .ooo| | ooo .o o| | oo . o| | oo .ooo| | oo .o o| | ooo . oo| | o o.o | | o . | | oo . o| | oo o.oo | | oo .o | | o . | | oo o.o o| | oo o.ooo| | ooo . o | | oo .o o| | o o.o | | o . | | oo o. | | oo o.ooo| | oo o.oo | | oo o. o| | oo o.oo | | oo .ooo| | o . | | ooo .o | | oo o. | | oo .o o| | oo o. o| | ooo . o | | o . | | ooo . oo| | oo o. oo| | oo o. o| | oo o.o | | oo o.o | | ooo . oo| | o . | | ooo .o | | oo o.ooo| | o . | | oo . o | | oo .o o| | oo . oo| | oo o.ooo| | oo o.o o| | oo .o o| | o . | | ooo .o | | oo o. | | oo .o o| | o . | | oo . o | | oo .o o| | ooo . oo| | ooo .o | | o . | | ooo . | | ooo . o | | oo o.ooo| | oo .ooo| | ooo . o | | oo . o| | oo o.o o| | oo o.o o| | oo .o o| | ooo . o | | ooo . oo| | o o.oo | | o. o | ___________""" assert(bonusEncode112(originalMessage) == encodedMessage) assert(bonusDecode112(encodedMessage) == originalMessage)