Categories
Python

Coding Richard Dawkins’ ‘Me Thinks It is a Like a Weasel’ in Python

https://www.youtube.com/watch?v=WekRrOXZWvk
#!/usr/bin/env python3
import random
import string

TARGET = ''
TARGET_LEN = 0
LETTERS = string.ascii_uppercase + ' ' + string.punctuation
GENERATIONS = 100
GENERATION_POPULATION = 100

allGenerations = []

bestString = {
    'string': '',
    'base_for_new_generation': '',
    'score': 0
}

def randomString(stringLength):
    return ''.join(random.choice(LETTERS) for i in range(stringLength));

def replaceNoneMatchesWithRandomChar():
    tempString = bestString['base_for_new_generation']
    for i, letter in enumerate(tempString):
        if letter == '*':
            tempString = switchChar(tempString, i, random.choice(LETTERS))
    return tempString

def switchChar(string, index, rand_char):
    return string[:index]+rand_char+string[index+1:]

def createNewGeneration():
    constructNewBaseForGeneration(bestString['string'])
    allGenerations.append([replaceNoneMatchesWithRandomChar() for _ in range(GENERATION_POPULATION)])

def constructNewBaseForGeneration(bestMatch):
    base_for_new_generation = ''
    for i in range(TARGET_LEN):
        if TARGET[i] == bestMatch[i]:
            base_for_new_generation = base_for_new_generation + bestString['string'][i]
        else:
            # No match so replace with '*' to make replacing with random char easier
            # This enables us to create x number of strings based on the same parent
            base_for_new_generation = base_for_new_generation + '*'
    bestString['base_for_new_generation'] = base_for_new_generation

def scoreString(string):
    score = 0
    for i in range(TARGET_LEN):
        if TARGET[i] == string[i]:
            score = score + 1
    return score

def updateBestString(string, score):
    bestString['string'] = string
    bestString['score'] = score


def checkMatch():
    latest_generation = allGenerations[-1]
    for string in latest_generation:
        score = scoreString(string)
        if score > bestString['score']:
            updateBestString(string, score)

def createInitialStrings():
    allGenerations.append([randomString(TARGET_LEN) for _ in range(GENERATION_POPULATION)])

def printBestString():
    print('Generation ' + str(len(allGenerations)))
    print('Current best string ' + bestString['string'])


def monkeys(target):
    global TARGET 
    TARGET = target
    global TARGET_LEN 
    TARGET_LEN = len(TARGET)
    createInitialStrings()
    checkMatch()
    printBestString()
    for i in range(GENERATIONS):
        if bestString['string'] == TARGET:
            printBestString()
            print('Script Complete Matched in ' + str(len(allGenerations)) + ' generations')
            return len(allGenerations)
        createNewGeneration()
        checkMatch()
        printBestString()


if __name__ == '__main__':
    monkeys(input('Enter a string for the monkeys to type: ').upper())