Learning programming with one of “the coolest applications around”: algorithmic puzzles ranging from scheduling selfie time to verifying the six degrees of separation hypothesis.
This book builds a bridge between the recreational world of algorithmic puzzles (puzzles that can be solved by algorithms) and the pragmatic world of computer programming, teaching readers to program while solving puzzles. Few introductory students want to program for programming’s sake. Puzzles are real-world applications that are attention grabbing, intriguing, and easy to describe.
Each lesson starts with the description of a puzzle. After a failed attempt or two at solving the puzzle, the reader arrives at an Aha! moment – a search strategy, data structure, or mathematical fact – and the solution presents itself. The solution to the puzzle becomes the specification of the code to be written. Readers will thus know what the code is supposed to do before seeing the code itself. This represents a pedagogical philosophy that decouples understanding the functionality of the code from understanding programming language syntax and semantics. Python syntax and semantics required to understand the code are explained as needed for each puzzle.
Programming is a skill that’s easy to start learning. You can head over to a site like Codecademy and get up and running instantly. But once you finish a few introductory courses, it’s not as easy to keep making progress. You need another approach.
How to Get Better at Programming
There are two ways to keep learning a programming language once you have the basics down:
Option #1: Work on a project
The project could be your own project. Or if you have the right kind of job, you could convince your boss to let you work in a new language.
When you’re learning a programming language by working on a project, you should actually care what your program does. Don’t just code for the sake of practice. If you decide to learn Python by writing a Twitter client, then read and post to Twitter using your program. If neither you nor anyone else is going to use your project when it’s done, you should pick a different project.
Option #2: Work on puzzles
Programming puzzles are dreamed up solely for the sake of learning or competition. You write small programs to solve them. Once you’re done with a puzzle solution, you don’t use it for anything. It has no practical purpose.
Projects are a great way to learn programming. Since they involve solving a practical problem, you get to learn about requirements and scope trade-offs. You learn a wider variety of language features than you do with puzzles. You often find yourself maintaining your code over time, so you get to see the consequences of your design choices. Projects are great. Ultimately they’re the reason that you learn programming: so you can write programs that do useful things. But in this post, I’m going to focus on the benefits of working on puzzles.
What is a Programming Puzzle?
The programming puzzles I’m talking about consist of a problem statement, some sample input data, and the corresponding output data. The goal is to come up with an algorithm that takes any input data that meets the requirements explained in the problem statement, and outputs the correct results. A wide variety of puzzles can be expressed using this input text/process/output text format. For example, each input line could be a word, and the output could be all of the anagrams that can be formed by the letters in the word. Or each input line could contain numbers representing temperature and water flow limits, and the output could be the settings required to fill a bathtub as quickly as possible to a particular temperature.
Programming puzzles are often associated with competitive programming, since programming contests are all about solving them. For the purpose of this discussion, I’m talking about using puzzles to learn programming, not necessarily competitive programming. When someone says they’re practicing competitive programming, they usually mean that they’re preparing to compete in events, like Google Code Jam or a TopCoder Single Round Match. Although there are reasons to use that type of preparation, you can also use puzzles for their inherent learning benefits, without worrying about contests and ratings.
Advantages of the Puzzle Learning Approach
Learning a language using programming puzzles has some benefits that are more difficult to achieve using the project approach:
What you learn stays useful longer
Solving programming puzzles requires problem-solving techniques more than knowledge of technical infrastructure, like databases or network routing. The program runtime environment is as simple as it could possibly be: you read from standard input, process the data, and write your answers to standard output. The same approach was used 45 years ago in the first programming competitions. Since you don’t have to deal with environment details, all of your effort can go into problem solving and implementation using core language features.
When you’re learning a language by working on a project, you have a wider variety of topics to cover, and they tend to become obsolete faster. For example, consider a project in which you’re building a mobile app. In addition to the programming language that you’re using, you have to take into account how your app will run on different devices and whether you need to update it when new operating system versions appear. There are plenty of benefits to developing app development skills, but there is also a trade-off that leaves you with less time to develop expertise in a programming language.
You can compare your solution with someone else’s
You can learn a lot from reading someone else’s code. Even better is solving a problem and then comparing it with someone else’s solution to the same problem. While this arrangement is rare in real-world programming, you can do exactly that at puzzle sites that allow you to view others’ solutions. Even for those sites that don’t, you can often find solutions posted online. If you Google a UVa problem number, you’ll generally find numerous solutions. For CodeForces problems, you can find submitted solutions along with the problem. Solutions are helpful for getting you unstuck, and also for picking up new ideas. And since you have spent some time with the problem, it’s easier to understand the code that you’re looking at.
It’s useful preparation for technical interviews
Many companies prefer to use programming puzzles rather than technology-specific questions when interviewing candidates. This is a controversial topic that generates a lot of debate among programmers. Nevertheless, preparing for or at least tolerating these types of interviews gives you a wider range of jobs to choose from. For a summary of why these types of coding interviews are used, see Proving That You Can Juggle Code.
You can take advantage of gamification
Gamification is only slightly less controversial than coding interviews, but once again it can be useful if you can put aside any aversion you may have towards it. When you’re working on a project, you have to supply your own motivation. Programming puzzle sites, on the other hand, often come with badges and leaderboards. If you treat these as games, you can find yourself practicing regularly and making progress on your learning.
Where to Find Programming Puzzles
Even if you’re not interested in participating in competitions, contest sites are a good source of puzzles. UVa Online Judge and SPOJ have a large collection from many years of competitions. TopCoder, Codeforces, and CodeChef hold regular contests, so they are continually adding to their problem archives. Project Euler is a popular site with hundreds of problems. One thing to keep in mind though: they have more of a math emphasis than other sites. Unless you have a strong math background, you’ll probably end up studying more math than programming if you choose that one. My current preference is UVa Online Judge, as I’ll explain below.
How to Use Programming Puzzles
You’ll get some learning benefit from solving puzzles even with no particular study system. But the process known as deliberate practice is the most efficient way to get better at a complex skill like programming. One of the principles that distinguishes deliberate practice from regular practice is metacognition, or thinking about thinking. Rather than just solving puzzles, take the time to evaluate yourself as you work through each step of the solution. The best way to do this is to make notes as you work through the problems. When you encounter a difficulty, make a note of it so you remember to think about it later and look for ways to improve.
With programming practice, one of the most common challenges you’ll encounter early on is remembering syntax. An effective way to tackle this problem is to maintain a source file that you update whenever you need to look something up in the language documentation. This file helps solidify your language knowledge, and provides snippets of code that you can use as you solve other puzzles. You can find my version of this file on GitHub. As noted above, programming puzzles don’t draw on all of the features of a language. By maintaining a code reference, you can focus on the subset of the language that is most useful for puzzle solving.
I’m trying out all of the ideas in this post as part of an experiment I’m calling Project 462. The number refers to the 462 starred problems on uHunt, a companion site to UVa Online Judge. If you want to try out the puzzle approach to coding mastery, uHunt is a reasonable place to get started. It provides a friendly interface to the UVa OJ problems, and a way to keep track of your progress.
One caveat: UVa OJ only supports C, C++, Java, and Pascal. If you want to use a different programming language, then another popular option is SPOJ, which supports over 45 languages.
I post here every week on topics related to programming, learning techniques, and the programming puzzle approach. If you’re interested, you can follow along. I’m @RedGreenCode on Twitter, and you can find other ways to follow me on the RedGreenCode home page.