It would take just one glorious Haskell PR

[Epistemic status: Fiction, satire]

“Tell me about FooCorp,” says Brian. “I’ve heard it’s one of the greatest software companies in the world, and I’m interested in working for you guys, but I’ve also heard the rumors and I was hoping you could explain.” Brian and Amy are having coffee. Brian doesn’t actually like coffee but it’s a good social pretext. Amy is a software engineer at FooCorp.

“Yeah, it’s unusual, but that’s what makes it so great!” says Amy, suddenly very passionate in a way that one rarely sees these days. “I guess, for starters, we have a really well-rounded group of engineers. Half the engineers only code in C, and half only code in Haskell.”

“Oh, that’s nice,” says Brian. “So I suppose they work on different parts of the product?”

“No,” says Amy, gesturing, “no, there’s only one codebase – a big monorepo. Right now it’s all in C. So all the Haskell engineers keep making massive PRs to change it over.”


“Right, right. It sounds crazy, but we’ve actually had to develop some really good consensus policies to handle this. So to merge in a PR, it has to be approved by a majority of the engineers in the company. Makes the codebase super stable, actually!”

“Woah. How does that play out?”

“We really focus on the important stuff, you know. We try to get in one or two big PRs a year that people can get behind. The Haskell guys usually don’t go for it but a few will usually compromise so the company doesn’t fail and fire everyone.”

“What do your users think of this release cycle?”

“I think at this point they’ve really accepted it. Some of our users would obviously prefer to see the product implemented in a functional way and some would prefer it in an imperative way but, hey reaching consensus takes time. They get it.”

“No, no, I mean what do your users think about bugs never getting fixed?”

“I think that’s not a very practical question. In the real world you have to choose a programming language for your PRs and that’s a highly contentious choice.”

Brian was confused but afraid to press the point. “I’m more of a Python engineer, you think I’d fit into your team?”

“Absolutely! You won’t be writing much code anyway, obviously. How are you at flame wars, IRC trolling, that sort of thing?”


FooCorp is fictional. At least, it’s not a software company. You might like working on my team, which is hiring, instead though!

6 Months of Working at a Hypergrowth Startup

I joined Scale AI late last summer. It’s been a crazy experience — Scale is growing incredibly fast right now, hitting a valuation of over $7 billion last year and recently signing a $250 million contract with the DoD. Personally, I’ve made over 100 PRs and conducted about 40 interviews already! It’s also by far the largest company I’ve worked for. Here are some lessons I’ve learned:

Working in a New Codebase

  • It’s often faster to check directly if something works than to prove it in your head
  • Finding the answer is less important than learning how to solve that category of problem
  • Global searches for strings/regular expressions are often the best way to gain context
  • You can configure your IDE to ignore log/build/dependency directories 
  • Turn on Git Blame so you can track down the PR that was responsible for a given line of code
  • You will need some of the (slightly) fancier features of Git, eg workflows based on git rebase and stacking branches
  • Strongly typed code is nice. Pay it forward
  • Your product probably has very informative logs/instrumentation if you know where to look
  • Some things you’re allowed to do when debugging:
    • Checkout an older version of the codebase
    • Checkout the latest version of the codebase
    • Comment out sections of code that are distracting or throwing errors
    • Use the debugger
    • Use specialized debuggers (eg React dev tools, Node.js debugger)
    • Refresh the page as many times as you like
    • Run as a different user/group/role
    • Print out the inputs to your function
    • Inspect network traffic
  • Sometimes you just need to read the whole schema/file/README to figure out how a system works
  • You are being paid, in part, for your capacity to be frustrated and stressed for hours at a time
  • Ask lots of questions, preferably in public forums. Start learning strategies to resolve specific categories of questions on your own: eg, documentation X, slack channel Y, schema Z.

Working in a Big Organization

(Size is relative; for me, 500 people is pretty darn big)

  • Follow up, over and over again
  • You’ll forget to follow up, so make a system that includes reminders
  • Find ways to be engaged outside of your team, eg engineering help channels or volunteer programs
  • There are performance reviews now. Make sure that you get actionable feedback well before the review cycle starts
  • Learn what’s important to to your manager and department, and figure out how your role aligns with those goals
  • Take notes during the week about questions/concerns/problems you can share in a 1:1 with your  manager 
  • If working remote: turn on the camera during Zoom calls (I don’t always do this but #goals :-))
  • Actively manage your calendar. Make sure you accept important events so other events don’t get scheduled on top. Decline events if you can
  • If you have a personal or interpersonal problem that affects work, there should be at least one person (your manager, HR business partner, etc) that you can bring it to
  • If no one is talking in a meeting, speak up. If lots of people are talking, be quiet. Don’t push meetings in tangents (that one is mostly for me :-)) 
  • When you build something new, make a short video to demo what you built and share it in your team channel and, if appropriate, with end users
  • Look for opportunities to present your work to larger groups of people within the org. Speaking/presenting is fun and a good skill to develop
  • Be very deliberate about replacing existing tools/workflows. Announce what you’re changing before you change it, let people opt in before you force them to opt out, and wait a long time to completely remove the old way.
  • Measure everything and insist on metrics to validate non-trivial projects. There’s too many initiatives to choose from otherwise, and the opportunity cost is enormous. 
  • Documentation goes out of date extremely fast. Try to consolidate and keep the core docs in a trafficked location.

Hiring and Interviews

  • This is an incredibly tight market for engineering talent. 
  • It’s important to make people feel at ease right away in an interview. Relax and show interest in them and their story
  • You’re only trying to answer one question: Would this person be a good addition to the team?
  • Remember to sell your company to the candidate too, since the good ones will have options.
  • Use interview questions that are programming-language agnostic 
  • Avoid miscommunication at all costs. You don’t want a candidate to struggle because you were unclear. Ask candidates to walk through a simple example based on a sketch of their solution before they starting writing code. 
  • Don’t help candidates too quickly when they run into a concrete problem. Give them a chance to figure it out! This is a high-signal moment in the interview
  • Take notes throughout the interview stream-of-consciousness and edit them after you’re done.
  • Simple questions are often better than complex questions because they leave less up to the skill of the interviewer

Code reviews 

  • If you are an active reviewer, you will gain valuable context that will help you debug problems faster
  • If someone approves your PR it doesn’t mean they’ve validated that your code works. You should find alternate ways to ensure this. For example:
    • Write tests
    • Work with QA, if available
    • Partner with an end user to conduct acceptance testing
  • There are many things a code review could cover. The fact that one of them is reviewed doesn’t mean that the rest are okay:
    • Code style
    • UX
    • Correctness
    • Performance
    • Security
    • Architecture
    • Consistency with similar features
    • Dependencies
    • Logging/observability
  • It’s okay if you don’t have a lot of context on a pull request. Try to contribute one useful thing. One of the best ways is to check it out locally and take the feature for a test run!
  • On finding reviewers for your code: Try to get at least one other engineer interested in your project so they’re motivated to give you feedback

Did I mention that we’re hiring a lot right now? Here’s my referral link. 😀

Is Nerdle Harder Than Wordle?

Nerdle is like Wordle, but for numbers. The words are short arithmetic sentences like “1+2+7=10” (always 8 characters long). You get 6 tries to solve a word, just like Wordle. A certain group chat got very, very excited about Nerdle this week and since some of them were freakishly good at it, not including yours truly, I’m trying to compensate by contributing a solver and some analysis. The source code for this post lives here.

We Need a Dictionary

By now, there are many solvers for Wordle. Those solvers rely on a well-defined dictionary of 2315 possible solutions and 12972 allowed guess words, which can be harvested from the Wordle source code. Nerdle doesn’t provide a dictionary, so we’ll need to generate our own. The rules state:


There are 8 “letters”

A “letter” is one of “0123456789+-*/=”

And a word must be a calculation that is mathematically correct. So it must have one “=”

Also, the number on the right of the “=” is just a number (not a calculation)

Standard order of operations applies, so calculate * and / before + and –

Order matters in nerdle. If the answer we’re looking for is 10+20=30, then 20+10=30 isn’t close enough.

Naively, there are 15^8 ≈ 2.5 billion candidate ‘nerdles’. That sounds like a lot, but we can cheat and just generate possible left-hand sides (on the order of 14^6 + 14^5 + … + 14 ≈ 8 million possibilities), and then check whether each expression evaluates to an integer with the right number of digits.

It turns out that this generates a torrent of obscenely irritating words like 1----1=0 (which is a valid guess in the interface) or 01++01=2 (also valid) or 0*0001=0 and its cousins. The Nerdle website states in another dialog:

As far as we can work out, there are over 100,000 valid words but we have chosen 17,723 valid “words” as there are quite a lot we thought you wouldn’t like.

This is a little more cheerfully vague than we might wish, but thankfully there is also an FAQ page that provides two additional rules:

Nerdle answers don’t use leading zeros or lone zeros, even though some may be accepted as valid guesses. So you won’t find an answer like this: 0+5+5=10, or like this: 01+2+1=4.

Nerdle answers don’t use numbers that are negative, even though some may be accepted as valid guesses.. So you won’t find an answer like this: -5-6=-11.

Somewhat to my surprise, these rules are enough to let us exactly recreate a dictionary of 17,723 words. Each rule has some additional gotchas:

  • while 0 cannot appear by itself on the left-hand side, it is allowed to appear as the answer on the right-hand side, although negative numbers are not allowed on either side.
  • the prohibition against negative numbers extends to all sequences of consecutive operators like ++ and -+ and ---, although these are accepted in the interface.

I was stuck on various lists of 16,000 to 80,000 words for some time before hitting on the magic combination of exceptions above, so: here is the list of words. The repository also contains Python and C++ dictionary generators, which run in about 8 seconds and 5 seconds on my 2020 MacBook Pro, respectively.

How Hard is Nerdle?

Compared to Wordle, both the number of possible answers and the number of legal guesses are an order of magnitude larger, so you might assume that Nerdle is harder. In fact, this is not necessarily true, due to the uniformity of the distribution of Nerdle characters and the smaller alphabet.

For comparison, here’s the same chart for the Wordle dictionary, which can be obtained from the source code at

You notice that in the Wordle dictionary, most characters appear in 10 – 25% of the words (with a few devilishly hard characters that appear in only a tiny fraction.) But in Nerdle, most characters appear in about 50% of words, with 25% in the worst case. 50% turns out to be great from an information theory perspective, since characters that show up more frequently don’t reduce your search space enough and characters that show up less frequently are risky to waste a guess on.

Random Algorithm

When you input a guess, some of the words that were previously possibilities are ruled out. Only words that that would produce the sequence of patterns you’ve seen for all your guesses can remain. So a simple heuristic, similar to how a human might play Nerdle, is to keep guessing a random word from the set of words that are still possible until you find the right one.

How well does this work? I ran a simulation of this strategy, trying 1000 random starting words and picking each guess randomly from the set of words that could still be allowed.

This strategy is surprisingly effective, taking an average of 3.37 guesses. This is already better than the best average score you can get at Wordle with completely optimal play, so Nerdle is, it seems, potentially easier to solve than its predecessor (ignoring the difficulty of coming up with valid guesses, which is probably harder than finding words for Wordle). Indeed, the random strategy finds the correct answer in two guesses 6% of the time! 99.7% of trials solved the puzzle within the limit 6 guesses or less. So it’s safe to say that if you are able to just keep guessing Nerdle words that are consistent with the clues you’ve gotten so far, you are almost certain to beat the game.

Best Starting Word

The first step to improving the random strategy is to find a good starting word (or words). Without actually simulating all possible Nerdle games, we can say that a good first word should narrow the search space as much as possible. Of course, how much your search space narrows depends on what result (call it a “grade”) you get after you input the word. Each grade corresponds to a different set of candidate words (call it a “pool”). We would like to minimize the expected average size of the pools.

Your daily dose of math: Suppose, for a guess w, you have k pools of sizes s1…sk. Each pool correspond to the answers that are still possible given a particular grade G. The sum of s1 + s2+… sk = S = 17723. The likelihood that you will end up with a particular pool is proportionate to its size, so the expected value of the pool size is (s1 / S) * s1 + … (sk / S) * sk = (s12 + … sk2)/S — that is, we want to minimize the sums of squares of pool sizes.

So we can simply go through all the possible starter words and check which ones have the best expected pool size. Because this is on the order of 177232 = 300 million operations, I haven’t actually computed this value exhaustively yet, but a preliminary search has produced a few words like 48-32=16 and 43-26-17 with expected pool sizes of approximately 10 each. This is actually fantastic – it means that if you pick one of these words, you can expect to have only about 10 feasible Nerdles to choose between in the next step (although there is significant variance here.) Here’s the code snippet I used to compute pool sizes; see this file for definitions of the helper methods used here.

def pick_best(target_pool, guess_pool=None):
    if guess_pool is None:
        guess_pool = target_pool
    pools_by_guess = defaultdict(Counter)
    for guess in guess_pool:
        for target in target_pool:
            score = grade(guess, target)
            pools_by_guess[guess][score] += 1
    best, best_score = None, 1e9
    for guess, pools in pools_by_guess.items():
        total = 0
        for pool in pools.values():
            total += pool ** 2
        avg = total / len(pools)
        if avg < best_score:
            best_score = avg
            best = guess
            print(f"{guess} has average pool size {avg}")
    return best

Extending the Best Starting Word Strategy

What if we start with 48-32=16 each time, and then use the same heuristic described above to find the best guess given the new pool of possible solutions? Here’s my results for this strategy, over 1000 trials:

Using the heuristic, the average number of guesses drops to 3.125 and 99% of trials take 4 or fewer guesses. I’m guessing that a really well-tuned minimax algorithm could drop this average under 3 guesses per game (but probably not too far under: two guess solutions simply aren’t possible in many cases.)

Use the Solver

Sample solver output

I’ve written a simple interactive Python program that tells you what guesses to make and lets you report what grade you’ve gotten from the web interface. You can get it from the repository here: Let me know if you have any questions or problems!


Despite a much larger dictionary, Nerdles can be solved somewhat faster on average than Wordles. However, it may be harder to find valid guesses for Nerdle than it is to think of words for Wordle, so I think which one is more difficult for you probably depends on that factor.

I think the strategy here and the simulations are reasonably good, but someone could test this strategy exhaustively for all 17,723 Nerdle solutions with 17,723 starting words to get a very precise result. That’s a few hundred million scenarios to simulate, but there is adequate cloud compute out there in the ether for that workload. If you do, I’ll happily edit this post to incorporate your results.

Those Computers In Your Head

You think this post is going to be about coding, but it’s really about chess and realizing that you can build wonderful special-purpose machines in your head over time.

When I was first learning to code, my main frustration was that the code didn’t compile. I would type out an example from the textbook exactly (“exactly”), and yet there still be cryptic errors. Mystified I would carefully compare each character to the source. Sometimes I found the mistake, and at least once I never did and abandoned that project entirely. I frequently observe beginners with the same problem.

After ten years or so of this, I can look at code snippets in my preferred programming language and pick out any syntax errors immediately. In fact, these days, I can run many programs in my head! This sounds obvious and ordinary to professional engineers, but it’s still quite wonderful. My brain can keep track of all the state in a short program, execute it line by line, follow control flow and data structures, and compute the output after only a short delay (assuming no complex math is involved.) Yet I have only an average working memory and am in fact rather bad at many other cognitive tasks that sound much simpler. Somehow my brain has built a tidy von Neumann architecture over the last decade.

I was surprised and delighted to discover that my brain has built a second such special-purpose device that only seemed to really activate a few days ago. I have been playing chess rather obsessively for about 3.5 years. When I started out my friend would try to play blindfold chess with me where you announce moves in turn without the aid of a board; it was almost impossible for me and I had to give up. Only a few days ago I found that I can now see entire chess positions in my mind and play many moves forward, seeing all the pieces as I go. For someone like me who is very bad at picturing anything in my head, this is astonishing. (But, quite ordinary among dedicated chess players!) My brain must have built a special module just for visualizing chess boards and speculating on moves. This has allowed me to reach roughly the top 1% of online blitz players by rating, and it’s a lot of fun.

To clarify, the experience in both cases is not about having a skill or special knowledge (though those exist, too) — it literally feels like I have extra working memory/RAM/brain hardware for these two domains that allow working on tasks that would seem cognitively impossible in other domains. If you’ve read A Thousand Brains, these structures presumably correspond to learned mental maps plus some method of exploiting sequential memory. This mental machinery took literally thousands of hours to develop, but I also feel that deliberate practice might be more important that raw time; 100 hours of chess tactics training has probably had a much bigger impact than 1000+ hours of playing games.

I had no idea brains could do this. But now it’s happened to me twice and I’m extremely excited to see what other special modules I can encourage it create. Some items on my wishlist: perfect pitch; being able to walk around a city and not get lost; eidetic memory. I’m increasingly suspicious now that all of these can be trained, too.

Comments on Hacker News

Speculative Autobiographies

It is very difficult to predict how one’s life will go; not only your life situation, but the very objects of your desire, are subject to change. This accounts for the terrible mess that people sometimes make of their selection of college major. Since life is a delicate, dynamical system, it may in fact be impossible to align your training with your destiny; perhaps to study writing is to guarantee a future in boxing, but to train for boxing would only nudge you into theatre…

One of my hobbies is to write little biographies of myself, as seen from the future, often in the form of resumes. I’m quite prolific at making these. In some respects these resumes tend to run hopelessly optimistic, but also they suffer from a failure of imagination; this is because one’s idea of what is interesting or prestigious, when one is young, is bound to lack details; and rarely touches on the elements of experience which are actually fulfilling and rewarding. I will illustrate both points with a fictional resume I made when I was 19, a sophomore, which was meant to illustrate my qualifications for the NSA on graduation.  Please note that everything after fall 2016 (and some undated items) are made up.

The objective states: “To contribute to a team of mathematicians working on difficult and interesting problems in cryptanalysis.”  In point of fact, I had zero experience with ‘cryptanalysis’ at this time. I believe it was on my list because I knew of several graduates from my small school who had gone to work for the NSA and some related organizations; it was simply the most prestigious thing I could imagine doing. Perhaps surprisingly, I did go on to explore this subject area in college: I did a summer of funded research on some post-RSA encryption schemes, and I took a graduate class on cryptocurrencies (okay, the connection here is tenuous, but it does have ‘crypt’ in it!) In the end, I found the whole subject – cryptography, cryptocurrencies, the lot – to be dry and overly difficult, and I had no interest in pursuing any of it after graduation. I did not start a graduate degree in cryptography, and I did not apply to the NSA.

Instead, I joined a very small local company as a software engineer  – a job to which no prestige attached whatsoever – which led to a couple years of intense personal growth, with such milestones as: building (eventually revenue-generating) software products from scratch; taking on my first intern, then leading a team; handling technical interviews for the company; and working with a whole host of interesting technologies that I’d never heard of before I started the position. I didn’t get rich, but the company was generous with me; when I left, they even gave me a gift! Words can’t express the richness of the years I spent at VisioStack, much better than the empty vision of prestige I had as a sophomore in college. (Of course, cryptography is still an amazing and by all accounts deeply rewarding career. It just wasn’t for me, and I was only interesting because it sounded cool.)

This is not the first time my plans went awry. From the ages of eight to fifteen or so, I was quite sure that I would be a civil engineer when I grew up. I thought this because I enjoyed drawing networks of roads – I really, really like drawing networks of roads – and I was told, upon inquiry, that this was the domain of Civil Engineers. (I still think that, if this could really be the sum of my job duties, I would have a tremendous time doing this.)

At other times I have been convinced, for periods of at least a few months, that I would eventually become a baseball radio announcer, a geneticist, or a missionary.  By contrast, becoming a software engineer, as I have been all my professional career, sort of just… happened by accident. This is all deeply disorienting: Are my present plans and ideas any better than they were at 19? Here are some failure modes I see in my thought process back then:

  • I focused on a future that sounded prestigious and/or similar to the work of my role models, instead of one aligned to my interests. In reality, I’ve always enjoyed building software, and I did this compulsively throughout college, sometimes to the detriment of my other obligations; my role models didn’t do this at all. So I probably should have identified different role models.
  • That resume was created when I was at a personal zenith of academic performance. It was one of the only semesters where I earned all A’s. An academic future (which would be required by a cryptography career) seemed more realistic at that time, even though there were plenty of signs that I didn’t really enjoy school.
  • I hadn’t yet done anything to validate this idea – no courses, additional study to see if I even liked it. This last seems like the biggest oversight.

I’m not going to be too hard on myself – I was young, fresh, I had lots of ideas, and I did go on to investigate the cryptography profession a bit more thoroughly. It’s not wrong to be wrong about this stuff. But I’m still writing future resumes, making fantastical five- and fifty- year plans, and I’d sure like to be right. These stories just seem like too much fun to miss.

The Touching Responses to “On Learning Chess”

On Sunday night I jotted down a short reflection on my journey learning chess over the last two years. I made a couple graphs to fill it out and submitted it to HackerNews. The response has been overwhelming – tens of thousands of readers, and hundreds of helpful, funny, and encouraging comments, through HackerNews, Reddit, email, and other sources – so I want to respond to everyone here, and highlight a few remarks that stood out to me.

I’ll start by answering the most frequently asked questions, and then move to the highlights.


Does your blitz rating correspond to a standard FIDE rating?

The ratings don’t correspond – I don’t have a FIDE rating, and online blitz is a different game from classical OTB chess. With that said, you can compute some statistical correlations between the ratings among players who have both, and a 1750 Blitz rating (my personal best, achieved November 2020) roughly correlates to a 1665 FIDE classical rating, according to this analysis, or a 1745 USCF rating.

What is your username? I want to analyze your games.

While that’s very touching, I have deliberately withheld my username because of the privacy ramifications of connecting my real-life identity to my account.

Can you share your Anki cards?

My Anki cards would not be useful to others except as examples, because they’re based on the specific mistakes I make and off-beat openings I use. In 6 months, my current set of Anki cards will probably not even be particularly useful to me. But, just to expand on my method, my Anki cards have 4 fields – Front (a picture of the position, with me to play); Back (A picture of the position after the correct move), FEN (a unique text representation of the starting position, to help me avoid duplicates), and GameHits (to help me keep track of how often I see a card’s position in an actual game.)

How can you spend so much time on chess?

Like everyone, I make tradeoffs. Life is not a contest. I have a fairly demanding job and I’m in grad school, but I still have significant flexibility in how I spend my time. I even have other hobbies! And I do deal with burnout and stress. Chess has actually helped me with that, because I’m less tempted to stay up late solving tactics than I am to watch a show. The feeling of steady progress, and a reliable routine, can actually provide stability and calm that outweighs the time and effort one puts in.

Highlights from the Comments

This is EXACTLY what I needed to hear as an adult who is just now getting really into the game. What was your training routine like for 800-1200 ELO on

sonicfood – Reddit

I’m so happy to hear this. I actually talk about exactly what I did in an earlier post, here (in the “Chess” section.) I would note that I didn’t do a lot of tactics training then, but I believe the process would have gone much faster if I had.

Hi, I would really encourage you to spend more time doing tactical problems and not spend as much with strategy concepts and openings. You can get to 2000 with minimal opening and strategy study, and you will get there faster. Until you have mastered tactics, you should have a basic understanding of opening concepts and strategy, no more than that. Have a look at Michael de la Maza’s book, or better yet, just read this article about it, it will save you some money:

P.S. I’m a chess teacher and I’ve switched to this approach a long time ago, based on research and results

P.S.2 There are some very good software for tactical training, I use the ones from Convekta, but there are others. Maybe check out Dan Heisman’s articles, I haven’t been up to date on him for a while but it was pretty solid advice.

Mesquita – WordPress

I definitely agree that most progress comes from solving tactics. Anki, though, is my silent chess coach, pushing me to analyze my games and explore the bad decisions I make. Chess is, after all, about making better choices. To those of you out there who already play slow time controls and analyze your games, Anki is probably superfluous. And thank you for the link about Michael de la Maza! His story shows us, I think, that for many of us the limiting factor is just how long we continue training. It’s hard work.

> on Friday I’m better than average,

I wonder if this is because the opponents might have been drinking.

For me at least, I know that even two beers has a noticeable effect when I do lichess puzzles.

emmelaich, HackerNews

I love this theory! Anecdotally, people do sometimes announce that they’re drinking in Friday games.

I did something very similar with an old strategy game called Age of empires II. Over the course of two years I went from a 1300 rating to 1850. I don’t play chess, so it’s hard for me to compare the scales, but I will say the highest players were rated around 2600. I think being 1850 put me around 90-95th percentile for active players– there were less than 50 players over 2300, and only a few hundred over 2000.

My only real commentary is that trying to follow a progression like this can be profoundly, profoundly frustrating. You need to really make sure you’re enjoying this hobby before you try to dedicate yourself to a trajectory like this. It can really make you feel like shit a lot of the time, as you find yourself continually repeating mistakes that other people breeze past without issue. It takes true love of the game and a great deal of patience and persistence to push through all the downspells.

Eventually I decided that I no longer wished to prioritize the game over other things. The enormous time investment was no longer a worthwhile trade-off for me, and I stopped playing almost all together. I haven’t regretted it since. There’s just so many things to do in life. I gave it thousands of hours of my time, and now the door is closed on that. Now I’m learning Ruby on rails!

aerovistae, HackerNews

You really speak to the psychology of training here. Sometimes it’s such a struggle. Some days you keep making mistakes, and everything is hard, and that feeling of “profound, profound frustration” just wells up. At those moments I try to fall back to having the clichéed “faith in the process” and grind out another puzzle. Fortunately, at so many moments, it’s fun and easy and flowing and you’ll see a beautiful tactic that wins your opponent’s queen. And you get more of those moments as you continue to grind.

Chess is pretty great.

I hope many of you are encouraged that you can improve with time and a good routine, as you have encouraged me to carry on. I particularly appreciate the kind words from much stronger players, who could easily have disregarded this result as unimportant in absolute terms. (But imagine Magnus Carlsen’s two year posts! Would we find them relatable? And so, I think, there is a use for celebrating small gains by ordinary people like me.)

I’ll end by signal-boosting some other interesting things I’ve done with chess.

I published an article in Math Horizons magazine earlier this year about a really fun puzzle that uses a chess board and chess pieces (but isn’t, strictly speaking, chess). (Spring 2020)

I really love 4-player chess and have spent a good deal of time working on a 4-player chess bot for (spring 2019).

Comments on Hacker News

On Learning Chess as an Adult – From 650 to 1750 in Two Years

I caught the chess bug as a college student, twenty-one years old, and it’s become my favorite way to unwind since then, as I’m now working at VisioStack and starting a master’s in CS at Clemson University.

Like all hobbies, chess is more fun when you’re making progress. And progress as an adult is certainly more difficult, as for instance recounted in this fine story by Tom Vanderbilt. It’s not so easy to rewire your brain.

I started out as a below-average-rated player, which was humbling and rather galling. My chess-playing friends IRL beat me easily. Today, I’m still a poor player – I frequently blunder pieces and make other mistakes – yet I’m much stronger; I beat those friends and am now around the 95th percentile at My rating progress at blitz looks like this:

(I would note that in fall of 2018, I played a great deal of 4-player chess instead of standard chess; this improved my regular game indirectly, fortunately.)

How I Study

Much of this progress was haphazard: I played lots of games, read the occasional book, learned a few openings. Earlier this year I hit a road block around 1450; the following routine is what’s helped me continue to progress.

I spend about two hours per day on chess, broken into three periods. In the first period, I drill opening theory and positional concepts. I use the spaced-repetition app Anki for this. My cards are just positions drawn from computer analysis of my own games: I put blunders and mistakes from my games here (front side of the card is the position before my move, reverse shows the correct move.) I also put many positions from the openings that I play here. I add about 25 new cards a day, which means I have 100+ cards to go over on a given day. Reviewing Anki cards takes between 30 minutes and an hour.

In the second period, I solve puzzles on for 30 minutes to an hour. I would note that this requires a membership, as does unlimited analysis of your games. I pay $99/year for a Diamond membership; there are other, cheaper levels as well. Still, for a serious hobby, it’s pretty cheap.

In the third period, I play blitz games (usually at the 3+0 time control). I will analyze many of these games – especially ones I lose – and put anything surprising into Anki. I might play for anywhere from 30 minutes to 3 hours.

Progress: Not a Straight Line

It’s fascinating to me how much chess performance can vary from day to day. Every two months or so, I’ll have an amazing chess day where my rating skyrockets by 150-200 points (and promptly returns to earth in the next few days.) More concretely: The median interval between my personal best ratings is exactly 60 days.

My rating varies by weekday. I have played over 10,000 blitz games in the last 2+ years. With the exception of a couple of multi-week breaks, I have played essentially every day. If, for each week, I find my median ELO and compare each day to that median (so, for example, that week’s median ELO is 1200, but on Wednesday is 1235, Wednesday gets a +35), and then take the median of all the deltas for each day, we get the following effect:

So on Thursday I’m about average, on Friday I’m better than average, and on other days I’m much worse. I assume this effect arises from playing fewer games on Monday and Tuesday, and so being a bit rusty, and then playing too many games on the weekend, ending with a lower rating. A win or loss is worth about 8 ELO, so on Tuesdays I lose about 9 more games than I win.

Time of day and number of games played also certainly affect rating, but I don’t have that data readily at hand. I do believe that it’s possible to determine via the extensive API (, though.


I’d like to reach 2000 in 2021. My current study strategy seems to net me around 1.5 ELO/day, so this seems achievable. Of course I could hit a wall where I need to reinvent myself again; if I do, I’ll consider getting a chess coach, reading chess books, etc.

Some day, I want to become a titled player. A candidate master needs an ELO of 2200, but this is in over-the-board play, which probably corresponds to around 2300 in online blitz. I don’t have a timeline for this, but I imagine that if I do get there, it will happen with in the next five years.

Comments on Hacker News | Reddit | My response

Massive Bulk Update

First, a life update: I graduated from college, I’m working at VisioStack doing some interesting greenfield work, and I’m taking my first class from Harvard Extension School,  hopefully en route to a degree in data science.

Signs & Seasons

My friend Elliot Lovegrove and I got back together for an ambitious project: A 4′ x 4′ painting on plexiglass with a network of ~80 NeoPixel lights inside the frame, powered by an Arduino Mega. It premiered at the Greenville Center for the Creative Arts on 8/2/19. I wrote a program to convert patterns of effects that run on the lights into Arduino-flavored C. That way Elliot could design everything and I could avoid messing everything up.

Here’s how the patterns work. An effect is some action (fading, twinkling, etc.) that happens to a subset of the lights. There are lots of effects and lots of options for each effect, which you can get a sense of at the link above. A stream is a consecutive set of effects, which happen in order and on repeat, forever. A stream’s modularity tells how many cycles a stream should go through to be active (e.g. with a modularity of 5 and length of 10 seconds, a stream would fire at times 0, 50, 100, etc.). A stream can also have an offset x to determine how long to wait before it runs the first time.

The formal way to say this is that the times when stream i begins are congruent to its offset x_i modulo (its length l_i times its modularity k_i). So each stream has its own little modular equation, and you can calculate how long it will take for everything to repeat using the Chinese Remainder Theorem. It’s a textbook case!

All streams run consecutively all the time. Two streams could potentially have effects that modify the same lights at the same time. If this happens, the conflicting colors are blended, unless the streams are on different layers, in which case the higher layer overrides the lower layer.

I don’t have a video of the painting right now; I was sort of hoping the gallery would put up a video, but if I get one through some other channel, I can add it here.


I started getting into chess last summer at the Clemson REU. It’s definitely grown on me! Although I remain objectively bad at it, I have more appreciation for how many different levels of suck are possible. Generally an ELO difference of 100 means that the better player will win or draw the other player most of the time. Since human blitz ratings go from 0 to ~3000, that means there are about 30 different levels of enlightenment to reach. I started out at about 700 a year a go – a number that’s phenomenally and embarrassingly low – and I gradually increased to about 1300 today. (I almost hit 1400 in July, though!)

The journey looked something like this:

From 700 to 900: Just playing a few hundred games online. 2 months.

From 900 to 1000: This happened while I wasn’t actually playing chess, rather four player chess, which I’ll discuss more below. Basically I played only 4-player chess for a few months, and when I returned, I had marginally improved my regular chess. 3 months.

From 1000 to 1100: There are a few common openings and a few reasonable responses to them. Using the analysis board to learn the openings to a depth of, like, two made a huge difference. 3 months.

From 1100 to 1200: I learned some basics about positional chess, like what constitutes a good pawn structure, two bishops good, etc. I read some of a beginner’s book on chess. 1200 is generally considered ‘standard’ chess noobishness, I think, and it’s about the 50th percentile of players on 3 months.

From 1200 to 1300: I did some tactics training on and try to look for options (and my opponent’s response) when I make a move. 1 month.

My best rating is 1390, from July 2019, and the highest-rated player I’ve beaten is 1490, from August 2019.

As I said, I took a break last fall to play a lot of 4 player chess. I actually was much better at it than I am at regular chess – reaching a rating of 1550, where the max was about 1800 – and I wrote a bot for it as a senior project at BJU during the spring semester. The bot used TamperMonkey to play games on the live chess server. It had a standard game tree / evaluate structure, and I tuned some parameters using a genetic algorithms idea on AWS EC2. I’m happy that I got it to work, though (TBH) I wish that I’d put more time into it to try out new ideas. I thought that by making a personal project a formal requirement I’d have more incentive to put time into the project, but I actually experienced the opposite. That’s psychology for you!

On a related note, I’ve found it much easier to invest in projects at my job than I generally did on school projects. In fact, work often feels like my most engaged moments as a hobbyist. I’m not sure exactly why this is, but I’m grateful for it.


It’s been a while since the last update. Three notable miniatures, all from April:

‘BJU Blind Date’: With 24 hours to get a date to the last artist series, I launched a website to coordinate blind dates to the event. I got ~50 Facebook shares and 7 signups, including my date(s), which was cool.

Animal Moral Value: I interacted with this Slate Star Codex post as Tibbar. You can see what I did by checking the comments, but basically I try (and fail) reproducing the claims of the post by commissioning a couple large Mechanical Turk surveys. I spent about $200 and I surveyed ~500 respondents. My work generated not one but two followup posts from Scott, first a ‘partial retraction’ and then a retraction of the retraction when other people invalidated my study. It was pretty fun. Also, it was my first solo attempt at Mechanical Turk (perhaps explaining why my results were irreparably flawed!), which I learned about while tutoring UPenn’s Crowdsourcing Class – a steep learning experience, but very rewarding.

[Note – don’t visit the following link – it will lock up your computer.]

BJUCoin: For a senior math project, I created a simulation of cryptocurrency mining and had a live audience (~20 people) compete to create the longest fork and win the most mining rewards. Later my friend automated the mining process so there’s way too much data at that page (hence why I say don’t visit it). All the coding was done in 24 hours due to my procrastination, but it went off without a hitch!

What next?

I have a wishlist of ideas that I’d like to bring to life. It takes a lot of emotional currency to invest in a personal project. Most of the things I do happen over very short periods of time when boredom, time, and curiosity explode in a magical way. A review of my projects folder reveals that I’ve initiated over 50 projects since November 2017:


The x-axis gives folder creation date; the y-axis is in log-bytes, so a 3 is a kilobyte, a 6 is a megabyte, and a 9 is a gigabyte.

Caveats: This is not an exhaustive list of my projects (but almost so). For any given project, work might be missing (on another server, deleted, etc.). Also, for gigabyte- or even megabyte- sized projects, the material may be dominated by non-code (usually generated files, occasionally images.) Also, not all of these creation dates are accurate, unfortunately: I’m not sure why.

I would consider anything 5 and above to be a ‘meaty project’, with some 4’s possibly qualifying as well. Clearly it’s been a while since I got near an 8, but not all interesting projects need to be an 8.

Anyway, some upcoming ideas include:

  • Calculating news bias with sentiment analysis and clustering of news topics. (This has been on the radar for nearly a year.) I’ve done some initial work on this in the past.
  • Collecting data on my school’s graduates, allowing society rankings and interesting analyses on marriage rates, etc. I know that the results would be interesting, but there’s so much data to scrape. I’ve done some initial work on this as well (like 2%).
  • Get reputation on StackOverflow by automatically identifying new error messages in popular open source projects (likely on GitHub) and proactively asking about and answering them, hopefully creating canonical responses.
  • Baseball:
    • Can you influence what a pitcher throws by your pattern of swinging?
    • Do batters do better against pitchers when they’ve seen a similar pitcher recently? / Can you arrange orders of pitchers in a way that’s most disorienting to batters?
  • Chess – how does time/piece odds affect the relative ELO of players?

I’m leaning towards the baseball projects, largely because it’s been so long since I did one. I’d like to get something together before next summer’s conference cycle. I’m definitely still interested in breaking into that world.

This should cover things for the next few months!


Microthought 0

Many hotels ask you to provide your last name and room number to use the WiFi.

In the US, three percent of people are named Smith, Williams, Brown, Johnson, or Jones.

Therefore, in a hotel with 50 rooms, there is a 78% change that one could sign in by just trying these names on each room.

In fact, when I tested this last, using only “Smith”, it took only ten rooms.

Your results may vary.

Update 0

Life Updates

I am college student, although this semester I’m traveling with a team from my school, Bob Jones University. Grad school applications feel very close. I’m studying for the Math GRE with the Princeton Review book. Ok that’s enough about me, let’s get to the good stuff.

Project Updates

Chess Slides

Start date: June 15, 2018

[See website for background]

Earlier this week I finished generating the SCC polynomials; I used ~20 hours of AWS computing time to get up to the 16×16 case. Interestingly, the 14×14 case broke Mono (the C# runtime), and I had to rewrite that part of the project in C++. If you want the stack trace, let me know, it’s some wacky memory management thing; estimating that the application was using 25-30GB of memory at the time.

Was pleased to see that several of the polynomials match existing OEIS sequences 🙂 My favorite is that the number of size-60 components is the same as the number of possible knight moves on an (n – 2)x(n – 2) board (A035008).

Also, this yields a general formula for the size of the largest component:

{n^2 \choose 4}- 8036 + \frac{15334}{3}x - \frac{1735}{4}x^2 - \frac{454}{3}x^3 - \frac{611}{24}x^4 + 12x^5 + \frac{1}{4}x^6 - \frac{1}{24}x^7.

I’m working on publishing an article about all this with a math magazine. I’ve never done this before so I’m paranoid about it falling through somehow, but I will post appropriate linkage if/when it’s live.

Media Bias Dashboard

Start date: August 9, 2018 (new)

Goal: create a live console to track political events and track reporting bias by news source. Inspiration: Bot SentinelNick Diakopolous. Right now I’m just sorting out what my approach will be, but I’m very excited about‘s free API, and I’ll probably use SentiWordNet. I’ll try to automate the backend with AWS (I have a free EC2 instance just sitting there… :))

I’ll need to find all the articles about a given event in real time, across the major media sources. (For example today everyone has a token article about the “Space Force.”) I think I can do this by looking for unusual words that appear in multiple news sources and then using some kind of similarity score to find all the articles on the given topic. (Basically a probabilistic union-find algorithm.) I don’t expect too many false positives, and I probably don’t care about false negatives.

Then, we need to evaluate the slant – pro or con – of each article towards the subject matter. I’ll likely work with just the headlines and article summaries I can pull from News API. Rather than use machine learning or Mechanical Turk etc, I want to formalize “bias” using word sentiment, which side is getting quoted, whether the article is rebutting the subject’s statements, etc.

Also, I want this to be very user-friendly, probably with its own domain name.

I tentatively predict a beta release in October. Stay tuned! 🙂

Floating Aces

Start date: July 4, 2018

[If I can get a better solution, I’ll do a better writeup. Fair? :)]

Suppose you have a 4×4 grid of playing cards – Ace, 2, 3, and 4 of each suit. You can swap any two adjacent (row/column) cards of the same rank or suit, and you can always swap an ace with the card above. Can you get the four aces to the bottom row?

(Not every combination of cards is solvable, but the vast majority are.)

The number of states is quite large, and so I’ve tried a breadth-first search that uses heuristics to pick a subset of the adjacent states to try. We assign a score to a given arrangement, and only look at new arrangements that are at least as high-scoring as the best score we’ve seen (minus a small fudge factor).

I arbitrarily define success as finding a solution in the first 100,000 boards considered.

This algorithm, as described, was solving about half my 30 tests. So I introduced randomness and various little tweaks and optimizations, tried a zillion different parameter values, and now I can solve (on average) about 83% of the test arrangements. (Some arrangements are solved 100% of the time, one was only solved 40% of the time.)

For your edification, the magic parameters are –

AceVal = 24, AceMoveDown = 9, AceMoveOver = 8, Lower = 15, QueueThrottle = 99,  Luck = 0.896.

I want a better solution, but I’ll likely have to change my approach.