Homework Four
Due 2025-03-13 at the start of class
Download Starter Files Submit on GradescopeObjectives
- Demonstrate your ability to write a for loop
- Demonstrate your ability to write a while loop
- Demonstrate your ability to write a recursion function
- Demonstrate your expanding ability to use conditional statements and manipulate strings
Getting started
For this assignment, we have another four functions for you to write. Please pay attention to all of these instructions. Even this front matter, which may look the same (and many of you skip over) has changed.
For this assignment, we have provided a starter file so that we can give you some extra helper functions. Please do all of your work in the enclosed file.
Feel free to work through the functions in any order. We do, however, suggest that you take the time to test each one as you go rather than trying to write all four out like they were part of an essay and then testing at the very end. Treat these are four totally separate and distinct problems (which they are).
Submit your solution on Gradescope using the button above. Feel free to resubmit as your complete each problem to check your progress.
Python subset
For this assignment, you now have recursion, while loops, and for loops in your toolbox. We are still working on your skills and intuition with respect to this, so read the problem description closely. Most of them specify which approach we would like you to use, and your solution should use the specified approach to receive credit.
While you are not reimplementing any core functions with this assignment, we are still getting very close to some standard methods that we would like you to continue to avoid for the time being. Unless explicitly permitted in the problem description, the only functions you are allowed are
- the type converters (
bool()
,float()
,int()
,str()
) - string methods
upper()
andlower()
- character converters
ord()
andchar()
len()
range()
Satisfactory vs. Excellence
A solution for these questions that is excellent will have the all of the following qualities
Style
An excellent function will have a docstring that is formatted in the way shown in the lectures. It should include:
- the purpose of the function
- the type and purpose of each parameter (if any)
- the type and meaning of the output (if any)
In addition, you should follow some of the PEP8 guidelines on whitespace. The ones we will be looking at are:
- no whitespace between names and
(
or[
(e.g.,f (5)
should bef(5)
ands [3:5]
should bes[3:5]
) - there should be a single space around operators (e.g.,
x=4+1
should bex = 4 + 1
andy = 3 -2
should bey = 3 - 2
) - there should be a space after commas, but not before (e.g.,
f(4 , 5)
orf(4,5)
should bef(4, 5)
)
Special cases and requirements
For some of the problems, we have identified special cases or requirements that we have deemed potentially more challenging and not essential to a satisfactory solution. An excellent solution will cover all cases. These cases will be identified in the autograder by tests with *
at the end of the title (so make sure you submit frequently as you are working).
Problem 1: Same count
Write a function called same_count
, which takes three string arguments: text
, sub1
, and sub2
. The function should return True
if sub1
appears the same number of times in text
as sub2
, and False
if it does not. This function should use a loop.
same_count
|
|||||||
---|---|---|---|---|---|---|---|
Parameters |
|
||||||
Return type |
bool
|
Examples
>>> same_count("abcdef", "mn", "st")
True
>>> same_count("abcdef", "ab", "de")
True
>>> same_count("aaaaabbbbbabab", "a", "b")
True
>>> same_count("aabbaaabb", "a", "b")
False
Problem 2: Caesar cipher
The Caesar cipher is a substitution cipher in which each letter is substituted with a different letter \(n\) positions away in the alphabet. The value \(n\) is called the key.
If the key is 3, our substitutions will look like this:
A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | A | B | C |
So, the word “cat” would become “fdw”. Notice that when we run out of letters, we wrap around and start the alphabet again.
The algorithm is:
- convert each letter to a number between 0 and 25 (we have provided a function called
letter_to_index
to help with this) - shift the number by the
key
, remembering to wrap around if the index exceeds the number of letters in the alphabet Hint: the module operator (%
) might be useful here. - convert the number back to a letter (we have provided a second function called
index_to_letter
to help with this)
To decode an encrypted message, we simply reverse this process.
For more information about the Caesar Cipher, see this article:
You should write a function called caesar_cipher
which takes three arguments:
message
- a string containing the messagekey
- an integer keyencode
- a boolean indicating if we are encoding (True
) or decoding (False
)
Any character that is not alphabetical (A-Z or a-z) should be copied into the output directly (e.g., whitespace, punctuation, numbers, etc…). Yes, this does compromise the security a bit – but not as much as converting spaces and making it very easy for an adversary to work out the key.
This function should use a for loop.
To receive a mark of excellent, encoded/decoded characters should retain their case.
caesar_cipher
|
|||||||
---|---|---|---|---|---|---|---|
Parameters |
|
||||||
Return type |
str
|
Examples
>>> caesar_cipher("cat", 3, True)
'fdw'
>>> caesar_cipher("fdw", 3, False)
'cat'
>>> caesar_cipher("You can't read this.", 10, True)
"Iye mkx'd bokn drsc."
>>> caesar_cipher("Iye mkx'd bokn drsc.", 10, False)
"You can't read this."
>>> caesar_cipher("abcdefghijklmnopqrstuvwxyz", 4, True)
'efghijklmnopqrstuvwxyzabcd'
Problem 3: Word extractor
Write a function called word_extractor
that takes in a single string called text
. text
is a string containing (potentially) multiple words, separated by spaces. The function will “neaten” the words, returning a new string with the words separated by a comma and a single space.
This function should be recursive and should not use any loops.
word_extractor
|
|||
---|---|---|---|
Parameters |
|
||
Return type |
str
|
Examples
>>> word_extractor("abc def ghi jkl")
'abc, def, ghi, jkl'
>>> word_extractor("abc def ghi jkl ")
'abc, def, ghi, jkl'
>>> word_extractor(" abc def ghi jkl ")
'abc, def, ghi, jkl'
>>> word_extractor(" not just three letter words in here ")
'not, just, three, letter, words, in, here'
Problem 4: Skip around
Write a function called skip_around
. which takes a string parameter called data
and an integer parameter max_length
. The function will read the string and return a new string containing the characters it found. If the function walked the string as many of our examples have (one character at a time from left to right), it would return a copy of data
. However, embedded in the string there will be commands that instruct the function to change the direction it is reading and the size of the interval between characters it visits. The function will continue to move in the new direction and with the new step size until it reaches a new command or the function ends.
- The function’s initial direction is forwards with a step size of 1.
- If the function reads an “F”, it reads the next character which should be a digit between 1-9 inclusive. The “F” means to move forwards through the data (increasing index), and the number provides the size of the steps to take (starting from the “F”).
- If the function reads an “B”, it reads the next character which should be a digit between 1-9 inclusive. The “B” means to move backwards through the data (decreasing index), and the number provides the size of the steps to take (starting from the “R”).
- If the function reads any other character, it saves it to the output string (if the function lands on the digit associated with a command, it is treated as a normal character).
- If the size of the output string reaches
max_length
, the function stops and returns the output string. - If the function walks off either end of the
data
, the function stops and returns the output string.
skip_around
|
|||||
---|---|---|---|---|---|
Parameters |
|
||||
Return type |
str
|
Examples
>>> skip_around("abcdefg", 20)
'abcdefg'
>>> skip_around("abcdefg", 3)
'abc'
>>> skip_around("abcF2defg", 20)
'abcdf'
>>> skip_around("abcF2deB3g", 20)
'abcd2b'
>>> skip_around("abcF2deB2g", 20)
'abcddddddddddddddddd'