I’m going to build an unstyled version of the application first, and then we’ll go back and add styles to make it as fun as the original.

Step 1: On/Off Buttons

Since this is a replica, I’ll add ON and OFF states to the application.

When the application route is entered, I’ll set the isOn attribute of the application controller to false. Then, I’ll add an ON and OFF button, just like in the original. When pressed, they will set the same isOn attribute.

Original ON/OFF Buttons

Here’s the commit to add these simple buttons.

Step 2: Level Button

Little Professor has 4 levels of difficulty that can by cycled through with the LEVEL button. I’ll set the level to 1 when the Little Professor is turned on. While I’ll probably need to add some restrictions to the resetting the level based on the state that the application is in, I’ll just limit that to only enabling the levels to change when it’s ON for now.

The code is still very simple. I added a nextLevel action to the application route that does the cycling, and reset the level in the turnOn action. Here’s the commit.

Step 3: Set Operator

Next up, we’ll set the operator that’s used for the math problems. There are four operators and each has a button. When the Little Professor is turned on, it defaults to addition.

I created a component to display the button. While this might be a little premature, it seemed fine to do and it’s interesting to explore the trade offs. I put the changeOperator action on the application controller and then pass it to the component. I also added a helper to format the operators using the appropriate HTML entity codes.

I changed the “display” at the top of the application to show the level and the operator in a way that’s similar to the toy, and I use the format-operator helper there too.

Check out the code for these changes in this commit.

Step 4: SET and GO

The Little Professor starts in the settings state, and has a GO button that exits that state and switches to the game state. There is also a SET button that switches back from the game state to the settings state. I’ll implement those next and adjust the functionality so that you can only change the settings when you’re in that state.

I decided to move all of the actions into the application controller. It just felt a bit cleaner, and given that the application only has one route (at least for now), that seems fine. One of the things that I like about making a simple application like this is that you can bounce back and forth between common idioms to find what feels right in each case.

I also added ember-truth-helpers add-on to give me some extra functionality in the template. I almost always use it in Ember projects — it practically feels like part of the framework to me now.

Here’s the commit with these changes.

Step 5: Generating Problems and Handling Answers

Well, this is really more than one step!

It’s time to make the problems. I’ll create a simple class to represent a problem and then generate a set of problems when the user presses the GO button based on the settings. For now, I’m not going to worry about the level of the problems — we can come back to that later.

My initial solution doesn’t completely work for division and subtraction. I’ll need to come back to that later and ensure that all questions have positive integer solutions. But, I’ve made it work for everything else.

When the user enters an digit, the controller checks to see if the currently displayed answer is the length of the correct answer. If it is, then it checks to see if the answer is correct. If it is correct, it goes on to the next question (or displays the final tally of correct answers). If it isn’t correct, the display flashes EEE and let’s the user try again. Once they’ve tried three times and haven’t gotten the answer right, it shows the answer and waits for the GO button to be pushed before advancing.

The actual toy (and application) have 10 problems per round, but I’ve temporarily set the problem count per round to 3 to show the feature.

Almost all of the code is still in the application controller (with a bit in the problem model and some logic in the application template too). I’ve refactored a little bit along the way, but haven’t really worried to much about the structure just yet.

Here’s the (too large) commit for this functionality.

Step 6: Fixing Division and Subtraction

Let’s hack in a simple fix for the division and subtraction problems. We need to ensure that all answers are positive integers.

To create the feasible division problems we’ll just iterate through the range of integers (1 to 100 to start) as both numerator and denominator and add those that have integer answers. We’ll need to do something else to prevent almost all problems from having a 1 or 2 denominator, but we’ll handle that when we work out how to handle levels.

Here’s the commit with the basic division change.

To create the feasible subtraction problems we’ll just select the second term from the random set of integers between 0 and the first term.

Here’s the commit with the basic subtraction change.

Here’s the division (without reducing the frequency of 1s and 2s) and subtraction in action:

Step 7: Layout and Style

This isn’t my favorite part of the programming task, but the results are worth it!

I did some Pixelmator hacking on an old photo of a Little Professor and added some basic CSS to style the elements to look similar to the original toy. I also refactored the buttons to use a new component that works nicely.

Here’s how it’s looking at this point.

Here’s the commit with those changes.

Step 8: Adding Levels

It’s time to go back and make the levels work. I’m sure that in the original Little Professor they were just hand coded, but we’ll create a generator to create problems for each level of an operator.

I didn’t have actual problem sets from the original Little Professor (or the algorithm used to created them), so I had to go through some trial and error until the problems felt “right”.

I extracted problem generation into a separate class and defined the minimum and maximum first term, second term and answer for each level of each operator. The implementation felt a bit messy, so I added a unit test that checked that the generated problems met the required criteria. I still don’t love the way that it works, but it’s good enough for just messing around.

Here’s the commit that added the level support.

Step 9: Replicating the Display

The display of the little professor is in the following format:

# # + # # = L# #

Supporting that fixed-position display style seems important to make it look right, so I’m going to extract the display into a component and then display the content in the 9 fixed positions using the same formatting rules.

Here’s the commit to that renders the display in this new style.

Step 10: Responsive Tweaks

The app looks great on a smart phone, but doesn’t look right on a desktop browser. So, I’ll add some responsive styling to prevent the height and width from stretching too much. I also added a favicon and an icon for the app when it’s saved to a smart phone’s home screen.

Here’s the commit with those responsive tweaks.

Step 11: Ship It!

You can use the application at http://littleprofessor.barelyknown.com.

If you want your kids to try it, add the application to your phone’s home screen and launch it from there. That will remove the browser chrome so they can’t change the page or move back and forth.

Summary

It took a bit longer than I expected, but it was lots of fun to create a replica of the Little Professor (and a day isn’t all that long!). Plus, my 9 year old even like playing with it. He needs the practice…