Sunday, 22 March 2015

Change MediaWiki Logo

Once you have your MediaWiki up and running (check out my blog post which explains how to do this,) there are a few things you will want to do. One of the first is to replace the MediaWiki logo, with one of your own. The MediaWiki logo shown even suggests that you do this and drops a hint on how you go about this.



The first thing you need to do it to copy your new logo to the correct place. The logo you want to display should be copied to the location:

/var/lib/mediawiki/skins/common/images/

The logo should be 135 x 135 pixels in size, otherwise you will not see all of it. If it's not square just make sure that the largest number of pixels in x or y is 135. I tend to use .png of .jpg images. Others may work, but I have not tested them!

Once this in place you now have to change your settings file to point to the new logo.

To change the logo it suggests you 'Set $wgLogo to the URL path to your own logo image.'

Most modifications you make within MediaWiki are within the LocalSettings.php file. You will find this in the /var/lib/mediawiki/ folder. That may sound more complex than it is, but don't worry, it really is simple!

To change this file, in the terminal, you need to type

sudo nano /var/lib/mediawiki/LocalSettings.php

For those that don't know.
  • sudo - gives you administrator rights to change the file.
  • nano - is a text editor. There are others you can use but for demonstration purposes I am using nano. 
  • /var/lib/mediawiki/LocalSettings.php - this is the location and name of the file you want to change. The file is LocalSettings.php, which is in location /var/lib/mediawiki/

This will open the LocalSettings.php file for you to edit.

You should see something like this.

<?php
# This file was automatically generated by the MediaWiki 1.19.20+dfsg-0+deb7u3
# installer. If you make manual changes, please keep track in case you
# need to recreate them later.
#
# See includes/DefaultSettings.php for all configurable settings
# and their default values, but don't forget to make changes in _this_
# file, not there.
#
# Further documentation for configuration settings may be found at:
# http://www.mediawiki.org/wiki/Manual:Configuration_settings

# Protect against web entry
if ( !defined( 'MEDIAWIKI' ) ) {
        exit;
}

## Uncomment this to disable output compression

Scroll down to the very bottom of this file using the arrow keys, and you should see the following two lines.

# End of automatically generated settings.
# Add more configuration options below.

This is where you should put your customised option. So below these two lines type in the following.

$wgStylePath = " $wgScriptPath/skins";
$wgLogo = "$wgStylePath/common/images/newLogo.jpg";

You should change newLogo.jpg to the name of your logo.

Now press ctrl-x to exit. You will be asked if you want to 'Save modified buffer', Simply press y and then press return. This should exit from nano having saved your file.

Now when you go to the main screen of your MediaWiki page you will see your new logo.

I have simply used the header block from my blogpage, as you can see below.




There you go, you have completed the first step to customising your MediaWiki page. A big improvement over the standard logo!


Tuesday, 3 March 2015

Solving the Monty Hall Problem with Python.

A while ago I stumbled across a problem which was referred to as the Monty Hall Problem. A problem which at first sight seems really simple.



It refers to a puzzle loosely based on the American television game show called 'Lets Make a Deal' hosted originally by Monty Hall.

The host Monty Hall shows you three doors, and asks you to pick one.

Behind one of these doors is the car of your dreams.
Behind the other two is a goat.

Now Monty hall asks you to pick a door, which you do.
You will win whatever is behind that door.
Happy with your choice?
Now comes the difficult decision. Monty Hall asks would you like to change the door you have chosen?
To help you, Monty Hall opens one of the other doors to reveal a goat. He never reveals the car.
Do you swap doors?

Surely you have now gone from a 1 in 3 chance of winning a Car, to a 1 in 2?
Or have you?
Does it matter if you swap?

What do you all think?

This problem became famous when a reader wrote in to Parade magazines ‘Ask Marilyn’ section in 1990. Marilyn Vos Savant answered the question correctly. However 10,000 people replied to her answer, the majority claiming she was wrong.

Her claim is you should always swap, as you improve your chances of winning a car from 1/3 to 2/3.

My statistics are not good enough to argue conclusively if Marilyn was right or not. However I decided to simulate the game in Python to prove once and for all if you should always swap doors!

Let us first have a think about what our program needs to do.
  • We need to set up a game with three doors. Each door needs either a goat or a car behind it. There should only be one car. 
  • We then need to simulate Monty Hall revealing one of the other doors. To make our program simpler we will assume we are always opening door one. If the position of the goats and car are random then it doesn't matter which door we initially chose. 
  • We need to be able to swap from our original choice when Monty Hall offers the swap.
  • We need to simulate many games where we do not swap our choice and check what the outcome is. 
  • Then we need to do the same but we swap when offered by Monty Hall, and then check what the outcome is. 
  • Finally we print the outcomes. 

Here is my code to solve the problem. Have a read through it and see what you understand. Then I will break this down and explain it line by line.

#Monty Hall Problem

from __future__ import print_function #Allows python3 use of print()
import random

#Variables used through out the program 
noSwap = 0
swap = 0
winCountNoSwap = 0
loseCountNoSwap = 0
winCountSwap = 0
loseCountSwap = 0
numberOfTests = 1000000 #Alter this to change the number of simulations

##Function to set up the game. 
##Returns list with three items. 1 Car and 2 Goats randomly positioned. 
def setUpGame():

    number = random.randint(0,2) #random number 0,1 or 2
    blankDoors = [0,0,0] #sets up a new game
    count = 0 
    for item in blankDoors:
        if count == number:
            blankDoors[count] = 'Car'
        else: 
            blankDoors[count] = 'Goat'
        count += 1

    return blankDoors

##Function to simulate Monty Hall revealing a goat. 
##Assumes contestant has door one.
##Reveals only a Goat in either door 2 or 3.  
def reveal(currentGame):
    randomReveal = random.randint(1,2)
    if currentGame[randomReveal] == 'Car':
        if randomReveal == 1:
            randomReveal = 2
        else:
            randomReveal = 1
        currentGame[randomReveal] = 'Reveal'
    else:
        currentGame[randomReveal] = 'Reveal'

    return currentGame

##Simulates the player swapping doors. 
##Ensures they do not pick the 'Reveal' door.    
def swapOption(currentGame):
    temp = currentGame[0]
    if currentGame[1] == 'Reveal':
        currentGame[0] = currentGame[2]
        currentGame[2] = temp
    else:
        currentGame[0] = currentGame[1]
        currentGame[1] = temp
        
    return currentGame
        
##Runs through the game without swapping the door chosen.
while noSwap < numberOfTests:
    currentGame = setUpGame()
    #print (currentGame)
    currentGame = reveal(currentGame)
    #print (currentGame)
    if currentGame[0] == 'Car':
        winCountNoSwap += 1
    else: 
        loseCountNoSwap += 1
    noSwap +=1

##Runs through the game swapping the door chosen.
while swap < numberOfTests:
    currentGame = setUpGame()
    #print (currentGame)
    currentGame = reveal(currentGame)
    #print (currentGame)
    currentGame = swapOption(currentGame)
    #print (currentGame)
    if currentGame[0] == 'Car':
        winCountSwap += 1
    else: 
        loseCountSwap += 1
    swap +=1

##Calculates percentage of winning for each of the options and prints the result.
print ("Without swapping you win" ,float(winCountNoSwap) / (float(winCountNoSwap) + float(loseCountNoSwap))*100, "% of the time.")
print ("With swapping you win" ,float(winCountSwap) / (float(winCountSwap) + float(loseCountSwap))*100, "% of the time.")
    


The first line is simply a comment to state what the program is doing. Anything preceded by a # is ignored by the program.

#Monty Hall Problem

Next is a line I have started to use recently, as I think more about moving over to Python 3. This means I can use the same print functions in my program as used in Python 3.

from __future__ import print_function #Allows python3 use of print()

I will be calling some random numbers, so I need to import the random library.

import random

Now we create a few variables which we will use later in the program. At this stage we will just create them, and will discuss where they are used later in the blog.

#Variables used through out the program 
noSwap = 0
swap = 0
winCountNoSwap = 0
loseCountNoSwap = 0
winCountSwap = 0
loseCountSwap = 0
numberOfTests = 1000000 #Alter this to change the number of simulations

Now the first thing we said we would do was to set up a blank game, with three doors. Two doors should have a goat behind them, and one a car. These should be randomly selected.

As setting up a blank game is something we will have to do before each of the simulations we run, I have put this code in a function to allow me to call it many times. The function in its entirety is here, afterwards we will run through it line by line.

##Function to set up the game. 
##Returns list with three items. 1 Car and 2 Goats randomly positioned. 
def setUpGame():

    number = random.randint(0,2) #random number 0,1 or 2
    blankDoors = [0,0,0] #sets up a new game
    count = 0 
    for item in blankDoors:
        if count == number:
            blankDoors[count] = 'Car'
        else: 
            blankDoors[count] = 'Goat'
        count += 1

    return blankDoors

The first line sets the function name, and as the brackets are empty explains we are not sending any variables into the function.

def setUpGame():

Now we know we want a car behind one door and a goat behind two. Therefore if we create a list holding the three things, one of these will be a car.

Lets generate a number from 0 - 2 to decide which item in the list will be the car. You might be asking why not a number from 1-3, as there are three doors? Well lists in Python, along with most other languages, have the first item in position 0. So door 1 is at position 0 in the list. Therefore our random number needs to be a 0, 1 or a 2.

    number = random.randint(0,2) #random number 0,1 or 2

Now we will create a list with three items in it, for now these are all set to 0.

    blankDoors = [0,0,0] #sets up a new game

We want to assign either goat or car to each of the items in the list. So, as we iterate through the list, lets keep count of where we are up to. If our count is equal to the random number we calculated, which covers only one of the locations in the list, then that should be the car, otherwise a goat should be assigned to the slot.

So first make a count variable. As we iterate through the list this keeps track of the position in the list we are up to, either a 0, 1 or 2.

    count = 0 


This next line iterates through each of the items in the list one at a time.

    for item in blankDoors:


We want to ensure if the count is equal to the random number we generated, this item in the list should be assigned as the car. First the check to see if the count is equal to the random number we generated earlier.

        if count == number:


If the count is equal to the number, then this position in the list should be turned into Car.

            blankDoors[count] = 'Car'


If it isn't, then it should become a Goat.

        else: 
            blankDoors[count] = 'Goat'


Well we have now done everything we want to with that item in the list, so all that remains is we update the count ready to match the next items position in the list we are going to be looking at.

        count += 1


Notice to increase the count by one we use += 1. We could say count = count + 1, but as this is done often in Python there is a shortcut method of typing this as count += 1. If we wanted to remove 1 from count we could say count -= 1.

Finally once we have finished iterating thorough the list, we want to return our now populated list back to the main program. We do this with

    return blankDoors


So now if we call this setUpGame() function, we will be returned a blank game. Perfect.

The next thing on our list was to simulate Monty Hall revealing a goat in one of the doors the contestant has not chosen.

For simplicity we are going to assume the contestant always chooses door 1. As the Goats and Cars are assigned randomly it really doesn't matter which door we say the contestant has chosen. This just makes our code easier for the simulations.

As we will want Monty Hall to reveal a goat in all our games, I have written this part as a function, so we can easily call it as many times as we want.

Here is the overall function, then we will break it down to see what it does.

##Function to simulate Monty Hall revealing a goat. 
##Assumes contestant has door one.
##Reveals only a Goat in either door 2 or 3.  
def reveal(currentGame):
    randomReveal = random.randint(1,2)
    if currentGame[randomReveal] == 'Car':
        if randomReveal == 1:
            randomReveal = 2
        else:
            randomReveal = 1
        currentGame[randomReveal] = 'Reveal'
    else:
        currentGame[randomReveal] = 'Reveal'

    return currentGame


First of all we set the name of the function. You can see we are passing the currentGame into it. This means the function has access to currentGame, and can make any modifications required.

def reveal(currentGame):


In the next line we create a random number which is either a 1 or a 2. We have stated that the contestant will always choose door 1, which is in position 0 in the list. We we want to ensure Monty Hall reveals either door 2 or 3, which are held in the list in position 1 or 2.

    randomReveal = random.randint(1,2)

We only want Monty Hall to reveal a goat. The next five lines look into if the random number matches a door which is hiding the car, which is a scenario we don't want. If this happens we get Monty Hall to switch the door he is about to reveal.

First of all we look to see if the random number (stored in randomReveal) we have just created matches the location of the car.

    if currentGame[randomReveal] == 'Car':


If it is a car behind the random door we want Monty Hall to reveal the other door. Therefore if he was going to reveal door 2 and this is a Car we want him to reveal door 3 which will be a goat and vice versa. The next few lines simply switch the randomReveal number to select the other position in the list. This is done by having if and else statements indented within the if statement above.

        if randomReveal == 1:
            randomReveal = 2
        else:
            randomReveal = 1


Notice that the else covers all other eventualities. In this case if randomReveal is not 1, it must be 2, in which case we want to set randomReveal to 1.

Now so we know that door has been revealed let us change what is behind the door to say Reveal instead of Goat.

        currentGame[randomReveal] = 'Reveal'


All that was to deal with the fact the Monty Hall was going to reveal a Car. If the randomReveal number was going to cause Monty Hall to reveal a goat, then thats ok. We will simply turn the goat behind that door into Reveal. Note that this else statement is at the same indentation level as the first if statement in the function. It is really important that you get the indentation right, as your whole program can change if it is wrong!

    else:
        currentGame[randomReveal] = 'Reveal'


Finally we return the modified version of current game which has one of the doors revealed.

    return currentGame


The next thing we said we had to do was to get the player to swap doors. Now this is not something which they player needs to do every-time, as we want to compare swapping with not swapping doors. But we do want our program to have the ability to simulate the player swapping doors when Monty Hall gives us the option.

Again this is something we will need to do often in our simulation, so it is written in a function.

##Simulates the player swapping doors. 
##Ensures they do not pick the 'Reveal' door.    
def swapOption(currentGame):
    temp = currentGame[0]
    if currentGame[1] == 'Reveal':
        currentGame[0] = currentGame[2]
        currentGame[2] = temp
    else:
        currentGame[0] = currentGame[1]
        currentGame[1] = temp
        
    return currentGame

The first line defines the function name and explains we are passing currentGame into the function.

def swapOption(currentGame):


The way we will do the swap may be a little different than you think. However it is to make our program a little easier. Rather than swap doors we have chosen, we will simply swap what is behind the doors. So the contestants door will still remain door 1, but we will swap what was behind door 1 with whatever is behind the door which Monty Hall has not revealed to us.

The first thing we will do is to store what is behind the contestants door in a temporary variable called temp.

    temp = currentGame[0]


We will use this to replace what is behind the door Monty Hall has not revealed in a minute or two.

What we are trying to do is choose which door has not been revealed to be a goat by Monty Hall, and switch that one with the contestants door, which is door 1. We first check to see if door 2 (stored in position 1 in the list remember) is Reveal

    if currentGame[1] == 'Reveal':

It is is, we want to swap what is behind door 3 (stored in the list in position 2) with what is behind the contestants door. This line takes what was behind door three and puts it in the position of the contestants door.

        currentGame[0] = currentGame[2]


Now we need to take what was behind the contestants door and put this  behind door 3. Hold on a second! We have just over written what was behind door 1. Luckily we made a copy by storing a copy in temp. So we simply copy what is in temp to the position in the list which is storing what is behind door 3.

        currentGame[2] = temp


We know Monty Hall has revealed either door 2 or door 3. Therefore if Door 2 is not 'Reveal' he must have revealed door 3. We use an else statement to deal with this scenario and then swap what is behind door 2 (position 1 in the list) with door 1 (position 0 in the list), using the same method as above.

    else:
        currentGame[0] = currentGame[1]
        currentGame[1] = temp


Finally we return the values in currentGame which now reflect the player accepting the swap.

    return currentGame


Now we enter a while loop to run through a simulation of how many times you will win or lose if you do not swap doors when offered by Monty Hall.

The first thing we do is start the while loop. We are going to need to use a few of those variables we created at the top of our program at this point. The whole of the while loop looks like this.

##Runs through the game without swapping the door chosen.
while noSwap < numberOfTests:
    currentGame = setUpGame()
    #print (currentGame)
    currentGame = reveal(currentGame)
    #print (currentGame)
    if currentGame[0] == 'Car':
        winCountNoSwap += 1
    else: 
        loseCountNoSwap += 1
    noSwap +=1


The first line states that while noSwap is less than the numberOfTests the loop should keep going. This ensures that we run the tests as many times as stated in the numberOfTests variable. We could say while noSwap < 1000000: However in a few months time, it would be hard to remember what the 1000000 was used for. It is also harder to find it in the body of the program rather than at the top. We would also have to change it in a couple of locations.

while noSwap < numberOfTests:


The next thing we do is call our setUpGame function and store the result in currentGame.

    currentGame = setUpGame()


There are some print statements in this while loop which I have commented out. I have left these in there to show you that when debugging I will often print the outputs out to ensure they are working as expected. However this slows the simulation, so I comment them out when running a real simulation.

Monty Hall then wants to reveal a door which has a goat, and ask if you want to swap. We will have Monty Hall reveal the goat, but in this simulation you are not swapping.

    currentGame = reveal(currentGame)

Now we start to check if the contestant has won. We know they will have won if what is behind their door is a car, unless of course they always wanted a goat! We have ensured that the contestants door is always door 1. And rather than swapping doors, we swapped what was behind the doors. As the item in position 0 in our list represents what is behind door 1 we can easily check if this is a car.

    if currentGame[0] == 'Car':

If it is the contestant has won! We will use another of those variables we created at the start to keep track of how many times the contestant has won

        winCountNoSwap += 1

If they have not won then we keep track of the losses as well.

    else: 
        loseCountNoSwap += 1


Finally we need to increase our count of how many simulations we have done otherwise our while loop will run forever.

    noSwap +=1

Well that was the simulation for if we do not want to swap when offered by Monty Hall. We now do something similar for the option when we do want to swap when offered. Again we do this in a while loop.

##Runs through the game swapping the door chosen.
while swap < numberOfTests:
    currentGame = setUpGame()
    #print (currentGame)
    currentGame = reveal(currentGame)
    #print (currentGame)
    currentGame = swapOption(currentGame)
    #print (currentGame)
    if currentGame[0] == 'Car':
        winCountSwap += 1
    else: 
        loseCountSwap += 1
    swap +=1

This while loop is incredibly similar apart from two things.

The variables have different names to reflect the fact that we are swapping. This means we don’t write over the information created in the previous while loop.

We have an extra line in there to call the function which carries out the swap, to make the swap when offered. We wrote this function earlier. This line is.

    currentGame = swapOption(currentGame)

Now we have all the data which we need to work out which is the better option, all we need to do it to calculate it and print it. We do that in the next two lines.

##Calculates percentage of winning for each of the options and prints the result.
print ("Without swapping you win" ,float(winCountNoSwap) / (float(winCountNoSwap) + float(loseCountNoSwap))*100, "% of the time.")
print ("With swapping you win" ,float(winCountSwap) / (float(winCountSwap) + float(loseCountSwap))*100, "% of the time.")

These lines print some text first of all, saying “Without/With swapping you win.”
They then use the results we have gathered to calculate the percentage of winning.

Using this equation

         Wins              x 100%
Wins + Losses                    

(Wins + Losses) is used to add up the total of simulations done.

But what is float for? Well in programming numbers can be stored as different things. All our numbers are stored as int which is short for integer. An integer is a whole number. However in Python if you do any maths on an int, the result will be an int also. Before we multiply our answer by 100 to get a percentage we will have a number less that 1, this will be rounded down to 0. Which is no good to use. To change our numbers to floating point, using float, ensures have decimal points. Carrying out maths on values which are floats will give us the answer as a float.

The final part of each line is to finish off the text with ‘% of the time.’

If you are interested in the results from this program, I can provide some below. I ran this program with the number of samples set to 1,000,000,000. Yes you read that correctly. I simulated 1 Billion game shows! Which really did not take long! The results are:

Without swapping you win 33.3321941 % of the time.
With swapping you win 66.6647868 % of the time.

I hope you have enjoyed this blog post. What I learned from writing it is this is a fairly complex problem to think about, and it has fooled many people, including some top mathematicians. Although I would struggle to prove the answer from a mathematical point of view, this was a simple thing to solve in Python.

Tuesday, 10 February 2015

Check downloads using SHA-1 and MD5

When you download a large file, such as a distribution of Linux for the Raspberry Pi, you are provided with a checksum to check the download is all correct. Has anyone ever checked their download? Would you know how to? I have to admit I rarely check. However if things did go wrong it would be very easy to overlook the fact the download went wrong. As you will see in this blog it is also possible to use this tool to check that SD cards have been written to correctly.

There are two types of checksum which are commonly used SHA-1 and MD5. I will explain how to use both of these.

First lets look how to do this on an Apple Mac.

To determine the MD5 open the terminal and type either

openssl md5 filename

or for SHA-1

openssl sha1 filename

for the MD5 you don't need to type openssl.

On a Linux system type the following into a terminal.

md5sum filename

and for SHA-1 you need to type

sha1sum filename

depending which checksum you are wanting to use.

Don't forget, if your filename is in a different folder, you will have to include the location along with the filename as below

location/of/folder/filename

Did you know that you are able to check that the image has burned correctly onto say an SD Card by checking the card once you have burned it?

For example on an Apple Mac to check a disk type the following

sudo openssl sha1 /dev/rdisk2

where /dev/rdisk2 is the path to the disk you want to check. Note you will probably need to use the sudo command to ensure you have the correct permissions. This is handy if you want to check that all your disks have burned correctly.


Saturday, 1 November 2014

Sending Email using Python

I often see people asking the question how do you send Email using Python?
Well a few years ago I had the idea to write a program, which would automatically send an Email should a certain event happen. I have been meaning to include the Email code in a blog post, but have never managed to get around to it.

Until now...

So here is the code I used. I know it works with Gmail, but have not tested it with other providers, although I am sure a little modification would make it work.

Remember this program requires you to store your Email password in plain text, something you need to be aware of!

Just ensure you add your username and password where necessary, and change the other fields as required.


#!/usr/bin/python
import smtplib

SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
GMAIL_USERNAME = 'your_username@gmail.com'
GMAIL_PASSWORD = 'your_gmail_password' #CAUTION: This is stored in plain text!

recipient = 'recipient@email_address.com'
subject = 'Email Subject'
emailText = 'This is the content of the e-mail.'

emailText = "" + emailText + ""

headers = ["From: " + GMAIL_USERNAME,
           "Subject: " + subject,
           "To: " + recipient,
           "MIME-Version: 1.0",
           "Content-Type: text/html"]
headers = "\r\n".join(headers)

session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)

session.ehlo()
session.starttls()
session.ehlo

session.login(GMAIL_USERNAME, GMAIL_PASSWORD)

session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + emailText)
session.quit()

Tuesday, 21 October 2014

Infinite Monkey Theorem using Python

They say that if you sat an infinite number of monkeys with an infinite number of typewriters, then they would write the complete works of Shakespeare. This is known as the Infinite Monkey Theorem. I always feel it would be nice to try the actual experiment out. I mean all these monkeys with typewriters would be kinda cool.



However wouldn't it be easier to get one monkey and one typewriter and give him an infinite amount of time to see how he goes?

Although in theory it sounds simpler, getting hold of even a single monkey is not that easy.

But what if we created a simulated monkey in Python? Now we are talking! That would be easy, and unlike a real monkey our simulated one could work all day and all night. No food required.

Sounds like a plan for a blog post.

However I want to give our virtual monkey a chance. If he managed to type the complete works of Shakespeare without worrying about punctuation, we would be happy right? Same goes for capital letters, let's just ignore them for now. We want to give him a fighting chance of completing his task.

To help you get started I have taken a text file of the complete works of Shakespeare, and removed all punctuation and made all letters small. If any of you are thinking I did that by hand, think again. Python is your friend for automating tasks like that.

Because the complete works is a large tome, I have also included a similar file, with just Hamlet. You can choose which one you want your monkey to attempt!

As with all my blog posts I will give you the complete program first of all. Have a read through this and see how much of it you understand. Try and figure out those sections you don’t. I will then go through the program a line at a time explaining it in more detail.

import random
import string

def typeShakespeare(scriptRead):
    monkeyTyped = ''
    while monkeyTyped == '' or scriptRead.count(monkeyTyped) >= 1:
        monkeyTyped = monkeyTyped + (random.choice(string.ascii_lowercase + ' '))
            
    else:
        return (monkeyTyped[:-1])

script = open('Shakespeare.txt','r') # opens the files
scriptRead = script.read()
script.close()

keyPresses = 0
monkeyTyped = ''
while len(monkeyTyped) != len(scriptRead): ## infinite loop ... unless the monkey does it!

    monkeyTyped = typeShakespeare(scriptRead)
    keyPresses = keyPresses + len(monkeyTyped) + 1
    
    if len(monkeyTyped) >=5:
        monkeyTyped = "'"+monkeyTyped+"'"
        print monkeyTyped, keyPresses
    if keyPresses%10000==0:
        print keyPresses

The first thing we do is import a couple of libraries we will use. We want our monkey to type some random letters, so we will call on the random library. We will also be needing strings (many letters joined together) so we should import the string library as well.

import random
import string

There is now a function called typeShakespeare(). It will make sense to explain this when we call it, so lets skip it for now.

The aim of the program is to work out if the monkey has managed to type the complete works of Shakespeare, or Hamlet, if thats what you prefer. To do this we need to judge his effort against the finished script. Therefore we will open the file with the completed text.

script = open('Shakespeare.txt','r') # opens the files

Change this to read Hamlet.txt if you want to use Hamlet instead.

We then store the text into a variable called scriptRead. To do this we use the .read() command on the script we have opened. Finally as we have the data stored in memory we will close the script.

scriptRead = script.read()
script.close()

I have now created a variable called keyPresses and set this to 0. There are two reasons for this. When he has typed a word worth reporting I want to know how many key presses it took before he got there. I also want to keep an eye on my monkey, to make sure he is working. Therefore every time he has pressed a key a set number of times I will report back.

keyPresses = 0

We also need to know what the monkey has typed and to keep an eye on that. Every-time he types a letter we will check he is on the right path. If he isn't, we will get him to start from scratch. We will create a blank string to store his effort in.

monkeyTyped = ''

Now we enter into our main loop which is a while loop.

We want the monkey to keep typing until he has finished the job. If he hasn't then we will make him keep going. The first line of our while loop checks to see if what is stored in monkeyTyped is as long as the file we are looking into him typing. As we are checking the monkey is on the right track every letter, should he type something the length of the complete works of Shakespeare, then we will know he has achieved his goal.

while len(monkeyTyped) != len(scriptRead): ## infinite loop ... unless the monkey does it!

Now we call the function typeShakespeare we skipped over earlier and we store the result into monkeyTyped.

    monkeyTyped = typeShakespeare(scriptRead)

I think it would be a good time to now go and write that function. It is in this function that the monkey does most of his work. He tries to type the complete works of Shakespeare. We will check his work every time he presses a key. If he is on the right track, we will let him continue. If what he has typed is not in Shakespeare, we will return his best efforts to our main program.

So directly below import string we should type

def typeShakespeare(scriptRead):

This defines our function and tells us we are passing scriptRead into it.

As I mentioned we are going to be in this function while the monkey types something. The first thing we need to do is to set monkeyTyped to = ''

    monkeyTyped = ''

Now we enter a new while loop. This one needs to keep looping while the monkey has typed something which appears in Shakespeare.

    while monkeyTyped == '' or scriptRead.count(monkeyTyped) >= 1:

We do this by using scriptRead.count(monkeyTyped) >= 1 What does that even mean? Well we take the complete works of Shakespeare stored in scriptRead, and we do a count of how many times the thing in the brackets appears. If we put monkeyTyped into the brackets then it will count how many times monkeyCount appeared in scriptRead. We only need it to appear once but if it appears more than once, then that is ok as well. We check this with the greater than or equal to symbol >=.

But the line also has monkeyTyped = ''. Why is that? Well when we start off this while loop the monkey has not typed anything, as we have set the variable to = '' , which means an empty string. This would mean our while loop would be false straight away, and our monkey would never start typing.

To get around this we us an or condition. We check that monkeyTyped is '' or scriptRead.count(monkeyTyped) >= 1

The next line is the line which does the actual typing.

monkeyTyped = monkeyTyped + (random.choice(string.ascii_lowercase + ' '))

We take monkeyTyped and we add the result of (random.choice(string.ascii_lowercase + ' ')) onto it and save the result as monkeyTyped.

What on earth is (random.choice(string.ascii_lowercase + ' ')) ?

Well we want to simulate the monkey typing on a keyboard. We have already said to make it easy we will not ask for punctuation, although we should ask him for a space between words. Thats not too much to ask is it? We also said we will not be too concerned about it being in capital letters.

So random.choice picks something from inside the brackets by random selection. So what have we put in the brackets. The first thing is

string.ascii_lowercase

This creates a string of the lower case ascii letters. i.e

abcdefghijklmnopqrstuvwxyz

We also add onto the end of that a space using ' '

Now remember this has a space between the two speech-marks. This is different from when we are creating a blank string, which doesn't have a space.

Once he has typed a word, the loop will start again and check if what has been typed is in the complete works. If it is he will continue. If not he will go to the else statement.

    else:
        return (monkeyTyped[:-1]

Here we return what he has typed. However remember we only get to this place if what is typed is not in the complete works. That's no use to us! We will need to remove the last letter of what he typed, as it was that last letter we know to have made perfect Shakespeare prose into gibberish.

So we return monkeyTyped[:-1] which returns everything up to the last letter but not the last letter.

Ok back to where we were in the main program.

Remember we said we would keep track of the number of key presses? Well lets update that now. We know the monkey has just typed a word, so it is easy to determine the size of that word and increase keyPresses by that amount. Oh but the monkey typed a letter which turned his prose into gibberish. We should add that on as well as we want our count to be accurate!

    keyPresses = keyPresses + len(monkeyTyped) + 1

Whats the point of doing something if no one knows about it? Mmmmm... this blog post is perhaps not the best place to get into a philosophical debate. We want our monkey to report back if he has typed some Shakespeare. However we don't want him reporting back if he has just typed one letter do we?  No one likes a show off!

We only want to be informed if the length of what he has typed is greater than 5, although you can vary this depending on how much chat you want with your monkey.

    if len(monkeyTyped) >=5:

As we are reporting the monkeys best effort in that round of typing, and his efforts are going to be set back to the beginning, it doesn't matter if we play around with our monkeyTyped variable to help make his reporting a little nicer. Lets first of all add speech marks onto his typing, so we can see what he has typed.

        monkeyTyped = "'"+monkeyTyped+"'"

Pay careful attention to those speech marks in there. Each side is a single quote ' surrounded by double quotes "

Now we will print what the monkey has typed, and the number of keyPresses he has made in total so far.

        print monkeyTyped, keyPresses

Finally if you are only checking for big words the monkey may be away working some time before he gets to report back. I think its wise to check in on him every so often.

    if keyPresses%10000==0:
        print keyPresses

This line checks to see if the number of key presses he has made is a multiple of 10,000. The % checks if keyPresses / 10,000 has no remainder i.e. it is a multiple of 10,000. If it is then it will print the number of key-presses made. This only works if the key-presses are an exact multiple of 10,000. There will be times when the monkey is in the middle of a word when this happen, so it will not report back. However it reports enough to make you realise the monkey is still working and not fallen asleep.

Remember to press F5 to save and run your program.

That is the end of the program. All you need now it to download the complete works of Shakespeare or just Hamlet if thats what you want to use. Use the links below to do that.

Download complete works of Shakespeare

Download Hamlet

Well I hope you have enjoyed this simple program, and that it helped you learn a little bit of Python! Good luck to all your Monkeys typing away, let me know how they get on!