ICS 32A Fall 2023
Exercise Set 8

Due date and time: Friday, December 8, 11:59pm


Getting started

First of all, be sure that you've read the Reinforcement Exercises page, which explains everything you'll need to know, generally, about how the reinforcement exercises will work this quarter. Make sure you read that page before you continue with this one.


Problem 1 (3 points)

In the Inputs and Sounds lecture, we saw that PyGame provides two different ways of reacting to keypresses on the keyboard:

It is suggested in that lecture that you only actually need the first of these techniques; while the second technique is convenient, the theory advanced in the lecture is that you could build it yourself using the first. Let's prove that theory by actually doing it!

Download the file problem1.py below, which contains the basic skeleton of a PyGame-based "game" that displays a string of text on its display. (It's a simple enough game that we won't bother separating the model from the view, because we're exploring a particular PyGame technique.) Try it and make sure you understand why it does what it does, as a starting point.

Now, modify the game so that it does something a little different: Instead of always printing the string 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ, it prints a string consisting of whichever of those characters (only digits or letters) are keys on the keyboard that are currently being held down (i.e., they've been pressed but not released). If more than one key is currently being held down, show all of them, sorted so that the digits appear before the letters, and so that digits are sorted numerically and the letters are sorted alphabetically. (So, for example, if the user is holding down the keys B, 1, 3, and ], we'd display 13B.) Don't worry about the effect of "modifier" keys, such as Shift or Ctrl. They're not relevant for this problem; if the key is down, it's down.

But there's a twist! You can't call any of the functions in the pygame.key module, but instead need to implement this by reacting only to input events that come from pygame.event.get(). (If we can do that, then we've proven that we only need the first of the two techniques, which is what we're actually setting out to do here.)

It's worth noting, also, that PyGame has a long-standing bug that sometimes causes it not to properly handle more than about three or four keys being held down simultaneously; this is not a problem you'll be expected to fix.

What to submit

Submit the one Python script named problem1.py that we provided, with your updates that comprise your solution to this problem.


Problem 2 (3 points)

Background

A few weeks ago, we learned about Python's peculiarly named feature called Duck Typing, which essentially means that we can ask objects to do anything, as long as it's something they're capable of doing; specifically what happens is governed by the types of those objects, so the "right thing" happens automatically.

As a consequence, if you have many objects of different types that nonetheless share an interface — which is to say that there's at least one way in which the objects can be used interchangeably — then this allows us to write code that doesn't have to know ahead of time exactly what types of objects it will receive as input, yet the "right thing" will happen automatically when we use them, as long as all of the objects are capable of doing what our code asks them to do (i.e., our code only uses the interface they share). That conversation we had was accompanied by an example, in which we wrote classes that shared an interface that we called Calc, in which all of the classes had a one-argument method called calculate.

When shown that example, it's not uncommon for students to ask this question: Why couldn't we have just solved that problem with functions? The answer I usually give revolves around two things:

  1. Because we're learning a new technique, which we'll want to be able to recognize when we see it and put into action when we need it, but in an example that's not so overly complex that we miss the point of it.
  2. Because there are things that objects of classes can do that functions can't.

Now, to be fair, the second part of the answer is actually not entirely true. It's safer to say that, at that point, there were things that we knew objects of classes could do that we didn't know that functions could also do; the line distinguishing classes from functions is blurrier than you might have imagined. But, as the quarter has progressed, we've expanded our understanding of what functions can do, so let's apply that expanded understanding to the Calc example from the Duck Typing notes.

What to do

In a Python script named problem2.py, re-implement the Calc example from the Duck Typing notes, meeting the following requirements, which are different than what I was aiming for in that example.

Additionally, in a Python script named problem2tests.py, write unit tests (using the unittest module from the Python standard library) for the individual calcs and for your newly-written run_calcs function.

You'll want to use Test-Driven Development to do all of this work, as additional practice with that technique, though that's up to you. (Either way, you'll need to write and submit tests, but you might find them a lot more valuable if you write them earlier rather than waiting until the end, when they may seem more like busywork.)

Docstrings are not necessary here, as we've already agreed on what problems we're solving. Type annotations are also not necessary here; there's so much flexibility in this example, they'd be difficult to write without techniques we've not yet learned.

What to submit

Submit two Python scripts: One named problem2.py that contains your re-implementation of the Calc example and another named problem2tests.py that contains your unit tests for your re-implemented example.


Problem 3 (2 points)

One level of understanding how to write programs is to be able to copy techniques that you see other people using. A much more important level of understanding is to be able to choose those techniques yourself when they're appropriate. While experience is the best teacher of design concepts like this, the way to accelerate that learning process is to be sure that you understand why you're doing the things you're doing, so that your palette of choices grows more quickly.

Along those lines, let's consider a technique that we used in object-oriented Tkinter applications. When we wanted to "wire up" event handlers in these applications, we used a Python concept known as bound methods to do so. That's a new technique that we'd not seen previously, so it's worth pausing to make sure that we understand what purpose it served. To solidify your understanding, think about and then answer two questions about that technique.

  1. In an object-oriented Tkinter application (i.e., one in which we implemented the user interface as a class), why did we use bound methods when we set up our event handlers?
  2. Suppose that bound methods didn't exist in Python, so that we couldn't have solved the problem that way. Using only techniques that have been taught in this course to date, suggest another way that we could have set up our event handlers, assuming that our design otherwise wasn't going to change (i.e., we're still implementing our user interface as a class, with an object of that class representing a running instance of that user interface). Demonstrate your chosen technique with a short example. There's no need to write an entire program; show us enough code for us to understand the technique, but focus some effort on eliminating things that aren't necessary to convey your idea. (This is a really useful practical skill that you'll want to learn; being able to explain complex technical matters in simple language and with clearly chosen examples is handy for software professionals, not just for teachers.)

What to submit

Submit one PDF file named problem3.pdf, which contains your answers to these two questions.


Problem 4 (2 points)

Background

Amidst a blizzard of assignments, their requirements, their due dates, and your grades on them — not to mention the concurrent blizzards in other courses you're taking alongside this one! — it's easy to forget why you're taking a course like this one, and what benefits you might derive from having come to the end of it. Our goal in offering this course is to introduce you to Python, from the perspective of being someone who's learned some other programming language previously. By resting on that assumption, we're able to ramp up on the language basics quickly, so that we can spend most of our time on the course's main focus: using software libraries to allow us to solve complex problems with meager skills, while building confidence in our ability to navigate unfamiliar territory, learn about pre-existing tools, and find a foothold among what can otherwise feel like a dizzying amount of complexity.

So, it's our hope that you've emerged stronger than you were when you went in, in the big-picture sense as well as the small-picture one (i.e., as a programmer generally, but also as a Python programmer). Since Python is not the first language you've learned, it's worth stopping briefly to think about how far you've come, and how your point of view might have changed in the last ten weeks or so; familiarity with more than one programming language leads to the need to consider how they compare to one another, which is actually a great problem to have.

The question

This problem asks you to consider one question and write your thoughts about it.

You can write as much or as little as you'd like; we're not requiring you to write a chapter's worth of great literature here, but we also don't want you to feel like you can't explore your thoughts if you're on a roll. But do stay focused on the issue at hand: The focus is on your views about Python and how it compares to languages you knew previously, rather than the logsitics of the course, your feelings about your grades, your interactions with course staff, and so on. The goal is to synthesize your thoughts about what you've learned, rather than getting yourself caught up in how you've learned it.

We can guarantee that we'll be grading this question by the "honest attempt" standard — there's no "correct" way to answer this, after all — though an honest attempt is one that actually engages with the stated question in some way (the "what you've learned" part), without veering into other matters (the "how you've learned it" part).

What to submit

Submit one PDF named problem4.pdf, which contains your answer to this question.


Deliverables

In Canvas, you'll find a separate submission area for each problem. Submit your solution to each problem into the appropriate submission area. Be sure that you're submitting the correct file into the correct area (i.e., submitting your Problem 1 solution to the area for Problem 1, and so on). Under no circumstances will we offer credit for files submitted in the incorrect area.

Submit each file as-is, without putting it into a Zip file or arranging it in any other way. If we asked for a PDF, for example, all we want is a PDF; no more, no less. If you submit something other than what we asked for (e.g., a text file when we asked for a PDF, even if its filename ends in .pdf), we will not be offering you any credit on the submission. There are no exceptions to this rule.

Of course, you should also be aware that you're responsible for submitting precisely the version of your work that you want graded. We won't regrade an exercise simply because you submitted the wrong version accidentally.

Can I submit after the deadline?

Unlike some of the projects in this course, the reinforcement exercises cannot be submitted after the deadline; there is no late policy for these. Each is worth only 3% of your grade, with the lowest score dropped — see the Reinforcement Exercises page for details — so it's not a disaster if you miss one of them along the way.

You're responsible for making a submission in order to receive credit, which means you'll want to be sure that you've remembered to submit your work and verify in Canvas that it's been received. A later claim of having forgotten to submit your work or having misremembered the due date will not be grounds for a resubmission under any circumstances.

What do I do if Canvas adjusts my filename?

Canvas will sometimes modify your filenames when you submit them (e.g., by adding a numbering scheme like -1 or a long sequence of hexadecimal digits to its name). In general, this is fine; as long as the file you submitted has the correct name prior to submission, we'll be able to obtain it with that same name, even if Canvas adjusts it.