Thursday, October 13, 2011

Hippocampal Anatomy Game, Take 2


I refactored the code from the Hippocampal Anatomy game I made a little while ago. After incorporating lists, dictionaries, and throwing in module, I was able to cut down the code by 36 lines!

Some major topics I learned from this part of the project:

1) Mutable Objects -- I'm still trying to wrap my head around the concept of mutable objects, i.e. objects whose value can change. I found it difficult to remember to apply the concept that I can modify a list, for example, after it's been created. And so it took some playing around with to really start understanding this.

2) Approximate string matching (aka fuzzy string searching) & the Levenshtein distance -- I asked a good friend if there was an easier way to accept variations of inputs, like for "hippocampal region CA3," "hippocapal region ca3" or "hippocampal regin ca3" and so on would be an acceptable response. He directed me toward fuzzy string searching and the Levenshtein package.

The Levenshtein distance can calculate string similarities and is one application of approximate string matching, which is a way to find strings that approximately match a pattern. This was my first foray into installing and using an external library. While working on this for quite some time, I had the realization that, "Oh my god, there must be tons of packages out there." And as one would expect, my mind was blown with all the possibilities.

3) randint -- A friend suggested that I use random numbers to vary the messages passed to dead(). This ended up being a useful challenge, so I appreciate the recommendation (see line 24).

Pending Question:
-- I'm still a little confused about the functional differences between modules, libraries, and packages.

Oh and while I was working on improving the game, my first version was on the O'Reilly Radar blog. Sweet.

Here's the link & description: Hippocampus Text Adventure -- written as an exercise in learning Python, you explore the hippocampus. It's simple, but I like the idea of educational text adventures. (Well, educational in that you learn about more than the axe-throwing behaviour of the cave-dwelling dwarf)

*Although I probably won't be updating this project much in the near future, if you have any suggestions for improvements on the code, please share.

New code and the imported dictionary are below. Also, I've added the code to github. Enjoy.
from sys import exit
from random import randint
from hippodict import responses 
import Levenshtein 

def geta_response(response_list, tolerance=2, error_msg = "That doesn't make much sense. Try typing that in again."): 
    while True:
        next = raw_input("> ")
        for response in response_list:
            if Levenshtein.distance(next.lower(), response) <= tolerance:
                return response
        print error_msg

def go(directions):
    response = geta_response(directions.keys(), 2)
    destination = directions[response]
    destination()

def dead():
    death = ["Have a good one.", "Aww, why not? Ok, maybe you'll want to play another day.", 
    "The hippocampus will miss you. I bet you'll miss it.", "You missed out on a damn good game.", 
    "You just missed out on such a good adventure. Bummer.", "Ok, you missed out. But no problem.", 
    "Aww, too bad. Guess you don't *really* want to explore the hippocampus.", "Maybe another time!"]
    print death[randint(0, len(death)-1)]
    exit(1)
 
def entorhinal_cortex():
    print responses['Layer2and3']

    response = geta_response(["2", "3"], 0 , responses['TryAgain'])
    how_much = int(response)

    if how_much == 2:
        print "Welcome! Now you have the option of exploring the dentate gyrus or the hippocampal region CA3. Enter your choice."

        go({"dentate gyrus": dentate_gyrus,"hippocampal region ca3": hippocampal_region_CA3})
        
    elif how_much == 3:
        print "Sweet pick. Since the entorhinal cortex has 2 major projections, you have the option of exploring the hippocampal region CA1 or the subiculum. Enter your choice."

        go({"hippocampal region ca1": hippocampal_region_CA1,"subiculum": subiculum})
            
def dentate_gyrus():
    print responses['DentateGyrus']
    response = geta_response(["yes", "no"], 1 , responses['TryAgain'])
    
    if response == "yes":
        print """The dentate gyrus primarily consists of granule cells, interneurons and pyramidal cells.""" """The dentate gyrus' main projection is to the CA3. So off to there you go!"""
        hippocampal_region_CA3()
    elif response == "no":
        dead()

def hippocampal_region_CA3():
    print responses['HippocampalRegionCA3']
    response = geta_response(["yes", "no"], 1, responses['TryAgain'])
    
    if response == "yes":
        print "The CA3 plays a role in the encoding of new spatial information within short-term memory with a duration of seconds and minutes.""" """The CA3's main projection is to the CA1. So that's where you're headed to next."""
        hippocampal_region_CA1()
    elif response == "no":
        dead()
        
def subiculum():
    print responses['Subiculum']
    response = geta_response(["stay", "leave"], 1, responses['TryAgain'])
    
    go({"stay": dead(), "leave": entorhinal_cortex_2()})

def hippocampal_region_CA1():
    print responses['HippocampalRegionCA1']
    response = geta_response(["subiculum", "entorhinal cortex"], 1, responses['TryAgain'])

    go({"subiculum": subiculum(), "entorhinal cortex": entorhinal_cortex_2()})
    
def entorhinal_cortex_2():
    print responses['EntorhinalCortex2']
    response = geta_response(["yes"], 1, responses['TryAgain'])
    
    if response == "yes":
        entorhinal_cortex()
    else: 
        print "Thanks for playing."

def start():
    print responses['StartHere']     
    response = geta_response(["ready"], 1, responses['TryAgain'])

    go({"ready": entorhinal_cortex()})

start()
responses = {
    'Layer2and3' : "You are currently in between layer 2 and 3 of the entorhinal cortex. You have the option of traveling in either layer. Which layer do you want to walk along?", 
    'DentateGyrus' : """Ah, the dentate gyrus. Good pick. The dentate gyrus is one of the few regions in the adult brain where neurogenesis is thought to take place. It also plays a role in depression.""" """ There are three major types of neurons found here.""" """ Would you like to learn about them?""", 
    'HippocampalRegionCA3' : """ Now you're in the hippocampal region CA3 or simply, the CA3.""" """ There are a few proposed behavioral functions of the CA3.""" """ Would you like to learn about one?""", 
    'Subiculum' : """Hey, now you're in the most inferior region of the hippcampus called the subiculum. It lies between the entorhinal cortex and the CA1.""" """ Do you want to stay or leave?""", 
    'HippocampalRegionCA1' : """Welcome to the hippocampal region CA1 or simply, CA1.""" """This region sends a large amount of output to the subiculum and some inputs back to the entorhinal cortex.""" """Which way would you like to travel?""", 
    'EntorhinalCortex2' : """You have now, more or less, made a full loop within the connections of the hippocampus. Congratulations!""" """If you want to explore a bit more, please replay the game! Is this what you want to do?""", 
    'StartHere' : """Hello. You're about to explore the hippocampus. """ """There will be many paths and therfore, many decisions you can make.""" """Enter 'Ready!' when prompted and you can begin your journey.""", 
    'TryAgain' : "That doesn't make much sense. Try typing that in again."}