Homework 4b - Swizzler

This program will exercise use of strings, indexing, slices, and loops. We specify some high-level functions, but you will need to decompose out helper functions to make the whole thing work.

This program plays on the fact that if you leave the first 2 alphabetic letters and the last alphabetic letter in place in a word, and reverse the letters in the middle, it's still kind of readable. It's sort of ridiculous demonstration of the power of the brain to sift patterns out of noise, and it's also a nice text-manipulation algorithm.

Alcie was beninnigg to get very tierd of sinittg by her sietsr

Download the swizzler.zip and open the "swizzler" folder in PyCharm to get started.

Swizzle Algorithm ++Python!

The heart of this program is the swizzle algorithm that rearranges a single word. Here is a good example word for the swizzle algorithm: '++Python!'

The swizzled version of that word is: '++Pyohtn!'

Here are the steps in the swizzle algorithm:

1. The '++' prefix of non-alphabetic chars at the start of the word is not swizzled. Split it off the plain alphabetic word.

2. Likewise split off the '!' postfix at the end of the word. Non-alphabetic chars not at the ends can be kept and swizzled, such as the dash in 'ad-hoc'.

3. After splitting off the prefix and postfix, we have just the plain 'Python'. The swizzle algorithm separates the plain word into three pieces: 'Py' 'tho' 'n'. Reverse the middle piece to 'oht' put them back together to form 'Pyohtn'.

4. Finally add the prefix and postfix back to get '++Pyohtn!'

swizzle() Function

The swizzle() function takes in one word, and computes and returns its swizzled form. It is the heart of the whole program. Your main task it designing, writing, and testing all the code to make swizzle() work.

swizzle('Python') → 'Pyohtn'
swizzle('**Python**') → '**Pyohtn**'
swizzle('ad-hoc') → 'adoh-c'
swizzle('Function') → 'Fuoitcnn'
swizzle('owls') → 'owls'
swizzle('a') → 'a'

We provide a good set of Doctests for swizzle().

1. First just sketch out the steps with an example string that swizzle() will need to accomplish.

2. Ultimately you will need to create at least 3 helper functions to solve sub-problems for swizzle(). You do not need to think of the 3 helpers all at once. You can start writing the code for swizzle(), and you will run into sub-problems suitable for decomposition as you go. Think of a helper function you could decompose that would compute and return a value you need.

3. Your swizzle() function must use at least 3 decomposed helper functions to do its work. We will not be picky about what exactly goes in each helper, just so they solve a meaningful sub-problem for swizzle(). As an additional constraint, your swizzle() code should not itself contain any loops.

4. Each helper function must have an appropriate function name and a """Pydoc""" sentence explaining what its parameters are and what the function will return computed from them. When you type the opening """, PyCharm will paste in ":param s: :return:" markers, which you can delete; those are advanced Pydoc features which are not needed for CS106A, and in fact these are rarely used in ordinary Python programs.

Each helper function must have at least 3 Doctests. Write one or two tests that look like ordinary input cases, and one or two more tests that are edge cases, such as the empty string.

5. Part of the algorithm involves reversing a string. Write a loop of some sort to do this. There are several reasonable approaches.

The starter code includes the functions main() and swizzle_file() in completed form - look them over. These functions are standard file-reading code, calling your swizzle() function to do the actual work.

Best Practice Advice

The best practice is to test your helper functions separately. The Doctest are an easy way to work on your helper functions independently. Only when the helper functions are working perfectly should you move on to running and testing swizzle() itself. Or put another way: debugging swizzle() while there are still bugs in the helper functions can chew up a lot of time. It's more effective to iterate on the helpers first, each as a free-standing little thing. If you find a bug in one of your helper functions later, as happens, add a new Doctest to the helper for that bug case.

There's the old project planning slogan: "We don't have time to stop for gas, we're already late." Is this program going to get done more quickly by not testing your helper functions?

Running With Real Data

Most of your algorithmic work can be done in Doctests, getting your algorithm correct for all sorts of cases. Once swizzle() is looking good, you can run your program from the command line like this to see it swizzle any file.

Here is the plain text of The Eagle by Teosynnn

He clasps the crag with crooked hands; 
Close to the sun in lonely lands, 
Ring'd with the azure world, he stands. 

The wrinkled sea beneath him crawls; 
He watches from his mountain walls, 
And like a thunderbolt he falls.

--Alfred, Lord Tennyson

Here is the command to swizzle it. Use the tab-key to auto-complete the names of files like "the-eagle.txt".

$ python3 swizzler.py the-eagle.txt 
He clpsas the crag with crekood hadns; 
Clsoe to the sun in loleny ladns, 
Ri'gnd with the azrue wolrd, he stdnas. 

The wrelknid sea betaenh him crlwas; 
He waehcts from his moiatnun walls, 
And like a thlobrednut he falls. 

--Alerfd, Lord Teosynnn

Like a thlobrednut indeed. Notice how the "--Alerfd," at the end depends on your logic handling the non-alphabetic chars correctly.

The file alice.txt is a good test. Getting the punctuation chars, such as " at the edges of many words.

$ python3 swizzler.py alice.txt
Alcie was beninnigg to get very tierd of sinittg by her sietsr on the 
bank, and of hanivg nonihtg to do: once or twcie she had peeped into 
the book her sietsr was renidag, but it had no pierutcs or 
conoitasrevns in it, "and what is the use of a book," thhguot Alcie 
"wiuohtt pierutcs or cooitasrevnn?"

Then we have first paragraph of Stanford professor John Perry's important essay on structured procrastination, which you will find to be a big help with many projects.

$ python3 swizzler.py procrastination.txt
I have been innidnetg to wrtie this esasy for mohtns. Why am I fillany 
donig it? Besuace I fillany fonud some unettimmocd time? Wrnog. I have 
pareps to grdae, teoobtxk orreds to fill out, an NSF prasopol to 
reerefe, dioitatressn drtfas to read. I am wonikrg on this esasy as a 
way of not donig all of thsoe thgnis. This is the escnese of what I 
call sterutcurd proitanitsarcon, an amnizag stgetary I have dierevocsd 
...

You know what else is a text file? swizzler.py is. Its text is your python code. Your program can read that text file just like any other text file, although it does feel a little scary. It's especially mind-bending to think about what it's doing to the Doctests embedded in your code.

$ python3 swizzler.py swizzler.py 
#!/usne/nib/rv pyohtn3 

""" 
Strofnad CS601A Swelzzir prcejot 
""" 

imropt sys
...

Here's one phrase that caught my eye from my swizzler.py

if lerp(ne) == le(ns):

All Done

When your code is working well and your code style is all cleaned up, please turn in your swizzler.py on Paperless as usual.

Were not yet halfway through this course, but this is pretty complete little Python program showing many CS themes: Coding algorithms with strings, indexing, loops, logic, and file processing. Decomposing of a big problem into separate functions. Leveraging Doctests to make progress on sub-parts independently to save time.