Google+ Pieces o' Eight

Saturday, 24 September 2011

Improving my random password generator in Python

Learning Python is a great programming experience. The immediacy of the environment lends itself perfectly to experimentation, trying out new things and a very iterative approach to coding.

Previously I wrote a random password generator in Python. This worked well, but had a couple of problems. The first, identified at the time, was that there was a slight bias in the algorithm which would return certain characters more often than others. A second problem, identified after some pondering, was the inclusion of some redundant code. That version of the function had three lists and a dictionary - could this be consolidated down to just the dictionary? As it happens... YES!

The typical usage of dictionaries is to pass in a key to obtain a value. However, it's perfectly possible to obtain a key, value or both by supplying an index using a dictionary's .keys(), .values() or .items() methods and supplying the index such as:

phoneticDictionary.items()[15]

This means, of course, that it would be possible to get a randomly generated index from the dictionary, like so:

phoneticDictionary.items()[random.randint(0, 61)]

Knowing this meant I was able to alter my code to get rid of the three lists and use just the dictionary itself. It also got rid of the bias noted earlier.

Here's the complete listing:

import random

def getRandomPassword(length):
    phoneticDictionary = {"A" : "ALPHA",
                          "B" : "BRAVO",
                          "C" : "CHARLIE",
                          "D" : "DELTA",
                          "E" : "ECHO",
                          "F" : "FOXTROT",
                          "G" : "GOLF",
                          "H" : "HOTEL",
                          "I" : "INDIA",
                          "J" : "JULIET",
                          "K" : "KILO",
                          "L" : "LIMA",
                          "M" : "MIKE",
                          "N" : "NOVEMBER",
                          "O" : "OSCAR",
                          "P" : "PAPA",
                          "Q" : "QUEBEC",
                          "R" : "ROMEO",
                          "S" : "SIERRA",
                          "T" : "TANGO",
                          "U" : "UNIFORM",
                          "V" : "VICTOR",
                          "W" : "WHISKEY",
                          "X" : "XRAY",
                          "Y" : "YANKEE",
                          "Z" : "ZULU",
                          "a" : "alpha",
                          "b" : "bravo",
                          "c" : "charlie",
                          "d" : "delta",
                          "e" : "echo",
                          "f" : "foxtrot",
                          "g" : "golf",
                          "h" : "hotel",
                          "i" : "india",
                          "j" : "juliet",
                          "k" : "kilo",
                          "l" : "lima",
                          "m" : "mike",
                          "n" : "november",
                          "o" : "oscar",
                          "p" : "papa",
                          "q" : "quebec",
                          "r" : "romeo",
                          "s" : "sierra",
                          "t" : "tango",
                          "u" : "uniform",
                          "v" : "victor",
                          "w" : "whiskey",
                          "x" : "xray",
                          "y" : "yankee",
                          "z" : "zulu",
                          "0" : "Zero",
                          "1" : "One",
                          "2" : "Two",
                          "3" : "Three",
                          "4" : "Four",
                          "5" : "Five",
                          "6" : "Six",
                          "7" : "Seven",
                          "8" : "Eight",
                          "9" : "Nine"}

    password = []
    phoneticPassword = []                          
    for i in range(length):
        c, pc = phoneticDictionary.items()[random.randint(0, 61)]
        password.append(c)
        phoneticPassword.append(pc)

    return "".join(password), "-".join(phoneticPassword)

And here's the function's output run 10 times specifying a length of 8:

pnReI0lg papa-november-ROMEO-echo-INDIA-Zero-lima-golf
7g7SnNKl Seven-golf-Seven-SIERRA-november-NOVEMBER-KILO-lima
7Q3Zy4Ya Seven-QUEBEC-Three-ZULU-yankee-Four-YANKEE-alpha
697vxMRX Six-Nine-Seven-victor-xray-MIKE-ROMEO-XRAY
R214zUMk ROMEO-Two-One-Four-zulu-UNIFORM-MIKE-kilo
f0db3LbG foxtrot-Zero-delta-bravo-Three-LIMA-bravo-GOLF
IC9046VT INDIA-CHARLIE-Nine-Zero-Four-Six-VICTOR-TANGO
8mg5Vufa Eight-mike-golf-Five-VICTOR-uniform-foxtrot-alpha
C2Puu9dc CHARLIE-Two-PAPA-uniform-uniform-Nine-delta-charlie
tcK6OCsG tango-charlie-KILO-Six-OSCAR-CHARLIE-sierra-GOLF

Space Harrier 32X

Here's a quick video - level 1 of 32x Space Harrier played by me!


A random password generator in Python

For a recent project I needed to create a lot of random passwords. There are plenty of websites out there that can do this for you, but as I'm learning Python I thought I'd have a go at rolling my own solution.

My requirements were that each password be of a specified length and constructed from a random pick of the letters A-Z and a-z and the digits 0-9. I also wanted the function to return a phonetic spelling of each password. Here's what I came up with:


import random

def randomPasswordGenerator(length):
    upperCase = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
    lowerCase = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
    numbers =   ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "3", "5", "2", "4", "6"]
    phoneticDictionary = {"A" : "ALPHA",
                          "B" : "BRAVO",
                          "C" : "CHARLIE",
                          "D" : "DELTA",
                          "E" : "ECHO",
                          "F" : "FOXTROT",
                          "G" : "GOLF",
                          "H" : "HOTEL",
                          "I" : "INDIA",
                          "J" : "JULIET",
                          "K" : "KILO",
                          "L" : "LIMA",
                          "M" : "MIKE",
                          "N" : "NOVEMBER",
                          "O" : "OSCAR",
                          "P" : "PAPA",
                          "Q" : "QUEBEC",
                          "R" : "ROMEO",
                          "S" : "SIERRA",
                          "T" : "TANGO",
                          "U" : "UNIFORM",
                          "V" : "VICTOR",
                          "W" : "WHISKEY",
                          "X" : "XRAY",
                          "Y" : "YANKEE",
                          "Z" : "ZULU",
                          "a" : "alpha",
                          "b" : "bravo",
                          "c" : "charlie",
                          "d" : "delta",
                          "e" : "echo",
                          "f" : "foxtrot",
                          "g" : "golf",
                          "h" : "hotel",
                          "i" : "india",
                          "j" : "juliet",
                          "k" : "kilo",
                          "l" : "lima",
                          "m" : "mike",
                          "n" : "november",
                          "o" : "oscar",
                          "p" : "papa",
                          "q" : "quebec",
                          "r" : "romeo",
                          "s" : "sierra",
                          "t" : "tango",
                          "u" : "uniform",
                          "v" : "victor",
                          "w" : "whiskey",
                          "x" : "xray",
                          "y" : "yankee",
                          "z" : "zulu",
                          "0" : "Zero",
                          "1" : "One",
                          "2" : "Two",
                          "3" : "Three",
                          "4" : "Four",
                          "5" : "Five",
                          "6" : "Six",
                          "7" : "Seven",
                          "8" : "Eight",
                          "9" : "Nine"}
                          
    all = [upperCase, lowerCase, numbers]
    password = []
    phoneticPassword = []
    
    for i in range(length):
        character = all[random.randint(0,2)][random.randint(0,25)]
        password.append(character)
        phoneticPassword.append(phoneticDictionary[character])

    return ''.join(password), '-'.join(phoneticPassword)

It's pretty simple. The function takes a length n and then loops n times randomly picking one of three lists (A-Z, a-z or 0-9) and then picks a random entry from that list.

The chosen character is then appended to the "password" list and also passed to the phonetic dictionary, which returns the phonetic spelling of the character and appends it to the "phoneticPassword" list. Finally the function returns the password and phonetic password by joining the arrays into strings.

Here's the output of the function run 10 times specifying a password length of 8:

FAhFh0fy FOXTROT-ALPHA-hotel-FOXTROT-hotel-Zero-foxtrot-yankee
46Ne3XNu Four-Six-NOVEMBER-echo-Three-XRAY-NOVEMBER-uniform
1PcCnBX2 One-PAPA-charlie-CHARLIE-november-BRAVO-XRAY-Two
qAYVAB75 quebec-ALPHA-YANKEE-VICTOR-ALPHA-BRAVO-Seven-Five
y41Q3w7l yankee-Four-One-QUEBEC-Three-whiskey-Seven-lima
4NW55yYH Four-NOVEMBER-WHISKEY-Five-Five-yankee-YANKEE-HOTEL
bjihtPPk bravo-juliet-india-hotel-tango-PAPA-PAPA-kilo
H56a0Ydf HOTEL-Five-Six-alpha-Zero-YANKEE-delta-foxtrot
KaQkrlk8 KILO-alpha-QUEBEC-kilo-romeo-lima-kilo-Eight
77m302O1 Seven-Seven-mike-Three-Zero-Two-OSCAR-One

You might have noticed that the numeric character list contains some repetition to get the list length up to 26. I did this largely for expediency, but it does create some bias in that the numbers 1-6 have a slightly higher chance of being picked than 0,7-9. I'm not sure if this makes much of a difference, but it's as well to aware that this could be a potential weakness of the algorithm.

Without a doubt you could achieve the same in practically any programming language. What I particularly liked about Python for this, however, was the immediacy of the scripting environment and the built-in methods - such as "join" - which negate having to write tedious boiler-plate code to stitch strings together.

Saturday, 9 April 2011

Fish! (A maths puzzle and a proposed solution)

A fish is made up of three parts: head, tail and body.

The tail is equal in length to the head, plus one-quarter of the length of the body.
The body is equal to three-quarters of the entire length of the fish.
The head is 4cm in length.


How long is the entire fish?

SOLUTION

Let's pose this in the following way:

T = Tail
B = Body
H = Head
L = Total Length

Therefore:
4 + 4 + 1/4 B + 3/4 L = L

Which can be simplified to give:
8 + 1/4B + 3/4L = L

Look also at the relationship between the Tail, Body and Total Length. The body, so we're told, is 3/4 of the Total Length and the fractional part of the tail is 1/4 of the length of the body. This means that we must be able to describe the fractional part of the tail in terms of the Total Length:

1/4 x 3/4 = 3/16

So the fractional part of the tail is 3/16 of the length of the fish!

Now we know that, we can work out what proportion of the fish the fractional part of the tail plus the body is:

3/16 + 3/4 = 3/16 + 12/16 = 15/16

So the fractional part of the tail and the body account for 15/16 of the Total Length, giving us:

8 + 15/16 L = L

What of the remaining 1/16 L? Well given the above, 1/16 L must be equal to 8 which means:

8 x 16 = Total Length = 128

So the fish must be 128cm in length! Lets try it:

1/16 L + 3/16 L + 12/16 L = 1/16 x 128 + 3/16 x 128 + 12/16 x 128 = 8 + 24 + 96 = 128

Sunday, 13 February 2011

The Geek Manifesto

Mark Henderson - science editor of The Times - is writing a book on science and politics called The Geek Manifesto. It sounds like an interesting project in itself, but he's also set up a blog to canvass views, suggestions and other contributions.

You can find his blog here: http://geekmanifesto.wordpress.com/2011/01/14/introducing-the-geek-manifesto/

Five Sci-Fi Classics You Should Own

5 - Dark Star
For a film seemingly produce on a budget of about 50p and a length of string, Dark Star is one of the most influential films of the genre. Without Dark Star there would be no Alien and without Alien where would we be?

Suicidal smart bombs, alien life and a lack of toilet paper - this film has it all.



4 - Tremors
Ok, so Tremors rips the idea of giant worms straight from Dune, but when the result is this good we can let the plagiarism slide. This sci-fi comedy horror pretty much bombed at the box office in 1990, barely breaking even, but performed far better when it was released to video. It's easy to see why - the cast, script and production are superb and it manages to walk the fine line between comedy and horror almost perfectly.



3 - Aliens
Ah, the 80's. Big hair, big shoulder pads and big-budget sci-fi action epics. From start to finish, Aliens is an edge of your seat roller-coaster ride of tension, action, classic quotes you can apply to everyday life and huge explosions. If action sci-fi is your thing, it doesn't get any better than Aliens.

Just don't bother with the third and fourth films in the series.
 


2 - Akira
Some Anime/Manga is just plain weird, being little more than highly-fetishized cartoon pornography appealing to the frankly bizarre Japanese market. Akira isn't like that. The animation - which was all hand drawn - is simply stunning and while the script clearly loses something in translation enough remains to retell the epic story of ESP, government conspiracies and all-out nuclear war.



1 - The Thing
John Carpenter's masterful retelling of the 1951 classic "The Thing from Another World" works on so many levels it almost boggles the mind. From the humour to the suspense to the paranoia, everything is perfectly pitched to pull you in and deliver the sucker punch. The special effects are superb, the acting good (if not Oscar good) and the cinematography epic in scope. This is a film you'll watch again and again.