"Is it Chance?" is a nice small demonstration of evolution. You can download the program: version for Mac OS X, (version for Windows and version for Linux may follow).
I used the ideas from Keith Goodnight, added a few things and also discuss here the algorithm.
I quote from the original goal of Keith Goodnight:
One of the common attacks launched by creationists is the claim that evolution is “mere chance.”
Typically, a creationist will point out how absurd it is that “mere chance” could produce a complex organ or adaptation.
Sometimes the attack will include a probability calculation based on some estimate of the number of mutations required to produce a certain organism from some ancestor, and will show that the odds are so small that the history of the universe is not long enough to expect the “coincidence” to occur.
Is It Chance? is a very simple little program that demonstrates the power of natural selection to accumulate favorable variations is anything but “mere chance.”
The program pits chance against selection in a race to “evolve” a complex target— a sentence entered by the program’s user— from an “ancestor” that is a string of random characters.
Evolution works by weeding out the organisms that are less well adapted to the environment than others. At each generation an organism produces a number of offspring, who are copies of the parent. If they were perfect copies, there would be no evolution. And then if the environment changes sufficiently, the organisms might all die. However, at each generation there is a small number of random mutations. Most of these are useless or even bad, but some will give a slightly better adaptation to the environment.
In this demonstration the well-adapted organism is a piece of text that you can type into the program. It is the "goal" of evolution.
The program tries to construct that well-adapted organism in two ways:
In each generation the offspring is a set of texts (10 by default) that are made up entirely by randomly picking characters. If one of the text strings matches the goal the program stops and the task is done.
In this second case the program starts with a totally random string, like in case 1. However, in each generation all offspring are now copies of the parent (there are again 10 of these). That is the inheritance part: offspring are copies of parents. But again, if they were perfect, we would never get to the goal. The program then makes a small number of mutations to the offspring: a few characters are changed in a totally random fashion.
Now the third aspect of evolution is used: selection. From the offspring a single text is selected, that comes closest to the goal, i.e. that one in which the largest number of charcters match those of the goal. All other offspring are weeded out, and only this best adapted one will be used in the next generation.
On startup the program "Is it Chance?" presents this window:

There is a field in which you can type some text, a start button, a speed slider, and a menu at the top. For the time being we will leave that set at "Simple".
Type some text and press the Start button. After a while you may see something like this:

In this case I typed the text "the quick brown fox", and that is the goal. Below the word "chance" you can see a random text, of which only one letter corresponds to the goal, the red "q". A little lower, below the words "selection and mutation" there is another fairly random text, but many more letters correspond to the goal. That is the text that is the result of several generations of accumulation of good mutations.
There are two other indications: the lenght of the text is 19 characters and the probability to make that text by randomly writing 19 characters in a row is a little over 4.4x10-33, a number so small it is impossible to pronounce.
When you run it you will see that the first process, pure randomness, will not get anywhere although it is not entirely excluded that it stumbles on the goal. The selection and mutation process of evolution will reach the goal in a reasonable time.
Two things you might try:
Now select the "Advanced" option from the top left menu. A few more things show up:

Type a reasonably short text and note how many tries it takes with the mutation rate at its default (10). Then set the mutation rate to the extreme minimum (1) and let it work again on the same text. It needs a lot more time: the chance that a good mutation crops up to bring us nearer to the goal is now much lower.
Then set the mutation rate at its maximum and let it work again on the same text. Note how you can now see that some letters that were already "good" are "destroyed" by mutations. It takes a lot more time now to get to the goal. In fact, if the mutation rate could be set very high, we would be in the situation of the totally random approach!
This illustrates that mutations are needed if successive generations are going to be different so that the best adapted ones can be selected. But if there are too many mutations (such as could happen in radioactive environments) then a lot of offspring is wasted and successive generations cannot accumulate what is good.
In this program the mutations are applied randomly over the offspring. That means some copies may not get any mutation and others may get more than one.
Set the number of offspring to the minimum: it will still get to the goal, but with fewer kids progress is slower. If you do not diminish the mutation rate at the same time, you will get many mutations in each one of the offspring and will not get to the goal again. If you set the number of offspring high you will get to the goal faster because the chances that one of them is closer is now high. In nature too a large number of offspring, even if only one utlimately survives, gives a good chance to keep adapting well to the changing environment.
It does not change. The goal text remains the same. In nature the environment does change, but normally this happens so slowly that organisms have plenty of time to adapt very well to it. We see plants and animals that are "perfectly" adapted to their niche. This is not true: no organism is perfectly adapted, it only looks like that because the changes in the environment are so slow.
Climate change as we are experiencing right now is a very fast change. Because evolution works slowly, many organisms, perhaps including ourselves, may not be able to survive this fast change.
This is the last mode: one more indication shows up, the list of offspring generated at each generation. It looks like this:

You can see that three of the ten offspring in this snapshot are the same, no mutations occurred in them, though some have multiple ones. There is nothing more to try in this mode than in the advanced mode.
The program was written in RunRev Studio. You can download a free version of RunRev. This free version has some limitations but they are not important for reconstructing the program. You can then inspect the full code by downloading the RunRev object and opening it with RunRev Media.
Below is the important part of the code. Note that I omitted all the stuff to do with the user interface, only the central part is listed here.
command Evolve
if the State of me is "Running" then
Generate
send "Evolve" to me in (the endvalue of scrollbar "Speed" - the thumbposition of scrollbar "Speed")*MillisecondsBetweenGenerations milliseconds
end if
end Evolve
command Generate
local Match, NumberMatched, NewRandom
set the caseSensitive to true
add 1 to NumberOfGenerations
-- CHANCE
-- at each step we generate NumberOfOffspring random texts of the length of the user's text
if ByChance["stillgoing"] then
put NumberOfGenerations into field "ChanceTries"
repeat with i=1 to NumberOfOffspring
put empty into NewRandom
repeat LengthUserText times
put char random(nAllowed) of AllowedCharacters after NewRandom
end repeat
put NewRandom into ByChance["tries"][i]
end repeat
-- select the best match:
put BestMatchOf(ByChance["tries"]) into Match
put ByChance["tries"][item BestMatch of Match] into field "ByChance"; ShowMatches "ByChance"
put HighMatch&space
put item HighMatch of Match after msg
put item HighMatch of Match into NumberMatched
if NumberMatched > field "BestChanceMatch" then put NumberMatched into field "BestChanceMatch"
if NumberMatched is LengthUserText then put false into ByChance["stillgoing"]
end if
-- SELECTION WITH MUTATION
-- generate NumberOfOffspring texts derived from the previous evolving text
-- the first time the evolving text is empty so no character matches and all will be random
if BySelection["stillgoing"] then
put NumberOfGenerations into field "SelectionTries"
-- make NumberOfOffspring copies
repeat with i=1 to NumberOfOffspring
put BySelection["evolved"] into BySelection["tries"][i]
end repeat
-- spread the desired number of mutations by randomly mutating one character in a random copy,
-- this will possibly give more than one mutation in some copies and no mutations in others
repeat with i=1 to the thumbposition of scrollbar "MutationRate"
put char random(nAllowed) of AllowedCharacters into char random(LengthUserText) of BySelection["tries"][random(NumberOfOffspring)]
end repeat
-- select the best match:
put BestMatchOf(BySelection["tries"]) into Match
put BySelection["tries"][item BestMatch of Match] into BySelection["evolved"]
put BySelection["evolved"] into field "BySelection"; ShowMatches "BySelection"
put item HighMatch of Match into NumberMatched
if NumberMatched > field "SelectionMatches" then put NumberMatched into field "SelectionMatches"
if NumberMatched is LengthUserText then
put false into BySelection["stillgoing"]
set the SelectMutations of me to the SelectMutations of me & "," & NumberOfGenerations
end if
if the visible of field "Offspring" then -- show the generated offspring
lock screen
put empty into field "Offspring"
repeat with i=1 to NumberOfOffspring
put BySelection["tries"][i] into line i of field "Offspring"
end repeat
set the textcolor of line item BestMatch of Match of field "Offspring" to "red"
unlock screen
end if
end if
end Generate
function BestMatchOf Strings
-- returns the index and the number of matching characters of the
-- string in array Strings that best matches string UserText
local Matches, HighMatchValue, BestMatchValue
set the caseSensitive to true
put 0 into HighMatchValue
repeat with Child=1 to NumberOfOffspring
put 0 into Matches
repeat with j=1 to LengthUserText
if char j of UserText is char j of Strings[Child] then
add 1 to Matches
end if
end repeat
if Matches > HighMatchValue then
put Matches into HighMatchValue
put Child into BestMatchValue
end if
end repeat
-- if none had a match, pick the first one:
if HighMatchValue = 0 then put 1 into BestMatchValue
return BestMatchValue & "," & HighMatchValue
end BestMatchOf
command ShowMatches FieldName
-- mark the matching characters in red
set the caseSensitive to true
repeat with j=1 to LengthUserText
if char j of UserText is char j of field FieldName then
set the textcolor of char j of field FieldName to "red"
end if
end repeat
end ShowMatches