Code like a speed-cuber

../../_images/cubebanner.jpg

The last couple of months have taken me down a rabbit hole of learning to think and code like a speed-cuber. This is an account of what i have learned.

True genius is rare, and the opportunity to learn how to think like one, even rarer. Genius is not a word i throw around lightly. Join me in this foray into the minds of geniuses, and let me guide you through why this level of cognition and skill can be attained by all who try.

To begin, meet Stefan Pochmann.

http://www.stefan-pochmann.info/images/header.jpg

I first came across Stefan’s code on leetcode.com; his answers to questions struck me as genius for multiple reasons. They:

  • execute more quickly than the majority of answers.
  • contain less code than most answers.
  • display multiple working variations to the answer, like he can simply crank them out effortlessly.
  • use python techniques in novel ways.
  • are simply brilliant (sometimes too brilliant).

So i started researching Stefan online. I first came across his personal site where he shares that he is a competitive programmer, and his many hobbies. I also came across his GitHub and was specifically intreagued by the fact he’d cloned the PyTricks repo.

It’s obvious that Stefan hones the craft or writing highly expressive and highly efficient code. This is his intent, and not an accident. It turns out Stefan is a speed cubing world champion, who invented the Pochmann Method for solving a Rubik’s cube blind-folded. I became intreagued: how can i learn how to think like Stefan Pochmann, and like a coding speed-cuber?

Enter the cube

My nephews Samar and Rahil visited from India at around the same time. Low and behold, they’d brought their Rubik’s cubes along with them. The universe was telling me something, and i leaped down the rabbit hole with little hesitation.

Over the course of several days, we learned how to solve the Rubik’s cube together. Solving the cube with the beginner method is suprisingly easy. This is the best video on the beginner method, and pretty much anyone can achieve this in less than a day.

But the beginner method is slow, and very inefficient. It uses a series of simple algorithms that have to be performed over and over. There are faster ways of solving the cube, the most popular being CFOP invented by Jessica Fridrich (another computer scientist).

../../_images/JessicaFridrich.jpg

So i was hooked. It became my new brainer-teaser challenge to learn how to solve the Cube in under 30 seconds, to see whether there was anything i could learn from doing so. CFOP is comprised of over 100 algorithms that need to be memorised.

../../_images/cfop.png

The first goal is to solve the cross, then the first two layers simultaneously, followed by the orientation of the last layer, and finally the permutations of the last layer. Dylan Wang’s youtube channel (another world champion) became a great resource, and showed me how CFOP is only the beginning.

../../_images/dylan.png

There exists many more algorithms to keep trimming down the number of moves required to solve the cube. The cubing community is obsessed with efficiency.

The result

I’ve been teaching myself speedcubing algorithms, and practicing solving in my spare time. I’m doing this while also working through leetcode problems (i highly recommend leetcode-cli).

After several months of daily practice, i’m noticing a change in how i code. My mind is now constantly looking for inefficiencies in my code, more so than i was before, and as a result, my code is becoming more expressive and concise. More importantly i’m using the approprite language constructs at the right times, and would dread not doing so.

Let’s discuss how speed cubers trim down their solving time, and then draw parallels with how you can use this to think like a better programmer.

Pick a system

CFOP is only one method to solve the cube. It’s used by many world cubing champions, so seems like a safe choice, but there are many options out there. Pick one, and stick with it.

Divide and conquer

When i started learning CFOP, i began by cramming algorithms. Big mistake. I quickly became overwhelmed. So i stepped back for a bit, and decided to focus on breaking down the problem, and looking at the structural and mechanical patterns in the cube.

../../_images/cross.png

One thing i noticed, was that speed cubers remove stickers to practice on what they need. This classic divide and conquer approach isolates the sub problems, removes the noise, and provides the mind with a single focal point. This brought down my solving of the cross from 20 seconds to an average of about 8 seconds. The cross can be solved in 8 moves or less.

../../_images/f2l.png

Spot patterns to develop intuition

F2L is divided into another 6 categories of algorithms. This is still divide and conquer, and simply cramming these categories also doesn’t really work.

../../_images/f2l_cube.png

Instead, you’ll need to look for patterns in the algorithms, this is what i mean:

../../_images/f2l_pattern.png

In F2L cases 1, 3, 5 and 7, you’ll notice the blue-red edge travels around the U layer counter-clockwise. Spotting this pattern is not obvious at first, but once you’ve seen it, it makes being able to solve these cases intuitively much easier.

Graph interconnectedness

Performing algorithms on a solve cube leads to other cases. Understanding how algorithms and cases are connected to each other makes it possible to set up cases while praticing algorithms you are currently learning.

Factorise

../../_images/factor.png

Notice how algorithms are comprised for similar sub-algorithms. The faster these sub-algorithms can be performed, the faster the algorithms can be executed.

Inspection and planning

Before a solve, speed cubers inspect the cube, and start planning their moves ahead of time. This effectively breaks down their solve into two major steps, the initial inspection and planning, where they try different moves in their heads, and exection where they execute what they pre-planned before starting.

Finger technique

../../_images/finger_technique.png

The good manuals contain colour-coded algorithms; the various colours dictate which fingers to use. Sometimes rather than doing a double spin of the up layer with the same finger (U2) you’ll want to do two spins of the same layer to two different fingers (`U`U). This develops a flow in the movement that speeds things up further.

Avoid unnecessary motion

Spinning the cube is by far the slowest move you can do, as it requires repositioning your fingers. Learn how to perform the algorithms facing away from you avoids unnecessarily spinning the cube, leading to much quicker solves.

Delay gratification

It may be tempting to practice solving the entire cube, however this will slow down progress dramatically. Start at the beginning, and only work your way up once you’ve achieved your solving speed targets.

Build muscle memory for everything

Solving cases is nice, but building muscle memory makes solving them much much quicker; faster than the eye can see. More importantly, it frees up the cognitive load of solving, freeing it up for what is known as ‘look ahead’.

Look ahead

Once you’ve built muscle memory, you are now free to look for the next case to solve while solving the current case. This is very similar to techniques used in speed-reading and touch-typing: building muscle memory and forcing your mind to be 1 step ahead of what your body is currently doing improves speed dramatically.

Know when to learn, and when to practice

Learning sessions are time spent practicing algorithms, and studying the cube. Pracice sessions are the application of that learning to solve the cube within your time limit. It’s really important to know which you’ll work on. A healthy mix of both is required.

Debug and improve

During practice, it’s important to take not of what’s slowing you down. You can jot these down in a note somewhere, and open the note during learning sessions to work on exactly what needs working on.

Time yourself

Timing your solves really focusses your mind on solving as quickly as possible.

Practice practice practice

Speed cubers perform hundreds of practice solves daily using cube timers. Practice while following good principles makes perfect.

How this relates to coding

../../_images/coding.jpg

I’m changing as a dev. For example. i’m writing this article without looking at the final result once. Before i would have built this page and glanced at it multiple times. I’m seeing very big changes in how i code too, and i’ll go over the same principles again from a coding perspective.

Pick a system

There are plethora of languages and frameworks out there. They can all be used to solve the same problems in their own way. Pick your primary one and stick with it as long as you can. Become a world expert at it.

Yes polyglotism is wonderful, and a degree of polyglotism will help with handling today’s technological heterogeneity, however being a polyglot will only take you so far if you want to really shine at being better than anyone both in terms of speed and quality to solve a specific set of problems.

Divide and conquer

This is too much of a classic, but worth repeating. Break down your problems into sub-problems as much as you can. Solve those and work your way up to solving the greater cases.

It’s so easy to get overwhelmed at first with computer science problems, divide and conquer helps keep the faith going: remove the unnecessary noise from your problem space. Really remove the clutter from your white-board / screen / mind, and only focus on one sub problem at a time.

Spot patterns to develop intuition

When i first started on leetcode, i’d just randomly walk through the various problems. I’m now going through them in a more organised way to build my intution on certain sets of problems. e.g

  • string algoritms
  • tree algorithms
  • system design
  • binary trees
  • binary search trees
  • arrays
  • algorithms
  • hashtables
  • greedy algorithms
  • graphs
  • dynamic programming
  • queues
  • linked lists
  • heaps
  • stacks
  • sorting
  • searching
  • recursion and backtracking
  • system design
  • etc.

Looking for patterns in each problem space, and developing an intuition for them over time yields much better results than randomly cramming problems and answers.

Find your common and favourite patterns to solving problems in the same problem spaces, like the algorithms used to solve cases in the cube. Build your toolkit of language features to crank through the answers like Stefan Pochmann would.

Graph interconnectedness

Various fundamental approaches can be used to solve the same problems. What happens when running your solution on the data twice? When building a solution pipeline, what happens when running your data through it in a different order? Experiment more with your solutions, and have fun with them to find unexpected and interconnected behaviour.

Factorise

Bits of code can often be composed of other bits of code you’ll reuse frequently. Try to spot the repetition, and be brutally aware of code’s sometimes pleonastic quality. Choose wisely when to factore a piece of code, and when to be at peace with the duplication.

Inspection and planning

Before jumping into a solution, devise your algorithms ahead of time. It’s a lot quicker to plan a solution, and only start writing code once this step is done, than jumping into writing code immediately.

Jumping into code too soon will not only slow you down, but it can easily make you run out of time, and ultimately fail. Changing your mind halfway through an implementation is also incredibly slow. Do not catch yourself out by jumping straight into implementing.

Finger technique

I find it shocking when i see devs looking down at their keyboard while typing. It only takes a couple of weeks of touch typing software to learn how to type without looking.

../../_images/das_keyboard_black_detail.jpg

My keyboard of choice (when i’m not on my mac) is the mechanical blank Das Keybaord. That really helps never having to look down at the keyboard ever again.

Avoid unnecessary motion

Organising and structuring your code well is important. I personally like the rule of 7: a maximum of 7 methods in a class, 7 classes per module, 7 modules per directory, 7 directories per library, 7 libraries per framework etc.

However, if you have to jump around your code repeatedly you’re adding unnecessary motion to your reading flow, and will slow down your productivity dramatically.

Delay gratification

Reducing or entirely obviating how often you execute your code will make you a better programmer. When you run your code, you interrupt your coding flow. You’d set out to do something, go ahead and do it, step by step, and have faith in your ability to solve that problem based on the intution and understanding you have honed over the years.

Do not be tempted by seeing result too early; that’ll just make you jump ahead several steps, and will prevent you from pacing yourself and doing the correct steps in the correct order.

Build muscle memory for everything

Especially when it comes to coding challenges, once you’ve spotted the patterns, go ahead and solve the same problems over and over until you can do so without thinking.

Think ahead

Think ahead of what you are currently doing. Yes you’re solving a problem sub-space, but why are you solving it? Who’s the caller, and what problem lies just around the corner.

Know when to learn, and when to practice

The modern developer has become far too reliant on stackoverflow for everything. That’s fine, however try to make a better dichotomy between coding time, learning time, deliberate practice time, note taking time, etc.

It’s become far too tempting to mush them all together. A better separation will lead to improved speed and accuracy while coding.

Debug and improve

Deliberately take note of what’s slowing you down when coding, then work on these areas during your learning and deliberate practice time. This will speed you up dramatically when doing the actual work and delivering results.

Time yourself

Time yourself when you are working. Set yourself a target for how long delivering a certain solution to a problem or sub-problem will take you, and try doing so as rapidly as possible.

Practice practice practice

On leetcode, i noticed my level improve dramatically during the periods of time when i solved a problem every morning without fail.

When reading Stefan’s beautiful solutions to problems, there’s really no secret besides these good principles and very regourous daily practice. Practice makes perfect.


The end

I hope you enjoyed this article. I’m currently available for work, so feel free to contact me shyal at ioloop.io.