Challenge 01
Due: 2025-03-25 at the start of class
Download Starter Files Submit on GradescopeWe will review revisions of challenges on a rolling basis, and if you submit early you may have a chance to go through multiple revision cycles. As students often submit work that is not finalized to gradescope, we ask that you fill out this form to indicate that your submission is ready to be regraded.
Objectives
- Demonstrate your ability to design and write a function on your own
- Demonstrate your ability to write conditional statements
- Demonstrate your ability to use repetition in code
Challenges
Challenges are your moment to demonstrate your ability to apply the concepts from the class independently. We may provide a framework that allows us to test your code and a description of the problem to be solved. The design of that solution is left up to you. We will not tell you how many functions to write, their names or what their parameters should be, nor will we dictate any implementation details beyond the requirements placed on what data you wll be given and what form we expect any data to be output. The only requirement is that your submission be entirely your own work.
Requirements
Challenges will only be marked Satisfactory, Incomplete or Unassessable.
To be marked Satisfactory,
- your code must meet the functional requirements (as embodied by the tests of Gradescope)
- your code must pass the style tests
- any function you write must have well formed docstrings that describe the purpose of the function, the name and type of each parameter and the return value
- your design should demonstrate good choices with respect to choices of abstraction and implementation (i.e., what to create as a function, how to handle repetition, how to break up conditions, etc…)
There are many ways to demonstrate good choices. At the largest scale, we will looking at how you use abstraction. Your functions should just do one thing, and that thing should make sense as a part of the problem you are solving. If you can’t describe what your function does in a simple sentence, it is probably too complex. On a small scale, good choices illustrate your grasp of how your tools work. For example, we might look at unnecessary type conversions (like converting a string literal to a string, e.g., str("already a string")
).
Submissions that are marked Incomplete will be eligible to be revised after feedback is returned. New work, or work that is Unassessable when the first submission period closes will not be accepted for revisions.
The Problem
For your first challenge we would like you to write a program that converts integers to strings containing their Roman Numeral representations. To give you maximum flexibility (and add an interesting wrinkle to the problem), your program will read in the values from a file and then write the results back out to a different file (please read all of this page before starting to implement this – we have a very specific way to handle the file operations).
Roman numerals
Unlike our system, which is positional, the Roman system is a (primarily) additive system in which numerals themselves are powers of ten and are added together and only the order matters.
The valid numerals and their values are
I | V | X | L | C | D | M |
1 | 5 | 10 | 50 | 100 | 500 | 1000 |
The numerals are summed to get their value. So, for example, \(\text{VIII} = 5 + 1 +1 + 1 = 8\).
While the system is not positional, we do think of translating each digit individually, so the one’s, ten’s, hundred’s, and thousand’s columns can all be considered individually.
Thousands | Hundreds | Tens | Ones | |
---|---|---|---|---|
1 | M | C | X | I |
2 | MM | CC | XX | II |
3 | MMM | CCC | XXX | III |
4 | CD | XL | IV | |
5 | D | L | V | |
6 | DC | LX | VI | |
7 | DCC | LXX | VII | |
8 | DCCC | LXXX | VIII | |
9 | CM | XC | IX |
So, for example, if we consider MMDCLXXIII
to get the decimal value, we could sum all of these:
\[ \text{MMDCLXXIII} = 1000 + 1000 + 500 + 100 + 50 + 10 + 10 + 1 + 1 + 1 = 2673 \]
or, we could look this up in blocks!
\[ \text{MMDCLXXIII} = \text{MM}\text{ }\text{DC}\text{ }\text{LXX}\text{ }\text{III} = 2\text{ }6\text{ }7\text{ }3 = 2673 \]
You hopefully will have already observed that there is a curious quirk in each column. It was deemed messy looking to have more than three of the same numeral in a row, so when we hit 4 and 9 we have a subtractive format, where the smaller numeral appears before the larger one (e.g., IV
). This is an indication that we need to subtract (e.g., \(\text{IV} = 5 - 1 = 4\)).
The range of valid Roman numerals is from 1 to 3999 inclusive. There is no concept of zero. For powers of ten that have a zero in decimal, like the ones and tens in \(100\), we just don’t write anything. You can expect that we will not give you a value outside of the range [1 - 3999].
Note that for this explanation of how the numerals work, I have been converting from Roman numerals to decimal. I have done this to avoid suggesting a particular algorithm. Your job is to go the other way and convert to Roman numerals from decimal.
Details
We want to give you the maximum amount of flexibility with this challenge while still retaining the ability to provide you with on demand feedback with the autograder, so we have had to give you a little bit of a framework to support these two competing demands.
main()
In the starter code (challenge01.py
), you will see the following code:
import io_handler
def main():
"""
This is the "main" function that drives your program. This is the function we will call when we want to run your code.
"""
= io_handler.get_handler() handler
To date, we have written individual functions and tested them directly. This time you will be writing a program that carries out multiple operations. Programs typically have a function called main
that serves as the entry point – where the first instruction to run is found. This is the function we will call to run your code.
A good solution to this challenge is unlikely to put all of its code in main()
(very unlikely…). You can, of course, test any function you write independently of main
, but bear in mind that we won’t know what your functions are, so we will only run main
.
Input/Output handler
We have not talked about how to handle file operations, and we don’t intend you to figure it out yourselves either. Instead, we have provided you with the io_handler
module. It will handle all of the file operations for you.
The module has one function: get_handler()
, which I’ve already provided for you. This returns the handler
with which your code will interact.
By default, values will be read in from input_numbers.txt
and will be written out in output_numbers.txt
. You are encouraged to add new numbers to the input file. Just make sure that you only have one number per line.
You can change the default file names by passing in two different names as strings to get_handler()
. You might do this, for example, if you wanted to have more than one set of test numbers.
The handler
will read in the values from the input file. Your code can then request the values one at a time, using the handler to write the results out to the output file. Your program will be expected to read all of the input and write out a response for every input.
The handler
has three functions:
handler.has_more()
- this will return a boolean indicating if there are any more values to processhandler.next()
- this will return the next value to process as an integerhandler.write_output(output)
- this has a single parameter (output
). The value of the parameter will be written out to the output file
Using these three functions and your own code, you are expected to convert every number found in the input file and write out the appropriately converted representation to the output file.
You should not need to look in io_handler.py
, and you certainly should not change anything in the file. However, you are welcome to poke through the code. There are a number of things in there that you will be unfamiliar with, but you will at least be introduced to most of them by the end of the semester.
Submission
As usual, you are encouraged to submit early and often to test your work against the autograder. The only file that you need to submit is challenge01.py
(and any other files you may have written as part of your solution). You do not need to submit input or output files, nor do we need io_handler.py
. Once you have finalized your submission, fill out this form to let us know that your submission is ready to be regraded.