Questions & Answers
Generations of Virtual Monkeys Typing Hamlet
Versions
Added in 2026Version 3.0 (November 2026) [source code]
- The program no longer runs on a server: it runs in your browser, as WebAssembly (a browser from before about 2021 cannot run it). Four of its five original files of 2015 (
Header.h,Evolution.cpp,Type.cpp,Output.cpp) are compiled exactly as written. The fifth,Source.cpp, gains six lines and loses none: the source code page shows them in green. The code is under the MIT licence. - On 7 April 2016 the server finished a Hamlet, and its counter read 11. It was last seen that evening, at 23:35, on line 151 of its twelfth Hamlet, one letter away from the line: “What we have two nighss seen.” In November 2026 the troop took up that line again, in the browsers of whoever is watching, and the count started again from zero.
- The monkeys you see are yours: they are drawn at random in your browser, as they were on the server, and they type live, one generation after another, at the pace measured on the server in 2016: 760 generations per second. That is about 20 seconds for an average line of text, and about 26 hours for one Hamlet.
- Nobody watches for 26 hours, so the visitors type in relay. A small program in front of this site remembers which line the troop has reached and how many lines it has typed. Your browser asks it for the line, types it and reports it; the next line goes to whoever is watching then. See What was added in 2026?
- The algorithm itself is untouched, and so are the keyboard and the randomness.
- This page was copy-edited (typos, grammar, tangled sentences) and its dead links were replaced. Of the four original images, three are lost: two have been redrawn from the code and from the 2016 archive, and one is left out. The fourth was a picture of the code of the keyboard: a drawing of the keyboard, made from that same code, takes its place. Wherever the facts have changed since 2015, the new text is marked [Update v. 3.0]; so are two places where the code does not do exactly what the text says.
Version 2.1 (October 2015)
- At least twice as fast: each couple now has two babies (see the explanation below).
Version 2.0 (October 2015)
- DNA encoded as a single binary string;
- Stronger genotype/phenotype distinction: the DNA is decoded into an int, a double and a bool;
- Enhanced statistical output (images of the hands);
- Help page reworked: longer explanations.
Version 1.0 (October 2015)
- Website launched.
Contents
- What is it?
- How does it work? (nontechnically)
- What was added in 2026?
- You keep insisting on “randomly,” but is it truly random?
- Does it really mimic evolution?
- Does it simulate intelligence?
- Is such an experiment a new thing?
- Are the monkeys able to type any text?
- How does it work? (technically)
- Is it useful?
- Do you simulate primate bones, hand muscles…?
- (Misc.)
- Can I ask more questions, or correct you?
What is it?
This is a genetic algorithm related to the infinite monkey theorem.
- a genetic algorithm — “a search heuristic that mimics the process of natural selection” (source of the definition);
- related to — this is not a direct implementation of this theorem;
- the infinite monkey theorem — “If an army of monkeys were strumming on typewriters they might write all the books in the British Museum. The chance of their doing so is decidedly more favourable than the chance of the molecules returning to one half of the vessel.” (A. S. Eddington; source).
My algorithm simulates generations and generations of virtual monkeys randomly typing on a keyboard to produce the Shakespearean tragedy Hamlet.
| Gene | DNA | Finger | Condition | [shift] | Character |
|---|---|---|---|---|---|
| 1 | 100001000001 | 8: right ring | .32 | pressed | L |
| 2 | 011001101001 | 6: right index | .52 | pressed | U |
| 3 | 001000000001 | 2: left middle | 0 | pressed | C |
| 4 | 011101111111 | 7: right middle | .63 | pressed | I |
| … | |||||
| 9 | 010001000110 | 4: left thumb | .35 | not pressed | [space] |
| … | |||||
| 13 | 011000101000 | 6: right index | .2 | not pressed | n |
| 14 | 001010001000 | 2: left middle | .68 | not pressed | e |
| 15 | 100110001000 | 9: right pinky | .68 | not pressed | p |
LUCIANUS nephew to the king., as the server recorded them in March 2016. The screenshot shown here in 2015 is lost: this table was rebuilt in 2026 from the same data.How does it work? (nontechnically)
- Twenty virtual monkeys are created.
- Each of them has a randomly generated binary DNA (10110…).
- Each of their genes is decoded into a group of three pieces of data (see the example above; on the live page, this data is available in the details of each line typed in your browser):
- a finger;
- the condition of this finger (folded, straight…);
- whether the monkey must press the [shift] key.
- This data is applied to a virtual standard US keyboard.
- A character is created (a, Z, 5, @, [tab]…) according to the finger to use and its position over the keyboard (see this example), and to whether the [shift] key is pressed or not.
- The order of the genes in the DNA gives the sequence of fingers to activate: a sentence is produced.
- The program, which “knows” Hamlet, compares the sentences generated by the monkeys with the original one and rates the monkeys between 0 and 1. The closer the score is to 1, the closer the generated sentence is to the expected one. The monkeys never have access to the original sentence: the only information they get is this score. If the sentence is found at this stage (in the first generation, that is: never), the loop restarts with new monkeys [goto b].
- When all the sentences have been produced and rated, the monkeys are ranked. The monkey closest to the original sentence is cloned for the next generation, and is guaranteed the opportunity to reproduce. The other monkeys have a chance of reproducing that is proportional to their score.
- The selected monkeys have sex with randomly selected monkeys of the group. They have babies. Each baby’s DNA is a mix of the DNA of both parents. [Update v. 2.1: each couple has two babies.]
- The genes of the babies’ DNA are randomly mutated (1% of the genes). The babies become adults. The process continues [goto c] until the sentence is found.
- Once the sentence is found, the loop restarts with new monkeys (entirely new DNA) [goto b].
- Once the whole book has been produced, the loop restarts from the beginning to produce another one [goto a].
Added in 2026What was added in 2026?
The program of 2015 ran on a server, day and night, and this site only showed what it wrote. That server is gone. Here is everything 2026 added to bring the monkeys back, and what it left alone.
The program runs in your browser. The C++ code of 2015 is compiled to WebAssembly, a format that browsers run. Your browser gives the program what the server gave it: a folder in which to write its text files. The live page reads those files, as the 2015 page did.
Six lines of code. Four of the five files of 2015 are compiled exactly as written.
Source.cppgains six lines and loses none: two calls to the browser, their two declarations, a comment and a blank line. The first call asks “which line do I type?” The second, before each generation, hands control back to the browser: it shows the best attempt, and waits when the monkeys go too fast. The source code page shows them in green.The pace. A recent laptop runs the program about ten times faster than the server did. The page holds it back to 760 generations per second, the speed measured on the server in March 2016 (630,209 generations in 829 seconds). Each generation is shown as it is computed: nothing is prepared in advance, and nothing knows when a line will be found.
The relay. One Hamlet takes about 26 hours at that pace, and nobody watches that long. So the visitors take turns. A small program in front of this site (a Cloudflare Worker) keeps the troop’s place: the Hamlet it is on, the line it has reached, and how many lines have been typed since the count began. When you open the live page, your browser asks for the line and types it. When your monkeys find it, your browser says so, the count grows by one, and the next line goes to whoever is watching at that moment: you, if you stay. If two visitors watch at the same time, both type the same line, each with their own monkeys, and the first to finish is counted.
When the relay does not answer. The monkeys type alone: your browser goes on with the next line by itself, the page says so, and nothing is counted. It asks again every minute.
What 2026 did not touch: the genetic algorithm, the keyboard and the fingers, the score, and the randomness. As in 2015, the random generator is seeded once, when the program starts. So the monkeys of your browser are yours alone: another visitor’s monkeys type the same line in their own way.
You keep insisting on “randomly,” but is it truly random?
Yes and no.
Yes — In this demonstration, the original book is never in direct contact with the primates. They receive no information about the content of the sentence they have to find. Their sentences are only rated. It is like a game of Hunt the Thimble with scores (.0265, .0444, .25…) instead of verbal hints (“cold, colder, warm, hot, boiling”).
This is a stochastic process (we do not know how many generations will be necessary; we do not determine the content of the DNA; etc.) with a deterministic output.
Randomness is explicitly used (that is, “injected”) three times in the process: to generate the DNA of the monkeys of the first generation; to select half of the monkeys that have sex, in each loop; to mutate the genes, in each loop.
No — This is not true randomness: because this is a computer-based experiment, and because no hardware random number generator is used, it would be more accurate to say pseudorandomness. But this is not a deliberate bias: nothing interferes with the workings of the algorithm’s pseudorandom generator, a Mersenne Twister 19937 (see below), which is a strong one for this context. On this site, “random” therefore means “pseudorandom.”
Because the monkeys are rated, selected and ranked, and their DNA mixed, this is not a canonical implementation of the infinite monkey theorem. Otherwise, it would be impossible to converge towards the book, sentence by sentence. Randomness is channeled. This is the very purpose of genetic algorithms.
Does it really mimic evolution?
Yes and no.
Yes — These creatures have a rudimentary data structure that carries information about how they will evolve and reproduce during their short “life.”
In the early stages, these structures, 840 bits long per creature, are highly diverse: the model allows more than 7 × 10252 different DNA strands.
The creatures that best fit the environment, which is given by the rating and ranking system, are more likely to reproduce.
The DNA of the creatures of the next generation is a mix of both parents’ DNA, and has distinctive features of its own (mutation).
No — In this simulation, as in genetic algorithms in general, creatures do not evolve freely, but towards a goal. I do not believe that such a situation represents a natural process. By creating an artificial evolution, I am not supporting creationism or the pseudoscience of intelligent design.
This experiment is probably more informative from a technical point of view than from a philosophical angle, because the monkeys, and the way they interact with a certain state of their virtual world, remain (and will remain) too simplistic vis-à-vis the real world.
Does it simulate intelligence?
Not at all.
The monkeys are not able, in general, to generate grammatically valid or seemingly meaningful sentences. If they do, it is only by accident or as a result of the evolutionary process. Suppose I had hidden how this website works, and said: “Look! I have created virtual monkeys that are able to understand any book and, after some hesitation, to rewrite it without copying it. They internalize the meaning of each sentence. I will not show you the code, but I will ask an indisputable C++ expert to confirm it.” You might reply: “No way! Monkey see, monkey do!” But because this expert, after taking a look at the source code, would say: “Indeed, there are creatures with no copy/paste function, and they produce the sentences by themselves,” you would probably think that such extraordinary creatures understand the English language (well, I know you are not that naive). If I put my program into a black box, I produce an experiment close to the Chinese Room argument, in order to give the (false) impression that my monkeys are smart.
But they are not, I insist. They have no brain; their only purpose is to type a sequence of keys in the hope of having sex with a random peer—like on a dating app.
In the first version, the title read: “. . . Monkeys Writing . . .” I changed it to “. . . Monkeys Typing . . .” because it seems to me that the act of writing has a different meaning from that of typing. Writing implies comprehending the result of the input, while typing focuses more on the input process. Cf. the hyperbolic “That’s not writing, that’s typing” (Capote on Kerouac).
Is such an experiment a new thing?
No (and yes).
No — Simulating typing monkeys with a genetic algorithm is a classic. Prof. Daniel Shiffman wrote a wonderful chapter on this very subject in The Nature of Code (freely available online). He explains how it works in a video, too:
In 2011, a programmer generated millions of virtual monkeys typing nine-character strings made of the letters a to z (more information). But the current experiment is very different. Here:
- only twenty monkeys go into action: a single computer can run the algorithm;
- almost all the characters available on a standard keyboard are used (uppercase included);
- the book is generated sentence by sentence, in order;
- the monkeys are constrained by their DNA: randomness is channeled, whereas the 2011 experiment was closer to the implementation of a string-searching algorithm (the monkeys generated nine-character strings [e.g. “to be or ”] that were compared with the whole book).
(Shy yes) — My implementation lets people watch the process live, sentence by sentence, with access to detailed information about the monkeys and the sentences they generate.
Are the monkeys able to type any text?
Yes, provided that its lines (lines, not sentences) are no more than 70 characters long and use only characters available on a standard US keyboard. It will work without any modification of the code.
How does it work? (technically)
This is a C++ program. The source code is available online.
Randomness
Engine: std::mt19937. std::uniform_int_distribution<int> randna randomly produces a 0 or a 1 (an int), which is converted to a char ('0', '1') with the formula (int) + '0';
Added in 2026[Update v. 3.0 (2026): the engine is seeded once, when the program starts, from std::random_device: in 2015 that was when the server started, now it is each time the live page is opened. The engine is the same, but the compiler and the C++ library are not, and the C++ standard leaves it to each library how a distribution turns the engine’s output into numbers: from the same seed, the 2015 program would have drawn other numbers.]
DNA
Per monkey: a string of 840 bits (70 genes × 12 bits), initialized to 0 and then randomized.
Genes: 12 bits long. The first 4 bits encode the finger (an int); the next 7 bits encode the condition of the finger (a double, from 0 to 1); the last bit encodes whether the [shift] key is pressed (a bool: 0 [false] or 1 [true]).
Example: 011000010001 is equivalent to 0110 0001000 1, where
0110 => (int) 6 : (6 + 1)th finger, right index 0001000 => (double) .08 : finger very folded 1 => (bool) true : [shift] pressed
Decode function: makes a tuple(int, double, bool) from the substring of a gene. Decoder: std::stoi(genes, nullptr, 2);
Some genes are repressed because they represent an impossible state of the world. Example: a 12th finger.
Fingers
From 0, the left pinky, to 9, the right pinky, with the thumbs side by side, that is:
- left pinky
- left ring
- left middle
- left index
- left thumb
- right thumb
- right index
- right middle
- right ring
- right pinky
Condition of the finger
The closer to the bottom of the keyboard, the closer to 0 (folded finger); the closer to the top of the keyboard (below the function keys), the closer to 1 (straightened finger). This is not a function based on scientific facts: it is a convenient and intuitive way to express the position of a finger above a keyboard and the “effort” needed to reach a key.
0 [folded] -- .5 [half-straightened] -- 1 [fully straightened]
Keyboard
ANSI INCITS 154-1988 (US standard).
All the keys are available, except:
- the function keys ([F1]…);
- [Esc], [Ctrl], [Caps Lock], [Alt];
- the navigation keys ([←], [End]…);
- the numeric keypad (the numbers are available on the alphanumeric keys);
- [Backspace];
- [Enter];
- the Windows key.
Thus, the monkeys use 96 different characters, including [Tab] and the grave accent.
The keyboard is hard-coded. Each finger has access to only a subset of the keyboard, like this.
| Finger | Keys, from the most folded position (rank 0) to the straightest | Width of a position |
|---|---|---|
| 0 left pinky | z a q Tab 1 ` | .167 |
| 1 left ring | x s w 2 | .25 |
| 2 left middle | c d e 3 | .25 |
| 3 left index | b v g f t r 5 4 | .125 |
| 4, 5 thumbs | space (whatever the condition) | – |
| 6 right index | m n j h u y 7 6 | .125 |
| 7 right middle | , k i 8 | .25 |
| 8 right ring | . l o 9 | .25 |
| 9 right pinky | / ' ; \ ] [ p = - 0 | .1 |
The keyboard as the program encodes it (Type.cpp), drawn in 2026 from the code itself: the image of 2015 showed the first lines of that code. Each key has the colour of the only finger that can reach it, and the fingers are numbered above the top row. The small number on a key is its rank among the positions of its finger, from 0 (the most folded). The keys with a dashed outline are not available to the monkeys. [shift] is not pressed by a finger: it is the last bit of each gene.
A finger presses its key of rank k when its condition is at least k times the width given in the table, and less than k + 1 times that width. Beyond its last key, the gene is repressed. With [shift], the same position gives the other character of the key (A for a, ! for 1, and so on).
If an impossible finger (> 9) or position (> 1) is given, it means that there is an anomaly in the gene: it is repressed, and the keyboard returns char(0), that is, null (because no action is performed on it).
Added in 2026[Update v. 3.0 (2026): this is not true of the thumbs. In the code, a thumb presses the space bar whatever its condition, even above 1: the seven bits of a condition, divided by 100, go up to 1.27.]
Evaluation
The sentence generated by each monkey, once its DNA has been decoded and the keys pressed, is compared, char by char, with the original sentence. The two sentences are kept strictly apart: they only come into contact in an rvalue, the computation of the absolute distance between them.
The monkeys’ “intelligence” (a convenient but probably biased way of saying “fitness”) is evaluated as a double:
1 divided by (absolute distance between the generated sentence and the reference sentence + 1)2
This lvalue does not contain any direct information about the content of the reference sentence. Only this double, between 0 and 1.
That’s it.
Selection
The monkeys are ranked according to their intelligence.
Reproduction
Two modes are combined: elite and roulette.
Elite: the best monkey is cloned twice, and its two clones are monkeys 0 and 1 of the next generation. Clone 0’s DNA remains intact in the next generation; clone 1’s DNA can be mutated before the next generation. This may look like a waste, but the best monkey quickly ends up being monkey 0 or monkey 1, so it clones into itself and one other monkey.
Roulette: statistically, the chance that a monkey becomes a breeder is proportional to its intelligence.
Reproduction (50/50 crossover): the baby monkeys (temporary monkeys 20 to 39) receive the first half of their DNA from a breeder, and the second half from a random monkey (std::uniform_int_distribution<int> randomonkey).
[Update v. 2.1: and vice versa. Each couple has two babies. The first baby gets its DNA from parent A and parent B, in that order; the second baby gets its DNA from parent B and parent A, in that order.]
Parent A: 10011 . . . 01010 (selected breeder) Parent B: 00101 . . . 11101 (random monkey) Baby A : 10011 . . . 11101 Baby B : 00101 . . . 01010 < update v. 2.1
Fun facts: the monkeys are neither male nor female (no identified sex), and a monkey can mate with itself. You may think that this is useless, until you realize that the resulting DNA can be mutated.
Mutation
No mutation = no genetic algorithm.
The mutation rate is set at 1%.
For each position of a character in a sentence (length: 70), a random number from 0 (included) to 100 (excluded) is generated (std::uniform_int_distribution<int> randomutation). If this number is strictly less than the mutation rate, the whole gene at this position is mutated at random: the finger can change, the condition of the finger can change, the state of [shift] can change.
Example:
0110 => (int) 6 : (6 + 1)th finger, right index 0001000 => (double) .08 : finger very folded 1 => (bool) true : [shift] pressed
becomes (arbitrary example):
0100 => (int) 4 : (4 + 1)th finger, left thumb 1011101 => (double) .93 : finger very straightened 0 => (bool) false: [shift] NOT pressed
Is it useful?
No. Or perhaps to illustrate the myth of Sisyphus.
Do you simulate primate bones, hand muscles…?
No. Do not expect a VR-ready 3D simulation of the monkeys either. There is nothing beyond the 2D, 44 × 11 px, non-animated fingers on the statistics pages. My monkeys are nothing more than hands and implicit, unidentified genitals.
(Misc.)
What are the numbers next to the sentences, on the statistics page?
These numbers are the “intelligence” (that is, the fitness) of the monkey that produced the sentence, from .000… to 1.
Sometimes, chunks of characters jump to the left or to the right. Why?
As displayed
(0.00000776) MJCH<<Id llklmd kg wxk ickc0 (0.00000935) MJCH<<Id llklmd kg wxk ickc0
Gene by gene
(0.00000776) MJCH<<Id [nothing] llklmd kg wxk ickc0 (0.00000935) MJCH<<Id llklmd kg wxk ickc0
LUCIANUS nephew to the king., with their scores, as the server recorded them in March 2016 (improvements 104 and 105 out of 184; the first 31 of the 70 characters). In the first attempt, gene 11 is repressed (the empty box): it types nothing, so everything after it is displayed one column to the left. In the second, the same gene presses the space bar (the filled box): the highlighted chunk, which will become nephew to the king., jumps one column to the right. The image shown here in 2015 is lost: this example was rebuilt in 2026.Some genes are not expressed (because they represent an impossible finger or an impossible condition of the finger). When a gene is repressed, the keyboard returns “nothing” (char(0), null) because no action is performed on it. Sometimes, a mutation turns a repressed gene into an expressed one. When this new gene means that the hand presses [space] or [tab], a null char is replaced by this space: a jump to the right occurs. And vice versa, when a mutation represses a gene.
Can I ask more questions, or correct you?
Sure!
Feel free to contact me. I may add your (anonymized) question here, along with my answer.