Week 5: Roman Numerals

Thanks for subscribing, and welcome to the fifth issue of the revamped All Tests Pass, a weekly programming debugging puzzle newsletter. I’m your puzzlemaster, Brandon Morrison, and I’m really happy that you’ve decided to play along.
Last week's puzzle: Distance and Fuzzing
Last week we wrapped up our conversion puzzle by adding distance calculations to our convert
function.
If you've followed along since the first conversion puzzle, then in some ways this past week's puzzle should feel pretty straightforward. Most of the complexity of adding an additional unit of measure should have been added by this week, so adding distances shouldn't have featured any significant new challenges to your approach.
However, once you add distance to the weight and temperature measurements, we're up to 13 valid options for convert
to handle, which might prompt a refactoring of your approach to make things easier to understand or modify.
In the author solution, I collapsed all of the methods for unit conversion into a single larger data object conversionsUnits
in order to make it easier to add additional units of measurement in a single place. Each item in the object has three elements to it.
- A
type
attribute, to describe what category the unit of measure is. - A
toBase
method, which converts the input into a common unit of measure per type. While they're not explicitly labeled, the default unit of measure for each type is the one that returns the same value back during conversion. - A
fromBase
method, which converts the base unit to the requested unit of measure.
By using this structure, if we were to continue this puzzle, it would be trivial to add additional categories to convert by adding additional functions to conversionUnits
.
Floating point numbers
One unexpected complication that I ran into with my approach was conversions with the feet to inches test. My original naive approach was to handle the conversions the same way as most everything else, as a simple ratio. Here's what the original inches conversion looked like.
const conversionUnits = {
in: {
type: 'distance',
toBase: (x) => x * 2.54,
fromBase: (x) => x * 0.3937,
},
};
With the provided tests, the feet to inches test always failed with a rounding error. This is entirely due to how JavaScript (and many other programming languages) handles floating point numbers, and something that I hadn't accounted for when creating the puzzle tests.
In a scenario where you control the tests, one way you could handle this issue is by using test methods that allow for an approximate answer. In Chai.js, for example, you could use either assert.closeTo
or assert.approximately
, which as far as I can tell do the same thing.
In our case, it breaks the spirit of the puzzle to modify the tests. What I chose to do was to tweak the output in relevant conversions to round the way that I would expect if the delta is close enough. A further refinement here could be to create a helper function to do this rounding that could be dropped into place as needed.
Implementations
- Author Implementation: https://github.com/fillerwriter/alltestspass-week4/blob/author-solution/week-4-measurements.js
This week's puzzle: Roman Numerals
For this week's puzzle, we're implementing a Roman numeral interpreter. Given a function romanNumeralInterpreter
that takes one argument input
, either return an equivalent number, or throw an error if the input isn't valid.
If you're like me, and rarely see Roman numerals outside of the cornerstones of buildings, movie credits, and the occasional large sporting event, Wikipedia has a good rundown of how Roman numeral notation works.
The rules
- Every Wednesday I'll send out a link to a short coding challenge. Sometimes your challenge will be to debug a pre-built function. Other times you'll need to flesh out a function or a method with a predefined specification. Sometimes we might just laugh at WTF JS moments. Regardless of the specifics, the puzzles should take roughly 30 minutes or less to solve.
- If you decide to play along, take the code from that week's newsletter, and fork it. Your code can live anywhere you feel comfortable. Feel free to use CodeSandbox, GitHub, JSBins, or some other external delivery system. Make your modifications, and respond back to
brandon at brandonmorrison dot com
. Responses should arrive no later than the following Monday at midnight Eastern. Please don't reply back with your code as an email attachment — I will not read it, no matter how nice the code is inside. - When I send out a new puzzle (on Wednesdays!), I'll post a solution to the previous week's puzzle. I'll also give shoutouts to those who responded with a correct answer. Privacy is important to me, so I'll only name you in the way that you identify yourself via your public GitHub/JSBin/CodeSandbox account, unless specifically asked to do otherwise. I won't share your email address.
- AI/Code Generation: While you're free to use any development tools to create your response, including generative AI coding tools, please consider not using them to solve the puzzles for you. The whole point of these puzzles is to enjoy solving the problem, not to get the answer with as little effort as possible.