Eldrow

Eldrow is a variation of the viral word game Wordle where the human and computer roles are reversed. In Wordle, the computer has a secret word that you are trying to guess. In Eldrow, the computer tries to guess the secret word that you have in mind. In today’s post, I wanted to explain my thought process behind Eldrow as well as how it works on a technical level.

The Solver

Strategy

At the heart of Eldrow is the Wordle solver program. Eldrow is greedy: it will try to eliminate as many words as quickly as possible. I’m using the Wordle dictionary and not differentiating between solution words and guessable words, so there are a total of 12,972 words that could be the solution.

To illustrate this strategy, let’s walk through an example game where the word is ABOUT – the most common English word in Wordle’s dictionary.

The first guess, SERAI, is guaranteed to narrow down the solution space to at most 697 words. That means even if we didn’t get any letters, or if we only got one or two letters present but not correct, there can only be at most 697 remaining words that we will need to choose between. This is the best possible performance on the first guess.

The next four best words for the first guess are:

  • reais: 769
  • soare: 769
  • paseo: 776
  • aeros: 801
S (not present), E (not present), R (not present), A (present), I (not present)

In this example game, the A in the fourth position gets a “present” hint, and this narrows down our search space to 697 words. Next, we guess NYALA, which guarantees us a solution space of 74 or less.

First guess: S (not present), E (not present), R (not present), A (present), I (not present). Second guess: N (not present), Y (not present), A (present), L (not present), A (not present).

Our guess didn’t give us any new present or correct letters, but we still ended up ruling out almost 90% of the words it could’ve been!

Unlike the first guess, for which SERAI is always optimal, the best second guess varies wildly with the score of the first guess.

The best guess at this step is BHOOT, which gives us another 10x improvement by guaranteeing that we will have at most 6 words to choose from.

First guess: S (not present), E (not present), R (not present), A (present), I (not present). Second guess: N (not present), Y (not present), A (present), L (not present), A (not present). Third guess: B (present), H (not present), O (correct), O (not present), T (correct).

This time we get lucky, and our hint from BHOOT rules out every single word except for one: ABOUT.

First guess: S (not present), E (not present), R (not present), A (present), I (not present). Second guess: N (not present), Y (not present), A (present), L (not present), A (not present). Third guess: B (present), H (not present), O (correct), O (not present), T (correct). Fourth guess: ABOUT, all correct.

And that’s how the game is played!

Speed

Making the solver fast enough for a game was a major hurdle. I originally wrote the solver in three hours using JavaScript, since that’s the programming language I’m most comfortable in and familiar with, but it soon became clear that I needed to compile to native machine code if I wanted to use it to play Wordle. I used Rust before to write the keyboard layout optimizer that produced RSTHD, and given its speed and expressiveness, it was a natural tool to reach for. Then, once I got the idea to turn the solver into an online game, I compiled the Rust solver to WASM so I could use it with React. Fortunately, existing tools made this extremely easy, despite me not having any successful previous experiences configuring Webpack, Babel, etc.

Compiling to machine code and leveraging SSE and AVX features ended up making a massive difference in performance:

VersionTime to find best first guess
JavaScript57.0 minutes
Rust, compiled to WASM14.7 seconds (230x improvement)
Rust, native & fully optimized (-C target-cpu=native)4.94 seconds (3x improvement)

I was originally planning on adding threads to parallelize the search for the best guess, but after seeing the speed of the solver after porting to Rust, I deemed further optimization unnecessary. The speed of guesses increases exponentially with each guess, so I only had to hard-code lookup tables for the first two guesses to basically guarantee the player will never wait more than 2 or 3 seconds for the next guess.

Another big performance optimization, which I made early on in both the JavaScript and Rust solvers, was also critical in making the solver run fast enough to play against: bitfields and lookup tables.

To find the optimal guess in a given situation, the solver must do two things:

  1. Calculate which words could possibly be the solution based on previous guesses
  2. Calculate which next guess would eliminate the most words from the list of possible solutions in the worst case

A natural solution would be to store candidate words as strings in a hash map and use string operations to filter down the list of candidates when evaluating both previous guesses and potential next guesses. However, this requires a large amount of memory allocations and iterating over strings. Since the list of candidate words is static, we can precompute some useful lookup tables that will speed up runtime performance significantly at the cost of extra code size. I chose to build lookup tables for the following:

  • Lists of words that have a given letter (A–Z) in a given position (1–5)
  • Lists of words that have at least N (1–5) instances of a given letter (A–Z)

Instead of storing the words themselves or hashes of them in the lookup tables, I assigned each word a numeric index based on how common it is (if two words are equally good guesses, the solver will guess the more common word) and stored each list as a bitfield with the bit at each word’s index representing whether or not that word satisfies the given condition. For example, here’s the beginning of the lookup table for “words that have at least one E”:

Byte #0123
Bits10011010110011101011100100111101
Matches
(Bit #)
other (#1)
their (#3)
there (#4)
these (#7)
price (#9)
state (#10)
email (#11)
after (#14)
video (#15)
where (#16)
years (#19)
order (#20)
items (#21)
under (#23)
games (#24)
great (#26)
hotel (#27)
store (#28)
terms (#29)

I use the same bitfield data structure to store the list of current candidate solutions, though in the case of the candidate solutions, enabled bits represent words that are eliminated. (This is just an implementation quirk, and I could’ve just as easily written it the other way around.) With this lookup table, when we encounter a guess with a yellow E, we can apply the information from the guess by bitwise-or’ing the complement of the lookup table into our candidate solution list. This is extremely fast compared to looking for the letter E in each candidate word due to the fact that we can process 64 candidate words per CPU instruction (assuming we’re running a 64-bit machine), and with modern x86 CPUs, SSE and AVX will get that to 256 or even 512 words at a time.

Counting the number of candidate solutions, which we do a lot to rank the suitability of possible guesses, is extremely fast in native code because we can use the popcnt instruction, which is available in both x86 and WASM. In contrast, I had to resort to slower methods for the same functionality in JavaScript.

Results

As Jonathan Olson notes, the greedy strategy in Eldrow is not actually the best strategy if your goal is to minimize the average or maximum number of guesses over all possible words. However, it has the advantage that the optimal solution for this heuristic does not require exhaustively searching the game’s decision tree. Although there isn’t a lot of information about other solvers that can solve for the entire guessable word list (most people only target the solution words), it seems that Eldrow does fairly well:

GuessesWords that take that many guesses to get
11
266
31716
46414
54086
6645
740
84

99.7% of words can be guessed in six tries or less, and the median number of guesses per word is four. Given that there’s only a handful of words that require 7 or 8 guesses, it may be possible to fine tune the decision tree to be able to guess everything in 6 guesses or less. However, the existence of the 7s and 8s is a big part of what makes Eldrow fun – if you want to know what they are, you’ll have to play Eldrow to find them!

The Game

Once I had the solver, the first thing I did was (obviously) see if it would help me beat Wordle. As this got boring, the idea slowly dawned on me that I could make the solver into its own game. I was aware of Absurdle, an adversarial variant in which the computer will try to divulge as little information as possible with each guess, so it only made sense to me that it should have an equal and opposite adversary that tries to gain as much information as possible with each guess.

By the way, since Absurdle and Eldrow are both deterministic, if you pit them against each other you’ll always end up with the word BOBBY in 5 guesses:

⬜⬜⬜⬜⬜
⬜⬜🟨⬜🟩
⬜⬜⬜⬜⬜
⬜🟩⬜⬜🟩
🟩🟩🟩🟩🟩

I wanted the UI to be as simple and intuitive as the original Wordle, so I ended up with a system where tapping a letter toggles through the possible hint types (black, yellow, green; not present, present, correct). I also wanted to ensure that it was accessible to as many people as possible, so I included not only the color blind mode from the original Wordle but also a high contrast mode and support for screen readers. (If you rely on a screen reader, I would love to hear feedback about how well I did because I don’t use a screen reader outside of accessibility testing.)

In terms of tech, it’s nothing too special. I started with some starter code for Rust + WASM and bumbled my way through configuring Webpack and Babel to let me write React in JSX.

Anyway, that’s everything remotely interesting I have to say about Eldrow. If you’re looking for other riffs on the Wordle concept, check out Wordles of the World, which is as far as I know the most comprehensive list of Wordle spinoffs.

RSTHD Today

Since I released the RSTHD keyboard layout into the wild in 2016, it’s occasionally gotten some interest from the tiny, niche community of keyboard layout designers.

The most common question I get: Do I still use RSTHD? Yes! RSTHD is my preferred keyboard layout on split ortholinear keyboards. I use an Ergodox EZ at work, so effectively this means I use RSTHD almost every day. Subjectively speaking, it’s more comfortable to be than QWERTY and Dvorak. It has a substantial inward roll bias and a phenomenal same finger usage rate, which, although it doesn’t help me type much faster, makes it easier for me to involve my wrist muscles when typing rather than relying primarily on finger strength. On staggered keyboards, I prefer Dvorak because it’s widely supported and I have muscle memory for it. Given that the E key on the thumb is such a crucial feature of RSTHD, I don’t see any significant efficiency gains for this form factor.

A few months back, I pulled up the old simulated annealing program and decided to see if I could further optimize the layout. One of the weaknesses of the original layout generation was that I used a corpus that is not representative of what I actually type, so I downloaded my entire Facebook message history, normalized the messages, and used that as my corpus for this run. I also tweaked some of the weights in the heuristic. This is what I came up with:

- U , C Z   Q G Y H ;
O I A N M   D T S L R B
' / . W V   J P F K X
        E

This new layout does fix one of the most annoying issues of RSTHD, which is that many common words such as “here” and “there” and “ever” require tricky and precise movements to type quickly. However, as a whole it looks remarkably similar overall to RSTHD. The vowel cluster is almost identical, and the main differences are the placements of some of the more lesser used keys. This indicates to me that I have hit the point of diminishing returns for this particular heuristic, so I don’t have any plans to learn this new iteration.

What about the more recent developments in keyboard layouts? Since the publishing of RSTHD, there has been some renewed interest in layouts that put a letter on a thumb key. I don’t follow them very closely. I already made my contribution to the keyboard layout design world, and for me, RSTHD is my end-game layout. But it’s always exciting to check every once in a while and see what new ideas people have come up with and how they’ve come to their various conclusions about what makes the best keyboard layout.

What do I recommend? For most people, QWERTY is still the right choice simply because of its ubiquity. I recognize that not everyone has the luxury of configuring the computers they use, and maintaining muscle memory in multiple keyboard layouts is harder for some people than others.

For people who have gotten jaded with QWERTY and aren’t afraid to try something new, my recommendation is to learn Colemak. It’s supported on virtually every operating system, including as a hardware keyboard layout on iPad, which makes it easy to use everywhere. Plus, the punctuation and ZXCV placement makes it easy to switch from QWERTY compared to Dvorak, the other popular alternate layout.

For people who are really hardcore and aren’t satisfied with Colemak, I honestly think you might be better off creating your own layout. I generated RSTHD using a heuristic that reflects how I type and what movements feel most natural to me, but there’s a large range of possibilities and ideas out there. Past discussions have shown that people can’t agree on what should constitute the “home row” of keys, and some people would rather have keys like Tab or Shift on the thumb rather than leave that space to E. The keyboard layout design community is overflowing with differing opinions, and given the lack of any reliable research in this space, whatever feels best to you is the best for you. There’s no need to settle for someone else’s perfect.

The True Meaning of Christmas?

Most people in America know Christmas as an occasion for spending time with your loved ones, buying gifts for each other after taking a picture with the local mall Santa, listening to the most seasonal music ever, and lying to your kids about Santa eating the cookies you made last night. Within Christian communities we often talk about the true meaning of Christmas as something that has been diluted in today’s society: the birth of Jesus Christ, a story often retold with elaborate details picturing the Savior sleeping in a feeding trough and being hailed by three wealthy astrologers from the East. Many would say it is the greatest story of all time.

(Source: xkcd)

Since I’ve become interested in Christian history recently and have some nerdy literature at my disposal, I thought it would be interesting to look at the Nativity from a historical context. Our modern understanding leaves too much unanswered for my comfort about the origins of this great tradition that has become the most culturally energetic holiday in American society today.

Continue reading “The True Meaning of Christmas?”

Stuff I made in Summer 2017

This post will be a bit different than my usual semester blog posts. Doing things has been the most interesting and memorable part of my summer, not thinking about things, so instead of telling you about what I thought about, I’ll show you the two most demonstrable things I made this summer: text formatting in Messenger and two tools to make window tiling easier.

Text formatting in Messenger

During an internal hackathon at Facebook, I added LaTeX math typesetting to Facebook Messenger’s web client. I also added *bold*, _italic_, ~strikethrough~, and `monospace` ranges…

Screen Shot 2017-09-02 at 11.27.27

…and both of these projects made it into production! You can read about them in the Facebook Help Center. Additionally, people on r/math have figured out all the features and easter eggs in math mode.

I actually wanted to make math in Messenger happen even before I signed my internship offer at Facebook. Being able to type math in Messenger would have been helpful throughout high school and the first few years in college when I was still taking math courses. I recall that at one point I even had someone join a nonce chat room on MathIM so that I could explain some calculus problem to them.

With math typesetting on Messenger, math students and researchers who talk about math every day won’t have to use ugly ASCII symbols to express themselves to other people online in the area of their expertise.

As for text formatting, practically every other chat client that’s newer than IRC has formatting, so there’s no reason we shouldn’t have at least some of the basics.

Window tiling solutions

I used two 1440p displays at work over the summer, and now that I’m back at school I upgraded to a 43 inch 2160p monitor. That’s equivalent to four 21.5″ full HD monitors, but with no borders in the middle. To optimize how well the screen estate is used on such a huge monitor, it’s much better to have many windows on the screen at once instead of one huge window. And since I’m bothered by inconsistency, I wanted to be able to switch between windows quickly and resize them quickly using only my keyboard.

The first little tool I made is a window switcher that lets you switch to any window visible on your screen by pressing alt-tab, followed by the first letter of the app’s name. (If there are multiple apps that start with the same letter or multiple windows of the same app visible, it’ll display the next available unused letter. For example, see the Chrome inspector, G for “Google Chrome”, alongside the actual browser, which is assigned H.) To me, this is more predictable and easy to use than the default cmd-tab switcher. I never remember which windows I focused most recently, so I have to wait until the switcher loads before I can select a window. With this, I know exactly what I need to press before the letters even pop up. Here’s a demo of the switcher in action:

(It’s faster when I’m not making a QuickTime screen recording.)

The second tool, shown right at the end of the video, is a keyboard-based tiling manager that lets you tile windows on any grid from 1×1 to 10×10. All you do is press alt-space, type the number of columns and rows, then the column and row number to move the window to, and then the number of columns and rows the window should take up. For example, the invocation for putting a window that takes up the right 3/5 of the screen but only the top half would be alt-tab 5 2 3 1 3 1. This can be a bit confusing for larger grids, but it’s doable, and for smaller grids, it’s pretty easy to gain muscle memory for the commands. There are a few special shortcuts for common grid sizes, including 1×1 (maximizing a window), 2×1, 2×2, 3×1, 3×2, 4×1, 4×2, and 4×4. In addition, if the number of rows in the grid is equal to 1, you can skip typing in the row numbers for position and size. So moving a window to the left half of the screen is simply alt-tab H 1 1 (H is the shortcut for halving the screen, i.e. 2×1 grid).

It’s not a feature right now, but a possible future expansion would be the ability to show an overlay of the grid on top of all the windows as you’re typing your invocation. That might make it a bit less arcane…

Both of these tools are written in Lua using Hammerspoon, a powerful automation tool for macOS. I highly recommend it over other window management apps for people who don’t mind a bit of coding. The app is stable, endlessly customizable, and well documented. If you’re interested in my scripts, they’re in one of my dotfiles repos. The switcher is navigator.lua, and the tiling manager is mosaic.lua.

Introducing the RSTHD layout

Screen Shot 2016-04-22 at 22.40.26.png

This is the actual RSTHD layout, as implemented in the firmware of my ErgoDox EZ. I have been using it consistently for four months, and since I started learning the layout, I have gotten up to about 120WPM on it. On a good day, I can occasionally manage 135. This is my fourth time learning a nonstandard keyboard layout for English (here I’m excluding Zhuyin and Dubeolsik because I’m not fluent enough in Chinese or Korean to run into issues with my typing speed anyway), so I think my brain is used to handling switching between layouts. My muscle memory for each layout is sufficiently abstracted away from my muscle memory from the physical keyboard that I can switch between layouts and learn new layouts with relative ease, as my typing speed history shows:

Screen Shot 2016-05-16 at 16.25.03.png

I switched to Dvorak in eighth grade and it has served me well as my primary layout over the years. When I used other people’s computers, including for doing work at school, I used Portable Keyboard Layout on a flash drive to remap the keyboard at the software level, so switching between Dvorak and Qwerty was never an issue. Up until I started learning RSTHD, I had a working proficiency of Qwerty and could sustain 80–90WPM fairly easily; my speed has since decreased to about 60–70, which is still above average, and I still use Qwerty on my phone and tablet without any issues. In my personal experience, learning an alternate layout does take a fair bit of commitment, but it is possible and in fact practical to retain muscle memory for multiple layouts as long as you use all of them on a regular basis. And if I have to, I have no problem getting on someone else’s computer and using Qwerty—perhaps to help troubleshoot an issue with their computer or something similar.

Since I will likely be working in front of a keyboard for eight hours a day for several decades of my life, I want to make sure that my keyboard is ergonomic and efficient. Dvorak has its own flaws; while it is a huge step up from Qwerty in terms of comfort, it still has little quirks that annoy me when I type:

  • L, a relatively common key, is in one of the hardest to reach corners of the keyboard, requiring you to stretch your pinky, the weakest finger, upward. This is exacerbated by how commonly the L key is used twice in succession.
  • The center column on the left side is used too often; for example, how much lateral movement your left index finger has to make to type words like “typing”, “hiking”, and “skippy”.
  • The bottom row on the left side often feels cramped on a standard staggered keyboard. The staggering is part of the culprit; it makes the middle and ring fingers bend towards the index finger to reach the keys if you are using the standard fingering.

When I was scouting out other alternate layouts, none of them struck me as much better than Dvorak; they all had some small but noticeable flaws, and since I’ve been using alternate layouts for years, I had come to know what I wanted in a keyboard layout very well and had some extremely specific requirements for a layout. So when nothing I found suited my particular needs, I did the only thing any sane engineer-at-heart would do: I created my own.

At first, I tried starting with the Malt layout and swapping keys around until I saw something I liked while trying to balance out hand and finger usage and eyeballing digraph comfortableness by intuition. But it turns out that I had so many different parameters I wanted to optimize at the same time that it was impossible for me to keep them all in mind at the same time. So in December, I wrote a Rust program to do the optimization for me using the simulated annealing technique made popular (relatively speaking) by the carpalx project.


Typing on RSTHD is very comfortable; my fingers move less than even in Dvorak. There are very few awkward hand stretches, and the vast majority of rolls feel very comfortable, since you tend to roll toward the center. Having E on a thumb key allows the rest of the alphabet to be arranged more optimally for comfortable strokes. Putting Backspace and Enter on the thumb as well greatly reduces the amount of load on the two pinkies, which are greatly overloaded on a standard layout. Escape on the home row makes working in Vim a pleasure; as for HJKL, I tend to use the arrow keys instead—they are placed in much more convenient locations on this keyboard. Down and Up take from Dvorak’s positioning of the J and K keys, and Left and Right are in the same position but on the other hand. In my opinion, this arrangement is much more usable than an arrow cluster awkwardly to one side of the keyboard. The number row is rearranged to put 1, 0, and 2, the most frequently typed numbers, on strong fingers while maintaining some semblance of natural ordering for ease of memorization.

The arrangement of the alphabet itself on the layout is based on optimizing a lot of parameters. The simplest parameter is that the easiest to reach keys are given the most frequently typed letters, and the hardest to reach keys are given uncommon letters. As you can see, this has worked out fairly well. The home row consists of the nine most common letters RSTH E NAIO, and the next two (DLU) are on the next easiest to reach keys. In the eight corners we have the least common letters: J, K, Z, Q, B, and X, with symbols taking up the bottom two corners. These are arranged in a way such that even when they occur, they appear in pleasant strokes of the hand; try tracing out the words JACK and QUEEN. Your hand will barely move at all.

Most of the strokes roll your hand toward the center of the keyboard, which people generally prefer to rolling outwards. Having most rolls in one direction means that it is relatively unlikely, compared to other layouts, that a roll will reverse direction in a hand. Reversing a roll prevents you from simply using the weight of your hand to support the rolling motion of your fingers, which slows down your typing. The keyboard is also designed so that as many strokes as possible consist of typing two to three letters successively using the same hand. Alternating hands for every keystroke at fast speeds can mess up your typing rhythm because it requires precise hand-to-hand coordination, and using one hand to type many keys in succession fatigues it, preventing fast typing.


My own metrics report the following penalties for various layouts (lower is better):

Screen Shot 2016-05-17 at 11.21.09.png
Full size

As you can see, the scaled penalty for RSTHD is much, much lower than the next best layout (MTGAP). Qwerty, naturally, is way worse than all of the other layouts. Surprisingly, my analysis showed that the optimized layout generated by carpalx (QGMLWY) is actually worse than Dvorak; it accumulates a large penalty due to high same finger usage. And the other layouts score about as well as I would intuitively think based on just looking at the layout: Colemak and Workman are in a league, and Maltron, Arensito and MTGAP, which are more liberal with moving around punctuation, beat Colemak by a small margin. But the gap between Colemak and MTGAP is still not as big as the gap between MTGAP and RSTHD.

For a full description of the heuristic I used along with brief justification, see the readme of my optimization program.

Patrick Gillespie’s keyboard layout analyzer seems to agree with the results: for the first chapter of Alice in Wonderland, it gives the following scores (higher is better):

Screen Shot 2016-05-16 at 17.55.14

Here again, we see Qwerty at the bottom, other alternate keyboard layouts in the middle, and RSTHD scoring a fair bit more than the rest. I haven’t done any more analysis using other people’s metrics, but I believe that they would yield similar results.

I think putting the E on the thumb key is the main differentiating factor in breaking past the sort of efficiency plateau that other layouts hit; getting an extra home row key for free is kind of a big deal. Without redoing your entire layout, I suppose you could also put Shift and/or Command/Control on the thumb instead of E and get similar significant improvements in comfort, but I did not consider those solutions. Relieving the non-thumb fingers of E key duty frees up space in the rest of the keyboard to improve in rolling comfort and same finger usage.

In the end, I learned Rust, wrote a simulated annealing program, and generated a unique keyboard layout that I’m proud to call my daily driver. The list of people in the world that use keyboard layouts that they’ve created probably fits on a single page of paper in normal sized font. If nothing else, I’m excited to be joining a small group of geeks who have a hobby that nobody really understands or appreciates. I seem to be good at having those :^)


Appendix: raw output of the optimizer.

Reference: QWERTY
q w e r t | y u i o p -
a s d f g | h j k l ; '
z x c v b | n m , . /

total: 5035296.5; scaled: 1.6927670825776282
base: 3483264.5 / t: 609156; n: 467607; e: 272982; y: 190108; o: 179775;
same finger: 776140 / ed: 107595; un: 66790; de: 49385; rt: 48070; tr: 46840;
long jump hand: 197021 / in: 40205; on: 21898; ve: 15038; be: 11513; no: 10805;
long jump: 348040 / ce: 76180; un: 66790; my: 44290; ec: 41740; mu: 22880;
long jump consecutive: 79184 / ct: 22384; ex: 15664; cr: 15616; o,: 8888; xt: 5064;
pinky/ring twist: 27272 / pl: 23656; lp: 2968; Pl: 320; PL: 128; Sz: 128;
roll reversal: 23496 / eas: 10040; cas: 3968; I'l: 1992; opi: 1312; sad: 904;
left crunch: 76 / Sz: 64; sz: 12;
same hand: 53342.5 / ever: 1370.5; were: 955; look: 914; tter: 609; ered: 561.5;
alternating hand: 52090.5 / with: 2424; ight: 1780; when: 911.5; them: 867.5; they: 846.5;
roll out: 40460.875 / re: 3399.375; hi: 2489.625; te: 1935.625; ve: 1879.75; wa: 1785.5;
roll in: -45014.875 / in: -5025.625; er: -4440; ou: -3636.25; at: -2978.25; on: -2737.25;

Reference: DVORAK
' , . p y | f g c r l /
a o e u i | d h t n s -
; q j k x | b m w v z

total: 2786545.75; scaled: 0.9367815618596818
base: 2285275.75 / l: 309984.5; f: 183732; i: 170015; y: 142581; d: 133745;
same finger: 332725 / gh: 34610; ki: 27690; e.: 25295; pi: 20610; up: 17845;
long jump hand: 16912 / bl: 3784; br: 2028; rm: 1415; Mr: 1188; k,: 1090;
long jump: 17570 / xp: 6150; rv: 5740; ky: 2010; mf: 1690; zl: 560;
long jump consecutive: 12304 / wr: 5576; lv: 3216; rw: 1864; wf: 1056; "Q: 240;
pinky/ring twist: 12192 / nl: 10496; o;: 856; ln: 632; o:: 184; NL: 24;
roll reversal: 18824 / rst: 7112; nst: 5392; nsw: 3096; nsc: 1456; ea,: 464;
left crunch: 5964 / ju: 3800; eq: 916; Ju: 684; o;: 428; o:: 92;
same hand: 7426.5 / ooke: 389.5; appe: 251; you,: 242; ooki: 232; "You: 229.5;
alternating hand: 100237 / here: 2119; have: 1477; ever: 1370.5; some: 1062.5; were: 955;
roll out: 20407.625 / ea: 1699.75; yo: 986.25; e,: 981.125; ke: 958.875; pe: 739.875;
roll in: -37328.125 / th: -7546.875; nd: -4083.75; ou: -3636.25; ng: -2612.75; st: -1985.875;

Reference: COLEMAK
q w f p g | j l u y ; -
a r s t d | h n e i o '
z x c v b | k m , . /

total: 2562625.375; scaled: 0.8615039610434362
base: 1996572 / h: 176607.5; g: 142815; d: 133745; l: 132850.5; b: 129280;
same finger: 192140 / e,: 39245; kn: 25540; nk: 18110; y.: 10305; ?": 9080;
long jump hand: 22018 / my: 4429; y,: 3536; mu: 2288; y.: 2061; l,: 1647;
long jump: 42910 / y.: 20610; lk: 8080; u,: 5070; lm: 3820; kl: 2490;
long jump consecutive: 40088 / y,: 28288; xp: 4920; u.: 2544; y?: 2144; .-: 1616;
pinky/ring twist: 216 / I;: 136; rz: 40; I:: 24; i;: 16;
roll reversal: 168520 / was: 66144; you: 62096; You: 9752; iou: 5648; car: 5488;
left crunch: 15684 / ct: 11192; tc: 4256; CT: 172; TC: 40; rz: 20;
same hand: 32116.5 / look: 914; like: 680; hink: 474.5; houl: 445.5; ooke: 389.5;
alternating hand: 64943.5 / with: 2424; ight: 1780; ever: 1370.5; were: 955; very: 909.5;
roll out: 46046.875 / he: 7694.625; hi: 2489.625; me: 2163.625; wa: 1785.5; le: 1709.375;
roll in: -42945.5 / in: -5025.625; ou: -3636.25; at: -2978.25; on: -2737.25; en: -2640.75;

Reference: QGMLWY
q g m l w | y f u b ; -
d s t n r | i a e o h '
z x c v j | k p , . /

total: 2876821.125; scaled: 0.9671303572419102
base: 2007832.5 / y: 190108; w: 173013; i: 170015; r: 150172.5; c: 93232;
same finger: 709525 / ai: 92120; ay: 72690; ki: 41535; e,: 39245; if: 35740;
long jump hand: 17757 / up: 3569; y,: 3536; y.: 2061; cl: 1804; pu: 1412;
long jump: 17770 / u,: 5070; lv: 4020; py: 2460; ky: 2010; yp: 1690;
long jump consecutive: 20376 / cl: 14432; u.: 2544; .-: 1616; Cl: 672; b,: 456;
pinky/ring twist: 1192 / o;: 856; o:: 184; Sz: 128; sz: 24;
roll reversal: 3568 / Oh,: 1768; eho: 816; e-b: 344; oh,: 288; ohe: 88;
left crunch: 19284 / nc: 16500; xt: 2532; Sz: 64; NC: 64; XT: 56;
same hand: 11341 / abou: 649.5; befo: 413.5; ooke: 389.5; appe: 251; you,: 242;
alternating hand: 99082.5 / with: 2424; ight: 1780; ever: 1370.5; some: 1062.5; were: 955;
roll out: 25358.5 / nd: 4083.75; ng: 2612.75; nt: 1389.875; fo: 1015.25; ld: 993.875;
roll in: -36981.375 / he: -7694.625; ou: -3636.25; ha: -3357.75; hi: -2489.625; st: -1985.875;

Reference: WORKMAN
q d r w b | j f u p ; -
a s h t g | y n e o i '
z x m c v | k l , . /

total: 2567358.375; scaled: 0.8630951020222921
base: 1914144.75 / l: 177134; r: 120138; m: 115986; d: 106996; b: 96960;
same finger: 357685 / ly: 65280; e,: 39245; kn: 25540; ny: 20810; po: 18325;
long jump hand: 27848 / ul: 7587; pl: 2957; cr: 1952; lf: 1885; rm: 1415;
long jump: 67590 / lf: 18850; rm: 14150; Mr: 11880; fl: 10610; u,: 5070;
long jump consecutive: 22224 / mb: 9832; p,: 5720; u.: 2544; .-: 1616; dm: 1240;
pinky/ring twist: 1192 / o;: 856; o:: 184; Sz: 128; sz: 24;
roll reversal: 71448 / had: 38120; mad: 7744; has: 6576; dar: 3424; sam: 2784;
left crunch: 1020 / tm: 640; xh: 224; Sz: 64; mt: 48; TM: 32;
same hand: 39148 / that: 4015.5; look: 914; what: 843.5; like: 680; ooke: 389.5;
alternating hand: 64044 / here: 2119; ever: 1370.5; some: 1062.5; were: 955; very: 909.5;
roll out: 46211.25 / th: 7546.875; ha: 3357.75; wa: 1785.5; le: 1709.375; ne: 1508.125;
roll in: -44176.625 / in: -5025.625; ou: -3636.25; at: -2978.25; on: -2737.25; en: -2640.75;

Reference: MALTRON
q p y c b | v m u z l =
a n i s f | d t h o r '
, . j g / | ; w k - x
        e
total: 2388307; scaled: 0.802901571474436
base: 1972571.5 / l: 309984.5; ,: 160419; d: 133745; w: 115342; b: 96960;
same finger: 98010 / n.: 9960; hu: 7265; sc: 7015; tw: 6100; rl: 6000;
long jump hand: 11064 / y,: 3536; y.: 2061; lk: 808; p,: 715; lw: 591;
long jump: 7790 / p.: 3810; uk: 1760; m;: 1260; P.: 250; m:: 130;
long jump consecutive: 27632 / y.: 16488; p,: 5720; -l: 1656; -m: 1352; l-: 1144;
pinky/ring twist: 134600 / lo: 63248; ol: 36496; n,: 28192; Lo: 5680; Ol: 544;
roll reversal: 24432 / hro: 6352; ian: 5624; ork: 4456; pai: 3264; olu: 1288;
left crunch: 14836 / n,: 14096; I.: 620; N,: 64; .i: 24; i.: 16;
same hand: 48167 / ould: 2370; woul: 1016; look: 914; thou: 843; been: 702;
alternating hand: 64550.5 / here: 2119; have: 1477; ever: 1370.5; tion: 1269; were: 955;
roll out: 39093 / th: 7546.875; in: 5025.625; to: 2750.375; or: 2301.125; ho: 1239.875;
roll in: -39603 / an: -4981.125; ou: -3636.25; ng: -2612.75; as: -2421.625; is: -2067.25;

Reference: MTGAP
y p o u - | b d l c k j
i n e a , | m h t s r v
( " ' . _ | ) f w g x
        z
total: 2299921.375; scaled: 0.7731880726619926
base: 1965028 / o: 179775; d: 160494; y: 142581; b: 129280; g: 119012.5;
same finger: 144135 / mb: 18435; tl: 13750; au: 8525; rk: 7165; sc: 7015;
long jump hand: 13885 / y.: 2061; lf: 1885; gl: 1109; fl: 1061; "Y: 715;
long jump: 23090 / lw: 5910; wl: 3930; u.: 3180; o': 3130; .-: 2020;
long jump consecutive: 28928 / gl: 8872; "Y: 5720; xc: 2800; "O: 2688; y?: 2144;
pinky/ring twist: 15952 / sk: 9160; ks: 6384; Sk: 368; KS: 32; SK: 8;
roll reversal: 28680 / oin: 9216; ein: 5272; "Yo: 3688; pie: 2240; "Ye: 1936;
left crunch: 3596 / e?: 2268; a': 548; 'a: 288; "E: 232; e": 100;
same hand: 12314 / upon: 281; appe: 251; ion,: 246; you,: 242; open: 241.5;
alternating hand: 86349 / here: 2119; have: 1477; ever: 1370.5; some: 1062.5; were: 955;
roll out: 25492.375 / an: 4981.125; on: 2737.25; en: 2640.75; ai: 1151.5; ay: 908.625;
roll in: -43932 / th: -7546.875; in: -5025.625; ou: -3636.25; st: -1985.875; ea: -1699.75;

Reference: CAPEWELL
. y w d f | j p l u q /
a e r s g | b t n i o -
x z c v ; | k w h , '

total: 2490136.375; scaled: 0.8371345931126758
base: 2018167.25 / h: 282572; f: 137799; e: 136491; w: 115342; ,: 114585;
same finger: 159825 / ey: 19440; gs: 11890; ds: 10505; ye: 10235; cr: 9760;
long jump hand: 13172 / ?": 1816; l,: 1647; hu: 1453; lk: 808; p,: 715;
long jump: 33710 / ?": 18160; u,: 5070; d;: 2970; ?': 1790; dv: 1560;
long jump consecutive: 34496 / l,: 13176; hu: 11624; cy: 4016; u': 2768; Hu: 1272;
pinky/ring twist: 18784 / ex: 15664; xe: 2320; Ex: 392; iq: 216; EX: 192;
roll reversal: 114472 / ear: 30624; hou: 28056; ion: 27976; eac: 3504; nou: 3384;
left crunch: 15304 / ex: 7832; sc: 5612; xe: 1160; cs: 224; Ex: 196;
same hand: 57649 / with: 2424; thin: 1950; ever: 1370.5; tion: 1269; woul: 1016;
alternating hand: 35187 / hand: 653.5; righ: 417.5; take: 409; heir: 382.5; stan: 357.5;
roll out: 54107.625 / th: 7546.875; re: 3399.375; to: 2750.375; hi: 2489.625; ve: 1879.75;
roll in: -49433.5 / in: -5025.625; er: -4440; ou: -3636.25; on: -2737.25; ed: -2689.875;

Reference: ARENSITO
q l , p   | f u d k
a r e n b | g s i t o
z w . h j | v c y m x

total: 2304346.25; scaled: 0.7746756281107176
base: 1907652.75 / h: 282572; m: 144982.5; w: 144177.5; d: 106996; t: 101526;
same finger: 151645 / e,: 39245; e.: 25295; ok: 19650; gs: 11890; ui: 8225;
long jump hand: 20648 / ck: 4524; uc: 2912; mu: 2288; dy: 1655; cu: 1423;
long jump: 17480 / lw: 5910; ph: 4820; wl: 3930; dm: 1550; uy: 400;
long jump consecutive: 60736 / mu: 18304; dy: 13240; um: 11368; w,: 7936; l.: 6600;
pinky/ring twist: 72 / rz: 40; kt: 24; tk: 8;
roll reversal: 48400 / ear: 30624; eal: 6176; mou: 3344; dou: 2040; tou: 1792;
left crunch: 57660 / we: 35052; n.: 7968; ew: 7564; We: 6584; EW: 216;
same hand: 38639 / here: 2119; were: 955; when: 911.5; been: 702; hear: 534.5;
alternating hand: 49758 / thin: 1950; hing: 1629; know: 890.5; ning: 694.5; ing,: 642;
roll out: 54585.125 / he: 7694.625; er: 4440; ha: 3357.75; to: 2750.375; it: 2501.375;
roll in: -45269.625 / an: -4981.125; ou: -3636.25; re: -3399.375; en: -2640.75; is: -2067.25;

RSTHD:
j c y f k | z l , u q =
r s t h d | m n a i o -
/ v g p b | x w . ; '
        e
total: 1865452.375; scaled: 0.6271281888794945
base: 1679719.75 / d: 133745; l: 132850.5; b: 129280; w: 115342; g: 95210;
same finger: 88285 / wn: 13635; ty: 10575; ui: 8225; sc: 7015; nl: 6560;
long jump hand: 11291 / by: 2226; ,": 1918; w,: 992; l.: 825; 'l: 595;
long jump: 11990 / lw: 5910; wl: 3930; gy: 890; "Q: 300; u;: 280;
long jump consecutive: 7352 / u': 2768; u.: 2544; vy: 1200; 'u: 376; "U: 208;
pinky/ring twist: 2288 / s?: 2032; iq: 216; S?: 16; s/: 16; /S: 8;
roll reversal: 1640 / cry: 1016; .-I: 392; io,: 80; io.: 32; aqu: 32;
left crunch: 28784 / gh: 27688; s?: 1016; GH: 44; Gh: 16; S?: 8;
same hand: 49379.5 / ther: 2398; here: 2119; ever: 1370.5; woul: 1016; very: 909.5;
alternating hand: 36579 / what: 843.5; whic: 719; ment: 587.5; went: 562.5; able: 512.5;
roll out: 23517.5 / wa: 1785.5; no: 1350.625; ai: 1151.5; li: 1139.625; wi: 1010.875;
roll in: -46589.375 / th: -7546.875; in: -5025.625; an: -4981.125; ou: -3636.25; on: -2737.25;