# CMU 15-112 Spring 2018: Fundamentals of Programming and Computer Science Colab 3 (Due Thursday 01-Feb, at 10pm)

• This assignment is collaborative. That means you may work with other students enrolled in the course, and you may even help each other write code and debug. However, you must still type all of your own work, and you must fully understand the code that you submit. Even though this is collaborative, you may not directly copy any code from anyone, and you may not electronically share your code with anyone. See the syllabus for more details.
• List your collaboration partners (name and andrew id) in a comment on the first line of this file. If you collaborate with another student and do not include their name in a comment, it will be considered cheating. You may work alone if you want to, but we recommend working with others, as it generally leads to better learning.
• Be a good collaborator! Help everyone in your group, and accept their help if you need it. Don't be in a hurry to finish the problems. Instead, take your time and be sure that everyone in the group is following and understanding. The goal is to learn, not just to finish.
• If you're looking for more people to collaborate with, you can request to be paired up with other 112 students using this form.

• To start:
1. Go to your folder named 'week3'
3. Edit colab3.py using Pyzo
4. When you are ready, submit colab3.py to Autolab. For this colab, you may submit up to 8 times, but only your last submission counts.
• Do not use lists or recursion this week.
• Do not hardcode the test cases in your solutions.

1. testIsEquidigital() [25pts]
We say that a number is equidigital if it is positive and has the same number of digits as the number of digits in all of its unique prime factors combined. For example, 10 is equidigital because it has two digits and its prime factors, 2 and 5, have two digits combined. 3 is also equidigital because it has the same number of digits as its only prime factor, which is itself. 66 is not equidigital because its prime factors (2, 3, and 11) have four combined digits and 66 only has two. We want to write the function isEquidigital(n) which returns True if the number n if equidigital and False otherwise.

We've made several attempts to solve this problem, each included in the starter file. We've given each a number (isEquidigital1, isEquidigital2, isEquidigital3...) to distinguish them. Only one of these implementations is correct according to the specification we've given above. Your task is to write a test function, testIsEquidigital(isEquidigital), which only passes when called on the correct function. On all other functions, it should raise an assertion error. The argument isEquidigital is actually a function; our own test function, testTestIsEquidigital (meta!), provides the different versions of isEquidigital for you to test. You can call the argument isEquidigital as you would a normal function name (we'll go over how this actually works closer to the end of the semester). For example, we would implement our example from before as:

def testIsEquidigital(isEquidigital): assert(isEquidigital(10) == True)

2. Debug the Programs [25pts]
Each of the following three programs has one error (or bug) in it somewhere. Your task is to find and fix that bug without substantially rewriting the program. Specifically, each bug can be fixed by modifying only one of the program lines (which will result in full credit); if you modify more than one line, you'll only get partial credit. We define 'modify' to mean either changing one line, adding one line, or deleting one line.

Note: for each of these problems, you'll need to remove the triple-string quotes before debugging the program.

1. countEvenDigits(n) [5pts]
This program is supposed to count the number of even digits that appear in the parameter n.
"""def countEvenDigits(n): if n < 0: return countEvenDigits(-n) elif n == 0: return 1 count = 0 while n > 0: digit = n % 10 if digit % 2 == 0 count += 1 n = n // 10 return count"""

2. hasDoubleLetters(s) [10pts]
This program is supposed to return True if the given string has two letters in a row that are the same, and False otherwise.
"""def hasDoubleLetters(s): for i in range(len(s)): if s[i] == s[i+1]: return True return False"""

3. largestNumber(s) [10pts]
This program is supposed to take a string of text and return the largest int value that occurs within that text, or None if no such value occurs. The only numbers in the text are non-negative integers, and numbers are always composed of consecutive digits (without commas, for example). So "test 1234 test" contains one number (1234), but "test 1234a test" contains no numbers.
"""import string def largestNumber(s): biggest = None for word in s.split(): allNumbers = True for i in range(len(word)): if word[i] not in string.digits: allNumbers = False if allNumbers: n = int(word) if biggest == None or n > biggest: n = biggest return biggest"""

3. Fix the Style [25pts]
We've written a program, areAnagrams(s1, s2), which returns True if two strings are anagrams (that is, if they contain the same letters in possibly-different orders). The program is functionally correct, but we've written this program with terrible style.

Fix this program so that it meets the 112 style guidelines without rewriting the main logic. Then, in a comment above the fixed program, write out a list of the changes you made to fix the style. You must make valid changes that cover at least five different style rules to get full credit. This problem is not autograded; we will hand-grade it instead.
def areAnagrams(s1, s2): if len(s1) != len(s2): return False print("bad case") if len(s1) == len(s2): for str in s1: one = 1 count_matches_1 = 0 count_matches_2 = 0 for i in range(len(s1)): if s1[i] == str: count_matches_1 += one for i in range(len(s2)): if s2[i] == str: count_matches_2 += one if count_matches_1 != count_matches_2: return False return True

4. nthKaprekarNumber [10pts]
Background: a Kaprekar number is a non-negative integer, the representation of whose square can be split into two possibly-different-length parts (where the right part is not zero) that add up to the original number again. For instance, 45 is a Kaprekar number, because 45**2 = 2025 and 20+25 = 45. You can read more about Kaprekar numbers here. The first several Kaprekar numbers are: 1, 9, 45, 55, 99, 297, 703, 999 , 2223, 2728,...

With this in mind, write the function nthKaprekarNumber(n) that takes a non-negative int n and returns the nth Kaprekar number. For example, nthKaprekarNumber(0) == 1.

5. mostFrequentLetters [15pts]
Write the function mostFrequentLetters(s), that takes a string s, and ignoring case (so "A" and "a" are treated the same), returns a lowercase string containing the letters of s in most frequently used order. (In the event of a tie between two letters, follow alphabetic order, aka normal string comparison.) For example, mostFrequentLetters("We Attack at Dawn") returns "atwcdekn". Note that digits, punctuation, and whitespace are not letters! Also note that seeing as we have not yet covered lists, sets, maps, or efficiency, you are not expected to write the most efficient solution. (And you should not use lists, sets, or maps in your solution.) Finally, if s does not contain any alphabetic characters, the result should be the empty string ("").

Note that in this problem and in many other future problems, we will not give you much guidance on how to approach solving the problem. You should use the notes on algorithmic thinking to come up with an algorithm yourself.