Monday, December 19, 2011

Expert Beginner

As a self-led beginner with only a few projects on my back, I constantly hear from pros that while learning, I should try to develop better coding habits like: comment on your code often, read code as often as you can, and play around with the code. While playing around with the code, I occasionally fall into that precarious group of "non-programmers" that fiddle with some lines of code and just move stuff around until they get the computer to do what they want. Even though I end up going back and trying to understand every line of what I've written, a modification to the last piece of advice is in order.

This habit of "moving stuff around" in the code, or what some refer to as blind tinkering, is not useful when that's all you're doing. I know that playing with the code is a great way to learn, but it should be done methodically and with the intention of caring about what you're learning. That is, either while or after you've played around and got the desired result, draw reusable conclusions as to why that experimentation was useful.

So I'm trying to build the practice in which I encourage myself to constantly ask questions like, "What do I know so far?", "Do I really understand how each line of code works?", "How else can I better organize what I've written?", and most importantly, "Am I just blindly tinkering?". Ask yourself these questions, think about the code, recognize what mistakes you made during the experimentation, and avoid blind tinkering. This type of concentration is key before declaring the job done and moving on to the next task. Doing this has not only provided me with a richer learning experience, but with more confidence in what I know.

For me, the value of the final product now also lies in my complete understanding of the code itself. I suspect that if this mindset becomes habitual, I can fulfill the role of an expert beginner in no time.

Tuesday, December 13, 2011

A Mantra (of sorts)

"Turn a blind eye to self-doubt and just write code."

-- Jae Kwon

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."}

Wednesday, August 10, 2011

A Hippocampus Anatomy Game


Problem: Write a game, any kind of game. Just start doing it, do a small version, make it bigger, keep a list of things to do, and do them.

I made this Choose Your Own Adventure-like game as practice after learning about branches and functions, if-else statements and while loops. I wanted to make an educational game that incorporated a deep interest of mine, neuroscience. So the subject of this game is a way to learn and explore one of the most studied regions in the brain, the hippocampus. The hippocampus is primarily known to be involved in memory and is located in the medial temporal lobe. Keep in mind: this region is very complex and this is only a crude (but hopefully fun) way to explore it.

This turned out to be fairly straightforward endeavor, thanks to Zed Shaw's Learn Python the Hard Way. I really enjoyed reviewing the anatomy of the hippocampus and finding better ways to navigate through the game. As of yet, I haven't used classes, lists nor dictionaries in this version of the game, but plan on doing so in the next. If you have any suggestions within these parameters, please feel free to share them.

In this game, you are in control and can decide where you want to travel and how much you want to learn about the hippocampus anatomy.

Here's what the code looks like:
from sys import exit

def entorhinal_cortex():
    print "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?"

    next = raw_input ("> ")
    if "2" in next or "3" in next:
        how_much = int(next)
    else:
        dead("Sorry, no can do. Guess you're stuck in the entorhinal cortex!")
        
    if how_much == 2:
        print "Welcome! Now you have the option of exploring the dentate gyrus or the hippocampal region CA3. Enter your choice."

        while True:
            next = raw_input("> ")
            if next.lower() == "dentate gyrus":
                dentate_gyrus()
            elif next.lower() == "hippocampal region ca3":
                hippocampal_region_CA3()
            else:
                print "That doesn't make much sense. Try typing that in again."
            
    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."

        while True:
            next = raw_input("> ")
            if next.lower() == "hippocampal region CA1":
                hippocampal_region_CA1()
            elif next.lower() == "subiculum":
                subiculum()
            else:
                dead("You just missed out on such a good adventure. Bummer.")

def dentate_gyrus():
    print "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."
    print "There are three major types of neurons found here."
    print "Would you like to learn about them?"

    while True:
        next = raw_input ("> ")
        if next.lower() == "yes":
            print "The dentate gyrus primarily consists of granule cells, interneurons and pyramidal cells." 
            print "The dentate gyrus' main projection is to the CA3. So off to there you go!"
            hippocampal_region_CA3()
        else: 
            dead("Aww, too bad. Guess you don't really want to explore the hippocampus.")

def hippocampal_region_CA3():
    print "Now you're in the hippocampal region CA3 or simply, CA3."
    print "There are a few proposed behavioral functions of the CA3."
    print "Would you like to learn about one?"

    next = raw_input ("> ")
    if next.lower() == "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."
        print "The CA3's main projection is to the CA1. So that's where you're headed to next."
        hippocampal_region_CA1()
    else: 
        dead("Ok, you missed out. But no problem.")
        
def subiculum():
    print "Hey, now you're in the most inferior region of the hippcampus called the subiculum. It lies between the entorhinal cortex and the CA1."
    print "Do you want to stay or leave?"

    next = raw_input("> ")
    if next.lower() == "stay":
        dead("Alright guess I'll leave you here.") 
    elif next.lower() == "leave":
        entorhinal_cortex_2()
    else:
        print "Huh? Try again."

def hippocampal_region_CA1():
    print
    print "--------------------"
    print "Welcome to the hippocampal region CA1 or simply, CA1."
    print "This region sends a large amount of output to the subiculum and some inputs back to the entorhinal cortex."
    print "Which way would you like to travel?"

    while True:
        next = raw_input("> ")
        if next.lower() == "subiculum":
            subiculum()
        elif next.lower() == "entorhinal cortex":
            entorhinal_cortex_2()
        else:
            print "Try typing that again."
    
def entorhinal_cortex_2():
    print "You have now, more or less, made a full loop within the connections of the hippocampus. Congratulations!"
    print "If you want to explore a bit more, please replay the game! Is this what you want to do?"
    next = raw_input("> ")
    if next.lower() == "yes":
        entorhinal_cortex()
    else: 
        dead("Thanks for playing.")
    
def dead(why):
    print why, "Have a good one."
    exit(0)

def start():
    print "Hello. You're about to explore the hippocampus."
    print "There will be many paths and therfore, many decisions you can make."
    print "Enter 'Ready!' when prompted and you can begin your journey."

    next = raw_input("> ")  

    if next.lower() == "ready!":
        entorhinal_cortex()
    else:
        dead("Maybe another time!")

start()
Here's what the output of one possible route looks like:
In my desire to add more flexibility to the program, I only experimented with how to allow the user to be able to respond to prompts in any case. This actually took me a little experimenting (and time) to figure how to do in a concise way.

Goals for improving the code and behavior of this game:
1) Make it more concise and clearer to read. Remove any repetition.
2) Incorporate classes, lists and dictionaries.
3.) Figure out how to travel backwards through the game. Give the user a chance to change their mind and reverse direction.
4.) This game made me realize that I don't know the full extent of possible operations that I have at my disposal. I want to experiment with more of them in the next version of the game.

Questions:
1.) Is there anything in my code that is considered bad practice?
2.) What are some ways that I can condense the code?
3.) Can I improve the naming of functions?
If you'd like a copy of the program to play with (and expand!), you can go here

Friday, June 10, 2011

Lessons From A Beginner Programmer


I've recently started an exciting journey into programming and thought it might be useful to share a few things that I've learned so far.

1.) Don't Be Intimidated. When I first gave serious consideration to learning how to program, a friend gave me some useful advice that stuck with me: "Whatever you do, however you decide to approach this, don't be intimated." My first thought was full of that naive yet self-confident, "Well, yeah of course." The more time I spent on it, both independently and with others, I understood why she said that. It's easy to be intimidated by the hacker culture, the concepts, the skill level of other programmers and so on. Although I admit to sometimes being discouraged by this, her advice has become a mantra in my mind. Don't be discouraged by programmers (if you're exposed to any), don't be discouraged by the concepts, and more importantly, don't be discouraged by the journey. You'll know if you truly want to learn if you can push through these obstacles.

2.) Pick A Project. I had been wanting to pick up programming since college, but not enough to put any significant energy toward it. I brushed over introductory chapters of CS books and perused through lectures on various college websites but that's about as far as I made it. This desire changed when I began thinking of a web project that I wanted to use for myself. At some point I decided, "Hey, I want to see this out there. Instead of waiting for it to occur, why not start learning and work toward it on my own?" Around the time I started learning programming, I also started learning how to read and write Devanagari (Hindi). So I got some Hindi textbooks from the library and just went at it. But the work quickly began to feel meaningless because I wasn't motivated by a project, like for example, a book in Hindi to read or a letter to write to a relative in India. So pick a project that matters to you. Think of what you want to accomplish and how enabled you will feel by doing it. The passion for your project will help you through the "hard stuff." It’s immensely critical that you really care about the idea and have a project to work toward. If this doesn't exist, learning may feel a little pointless at times. Figure out your intentions and dedicate yourself to it.

3.) Be Patient. Take your time working through the exercises and problem sets. The hard work you do on them really pays off in the long run. Learning the basics may feel like low-level skills, but it's worth it to master these from the get go before moving on. Along with this, keep in mind that you will always have more to learn. There's no end to your proficiency and creations, so regardless of what, take as long as it takes. Especially in the beginning, be patient with the material and yourself as you learn.

4.) Examine Yourself. Since it had been some time since I picked up anything new with such ferocity, I realized that being a beginner, at anything, really gives you key insights into yourself. How you learn, what your motivations are, what discourages you, etc. It can be hard to pick up challenging activities, because, well, they are challenging. It’s a learning process and that can be difficult if you’ve generally been doing the things you know well often. So while you're learning, think seriously about your learning techniques and strengths/weaknesses.

5.) Experiment With It. This one takes a little practice but it's been the most important one for me. When you're learning the basics, really play with each part of the code. Whenever I would ask a friend a coding question, often times the response would include the answer and encouragement to experiment with it. For instance, if an exercise asks you to solve one problem, see how many other ways you can solve it. See how other people tried to solve a similar problem. How is their coding style different than yours? Reading and playing with a lot of code will really help with your fluency in the language. All this experimentation will improve the quality of your learning and will ultimately make you a better coder.

Don't forget to seek out programming events/workshops in your area, set up coding dates with friends, and of course refer to online communities.