SEARCH

Enter your search query in the box above ^, or use the forum search tool.

You are not logged in.

#76 2013-06-09 08:40:53

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Argument Vectors : argv

Not so very long ago, and what prompted me to start sharing some python wizardry with everyone, a random poster on this board was asking about how to make a python script that had been written to interface with a headphone system run and have the desired output.  He was having some difficulty because the writer had used what we're about to go over to allow the user to specify what piece of hardware was to be connected/disconnected.  Dr. Xaos (in his normal "surgical" way) explained that the script needed to be ran as "./scriptname something XXX something_else" for it to work.  As I glanced at the script, I had a few questions about why the author used his numbering scheme, but realized that if he didn't specify how this process was to be launched, a person who didn't understand argument vectors would have some trouble figuring it out.  So without further ado, how to use and call arguments from the command line:

Let's first make this script, save it as "argvspell.py" and look at it more carefully afterwards.

from sys import argv

script, first_var, second_var, third_var = argv

print "The script is called:", script
print "Your first variable is:", first_var
print "Your second variable is:", second_var
print "Your third variable is:", third_var

If you try to simple run this as "$->python argvspell.py" you'll run into an error.  That's because what we're doing is allowing arguments to be passed to our script from outside of our code and then unpacking them inside of it.

Try to run this with the following notation:

python argvspell.py fireball ice lightning

Now run it again as:

python argvspell.py blizzard instant_death summon_snake

This should give you some pretty interesting output.  Now, we've imported a module (oh no, new term) at the beginning of our program to allow us this functionality.  Real power with python comes in the ability to take these modules and build scripts around them.  There are literally thousands of them out there, and we'll get into how to download and add them to our programs at a later date.  From the point that we release our code, the modules that we call from it will be dependencies for our programs.  (Feel free to take a moment to process what I just said there if you didn't catch it.  WE will be requiring the user to have certain dependencies met.  Mwa ha ha ha ha!  Now they have make sure OUR requirements are met before they can use our spells.)

This particular module is included in python.  The name of the module is "sys" and you can read more about it In the python documentation.  On the other hand, if this is your first time trying these out, don't expect to totally grasp all of it.  There's enough there to melt your brain.  For our purposes, we're only importing "argv" from the "sys" module.  We don't need all of that stuff for what we're looking at doing.

Argument vectors (argv) are an easy way to handle switches that the user can input at the time that the script is called.  It can also be "passed for unpacking" from another script, but we're getting WAY ahead of ourselves here.  If I keep discussing theory, we're not going to learn anything.  Let's look at a potential need for this that's simple enough for our purposes.

Let's say that we've got a simple program that reads the value of a thermometer and gives the output to the user.  It totally works great and we love it.  They simply call "therm.py" and our script gives them the output that they want.  Now, I'm not going to make a script that does this, because I don't have a thermometer with digital interfacing anywhere close, so we'll start by just making sure that we can get the input that we want into our script:

#run this program as "temp.py temp"
from sys import argv
print argv[0]
print argv[1]
print type(argv[1])

Once we've completed our program, though, we realize that we have "Bob" who's American, and "Carl" who's from France...and they can't agree on what system should be used for the format of the output.  Bob only understands Fahrenheit, and Carl only understands centigrade.  So, we want them to have control over what output they receive when they run the program because they can't be bothered with standardizing.  Previously, we ran our program as "temp.py temp" where temp was a string that should be the temperature on our gauge.  Now, let's give them an option to pass the "-c" switch to our program to convert our American-thermometer reading into centigrade or the "-f" to leave it in Fahrenheit.  So now, we teach both Bob and Carl to run the program as "$->python temp.py <temperature> <switch>"  So, either "python temp.py <whatever_the_temp_is> -c" or "python temp.py <whatever_the_temp_is> -f" should work.

#run this program as "temp.py temp -switch"
from sys import argv

if argv[2] == "-f":
	print "What Bob wants"
elif argv[2] == "-c":
	print "What Carl Wants"
else:
	print "Not Applicable Format Specified in %s" % (argv[0])

Try it out, it now should give you different outputs depending upon what switch you use:

python temp.py 97 -c

or 

python temp.py 97 -f

or

python temp.py 97 -a

The "-a" is just to activate our "else" logic for if they don't use an applicable switch.  We at least know now that our "design" works, so let's start making it function correctly.  We go check out wikipedia because we used all of our time memorizing how to configure conky and didn't have time to memorize the conversion for Fahrenheit to centigrade.  It says that basically Celsius is [(5/9)*(fahrenheit-32)]  We can deal with that, right?

#run this program as "temp.py temp -switch"
from sys import argv

def fahrenheit2celsius(fahrenheit):
	celsius = (float(5) / float(9) * (float(fahrenheit) - 32))
	return celsius

if argv[2] == "-f":
	print "What Bob wants is %s" % argv[1]
elif argv[2] == "-c":
	print "What Carl Wants is %s" % (fahrenheit2celsius(argv[1]))
else:
	print "Not Applicable Format Specified in %s" % (argv[0])

This is pretty muddled looking, but it does what we've asked of it so far.  To further complicate thing, we get a new lady in the lab called Susan.  Susan graduated from MIT and likes to prove how "scientific" she is by complicating things.  She requests that we also be able to give her the option to see the output in Kelvin.  Now, we are wizards, so we can't let her request even slow us down.  Kelvin is simple, as it only adds celsius+273.15.  On the other hand, we want to make a nicely organized function to handle this as well.  Let's use something like:

#run this program as "temp.py temp -switch"
from sys import argv

def fahrenheit2celsius(fahrenheit):
    celsius = (float(5) / float(9) * (float(fahrenheit) - 32))
    return celsius

def fahrenheit2kelvin(fahrenheit):
    celsius = fahrenheit2celsius(fahrenheit)
    kelvin = celsius + 273.15
    return kelvin

if argv[2] == "-f":
	print "What Bob wants is %s" % argv[1]
elif argv[2] == "-c":
	print "What Carl Wants is %s" % (fahrenheit2celsius(argv[1]))
elif argv[2] == "-k":
	print "What Susan Wants is %s" % (fahrenheit2kelvin(argv[1]))
else:
	print "Not Applicable Format Specified in %s" % (argv[0])

That's right!  F**k you Susan!  We got your stupid "-k" switch in there, and if you really knew anything you'd use your MIT grad knowledge to just mentally figure it out.  You can't stump us, we're WIZARDS!

Or are we?  What if we get a new intern in the building and he doesn't know to add the switch at the end of the call to our program?  Well, we need to handle that too.  On the other hand, we need a little more understanding of HOW this structure works to be able to really cover ALL of the bases.

More to come....

Last edited by DebianJoe (2013-06-09 09:37:32)

Offline

Be excellent to each other!

#77 2013-06-09 09:27:45

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Lists

If you've been paying attention then you probably caught the fact that I used argv[1] to grab our temperature and argv[2] to grab our switch out of the above code.  Well, when we were slicing strings, if we used string_name[1] to slice our string, we got the characters at position 1 as output.  Now, we looked at what type argv[1] was, and I'm pretty certain that it said "<str>" so what's the deal?  To answer this, we'll ask python to tell us what "argv" is.

#run this program as "temp.py temp"
from sys import argv
print argv[0]
print argv[1]
print type(argv[1])
print type(argv)

That last line comes back as <list>, and there's something that we really need to cover to be proficient wizards.  What's a <list>?  A list is simply an ordered set of items.  Take note that I said, "ordered" here, as that's really important to how we can use them.  They can hold other variables in a sequence for us to index through or index by position.  We'll get away from "argv" for a moment to see them in the simplest light possible.

pets = ['dog', 'cat', 'fish', 'velociraptor']

print pets
print type(pets)
print len(pets)
print pets[0]
print pets[1]
print pets[2]
print pets[3]

So, we've made a list using the "[]" brackets that includes 4 pets.  When we call out positions, we don't get the character, but rather we get the string inside of the list at that position.  This gives us a flexible framework for managing how we can access data inside the list.

pets = ['dog', 'cat', 'fish', 'velociraptor']

print pets[0: 3]
print pets[2:]
print pets[3:0:-1]
print pets[3::-1]

The technique that we used in stringmancy can be applied in much of the same way to lists.  We can index them, slice ranges, index in a progression, and much much more.  Let's pretend that this is a list of pets that we currently own, and we purchase a turtle.  We can add the turtle to the list easily.

pets = ['dog', 'cat', 'fish', 'velociraptor']

pets.append('turtle')
print pets

Let's assume that we want to give away this turtle because he doesn't get along well with our velociraptor.  We want to be able to see what item we're removing, and ALSO remove him from the list.  So we can use the "pop" method to get that turtle out of our list.

pets = ['dog', 'cat', 'fish', 'velociraptor']
print pets
pets.append('turtle')
print pets
print pets.pop(-1)
print pets

This is only the surface, but I didn't want to leave you totally hanging from the last lesson.  I've got work that I need to be doing, but trust me when I say that we'll cover lists and methods on lists in FAR greater detail in the future.  Given only the things that I've pointed out here, functions that I've used, and some if/elif/else statements, think about how we can prevent the intern in the previous lesson from being able to crash out our program by simply forgetting the "switch" or perhaps even adding some extra ones.

Offline

#78 2013-06-09 10:05:34

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

The "Why" of Lists.

Before I call it a day, I want to cover something that I think is really neat about lists.  Since they're ordered, we can use them as a "stack" for holding variables.  As a neat little example of something else that is useful using lists, let's give ourselves the option to "deal" out a deck of cards.  We first want the user to tell us how many cards are in the deck, then we'll add them to the list/deck, then by importing random, we can use the "shuffle" method to shuffle our deck, and then deal ourselves a "hand" of the bottom 5 cards.

import random

number = int(raw_input("How many cards would you like? "))
cards = []
hand = []
while number > 0:
	cards.append(number)
	number -= 1

print cards
random.shuffle(cards)
print cards

for card in cards:
	hand.append(cards.pop())
print "In your hand there's " + str(hand)
print "In the deck there's " + str(cards)

Offline

#79 2013-06-09 11:44:48

savalaserg
#! Member
Registered: 2013-05-15
Posts: 91

Re: Baby's First Programming, (In Python)

Im still in the game guys. Just have alot of things going on and not much time to focus. Keep it coming I will be playing catch up soon. Oh and just if you guys are wondering who that guy was that debianjoe was talking about a couple of posts back about the headphone script it was me  big_smile lol. Anyway great class great teacher keep moving forward!

Last edited by savalaserg (2013-06-09 11:45:24)

Offline

#80 2013-06-09 11:48:40

kbmonkey
#! Die Hard
From: South Africa
Registered: 2011-01-14
Posts: 879
Website

Re: Baby's First Programming, (In Python)

Another way to generate your list of cards, utilizing all the beautiful commands we learned, would be:

cards = list(xrange(number, 0, -1))

The while-loop is by all means correct, it goes to show there are many ways to skin a list. O:)

p.s. Is your dungeon crawler public DebianJoe? I do enjoy a good roguelike on Sundays.

Offline

#81 2013-06-09 12:39:11

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

kbmonkey wrote:

p.s. Is your dungeon crawler public DebianJoe? I do enjoy a good roguelike on Sundays.

I'm still a pretty decent distance from pushing it to my github yet.  I've been a tiny bit preoccupied with schooling, but as soon as I get it to a point where there's actually something other than endless levels of going deeper and deeper, I'll be sure to let you know.

Offline

#82 2013-06-09 15:40:14

ze-hobbit
Member
Registered: 2009-07-09
Posts: 13
Website

Re: Baby's First Programming, (In Python)

DebianJoe wrote:

Let's see how we could do it with 7 lines.

for num in xrange(1,101):
    msg = ''
    if num % 3 == 0:
        msg += 'Fizz'
    if num % 5 == 0:
        msg += 'Buzz'
    print msg or num

Now, that's nice.  It can be done in less, but we won't go into that yet.  I used a new trick here, the "xrange" function.  Read more about it in (you guessed it) The Python Documentation.

Wow... I wasn't too much surprised with xrange, but I certainly wasn't expecting the operator <or> working with the comparison of a string (empty or not) and a number, such that

   '' or number

returns number

and

   'non-empty-string' or number

returns the string.

I made a pause and I'll continue and look at functions tomorrow.

Offline

#83 2013-06-09 16:47:44

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Pretty neat, isn't it.  Since we were discussing "spell-books" this if the fastest way that I've figured out how to do the Fizzbuzz.  I wouldn't ever write anything like this, as it violates the "Zen of Python" on so many levels, but it's a cool way to do it.

for x in xrange(1,101):print"FizzBuzz"[x*x%3*4:8--x**4%5]or x

*edited to only use subjects that we've looked at. big_smile

Last edited by DebianJoe (2013-06-09 16:49:37)

Offline

#84 2013-06-09 17:48:44

ze-hobbit
Member
Registered: 2009-07-09
Posts: 13
Website

Re: Baby's First Programming, (In Python)

afterall I found some time to check out the rest of the wizard lessons tongue

About the dungeon crawler, is it a roguelike. What lprogramming language/library are you using?

Offline

#85 2013-06-09 18:08:43

intoCB
Scatweasel
Registered: 2012-10-25
Posts: 2,412

Re: Baby's First Programming, (In Python)

Just noticed this and did the first two parts. Great stuff. Will try to catch up.

Offline

#86 2013-06-09 18:34:54

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

ze-hobbit wrote:

About the dungeon crawler, is it a roguelike. What lprogramming language/library are you using?

I'm using Python and libtcod, and yes...it's a Roguelike.

Edit: Just got to thinking, I'd be more than glad to get it up and working in a skeleton build and then push it to github to allow everyone that's been hanging out here to do whatever you guys can to make it better.  It would be a fun way to test out what all we've learned.

Last edited by DebianJoe (2013-06-10 04:58:44)

Offline

#87 2013-06-10 08:16:28

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Class Project

I have a working copy of a mildly modified libtcod based Roguelike that's far simpler than the one that I have been hacking on that I did after checking out libtcod the first time.  It's very closely tied to the tutorials that are available on using the library so if anyone had questions, they could go and check out the libtcod docs to get a better understanding of it.  I'm looking at pushing it up later, but I wanted to first get feedback on setting up a group project.  I'm thinking release under the GPLv2, under my name for the license and with all credit being given to the "Crunchbang Python Group" where everyone who makes changes can add their name to the comments and the readme.  I wanted to be sure that there was a very specific division between Crunchbang as a distribution and anything with the name inside of it, so I sketched this out as a README note.  Thoughts, corrections, etc?  If you guys are cool with this, I think that it would be really cool to have a big group project that was version controlled that everyone could modify and work with in their own time.  I've set up a github just for this class's projects and such.

The Readme:

Welcome to the Crunchbang Python Group's
group project in Python.  

The main program dungeons.py requires
libtcod-1.5.1. which can be freely downloaded at:
http://doryen.eptalys.net/libtcod/download/

The Crunchbang Python Group is honestly just simple post on a forum
located at http://crunchbang.org/forums/viewtopic.php?id=26914&p=1
and are in NO way affiliated with Crunchbang Linux, Corenominal, the
Crunchbang distribution process, or any other implied projects.
We simply love Crunchbang and happen to use the forums a lot.

...and then the licensing information.  Give me some feedback on this one guys.  I want the credit to be tied to the work done on the project, and for everyone involved to have their name/avatar's name in it somewhere.

Last edited by DebianJoe (2013-06-10 08:17:19)

Offline

#88 2013-06-10 09:53:01

joek
#! Junkie
Registered: 2011-09-06
Posts: 497

Re: Baby's First Programming, (In Python)

That looks fine. I agree that GPL is possibly the best license to release under.

Would Corenomial mind the CrunchBang name being associated with this project?

Also:

for x in xrange(1,101):print"FizzBuzz"[x*x%3*4:8--x**4%5]or x

Is horrible in so many ways.

Offline

#89 2013-06-10 17:19:48

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

@joek, I'm not sure if it would be an issue or not.  I've not spoken with Corenominal about it yet.  I just want to be certain that we wouldn't be stepping on any toes, and as long as we're as honest as possible, I don't see how anyone would take offense.  Also, yes, that's the very definition of "obfuscated".  Speaking of definitions.

More works of disorder.  Dictionaries.

One of the other major structures you'll see in python coding is a Dictionary (dict for short.)  There's a lot of similarities between lists and dictionaries, but the design difference makes for a highly ordered structure.  The basics of a dict is that it stores pairs of variables, one as a "key" and one as a "value".  Let's look at a simple example and see how our python compiler sees the groups.

our_dict = {'one': 1, 'two': 2, 'three': 3, 'four' : 4}
print our_dict.items()

Now, it may be intuitive as to which one is which, but we can also get python to spit out the parts of the dict independent of one another.

our_dict = {'one': 1, 'two': 2, 'three': 3, 'four' : 4}
print "Our keys are..."
print our_dict.keys()
print "and our values are."
print our_dict.values()

I wish I could tell you how these are printed out on your screen, but I really can't because the order keys are iterated in is arbitrary.  That's why I was quick to point out that they are "disorder" in the title.  On the other hand, the pairs always remain grouped together.  This can be used to keep clearly named keys matched to their respective numerical values.  They can also be used for totally useless purposes, and that's what I'm going to do because I feel like wizards should be able to understand the applications with fun little applications that clearly show how the structure works.

#Really basic Cloak and Dagger cypher based on dicts
#Run as #`>> python <script_name>.py <switch> <message>
from sys import argv


CIPHER = {'a': 'x', 'b': 'c', 'c': 'r', 'd': 'm', 'e': 'l', 'f': 'y'
	,'g': 't'}


# Encode switch
def encode():
    emsg = ""
    for ch in message:
        emsg += CIPHER[ch]
    print message, "encodes to", emsg

# Decode switch
def decode():
    dmsg = ""
    for ch in message:
        for key, value in CIPHER.items():
            if ch == value:
                dmsg += key
    print message, "decodes to", dmsg


if len(argv) == 3:
	message = argv[2]
	if argv[1] == '-e':
		encode()
	elif argv[1] == '-d':
		decode()
	else:
		print "You didn't set a correct switch switch"

else:
	print '''
Not correct format to run this program,
use form <scriptname> <switch> <message>
where <switch> is -e for encode,
and -d is for decode.

Message can only be a single word with 
letters from a-g...it's not for real use!
'''

There's a lot of other neat things that we could potentially do with dicts, but I just wanted to have a quick overview of them.  There's a whole lot more information in the PYTHON DOCUMENTS, as though you didn't know. 

I'm really interested in throwing you guys a program to play with, study, improve, ask question about, etc.  There's a few things that I've used in there that we haven't had a chance to look at the structure of.  Since I know that we have at least a couple of truly new to python coders here, I don't want to push my luck with this or have anyone feeling totally confused by something that's actually really simple in execution. 

What should I do?  Group project already, or wait until we at least get to classes?

Offline

#90 2013-06-11 05:55:24

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Class Project - The Underdeep: A Roguelike in Python

I gave everyone at least 12 hours to bring up an argument as to why we might not want to throw out a class project now, and nobody said anything.  So, without further ado, let's open up the first creative class project:

The Github for our project.
Libtcod Repo (needs 1.5.1)
The Tutorial for Making the Base Code
The libtcod documentation.
Github Help page, for the newer members.

The basic tiled Ariel 10x10 png
arial10x10.jpg

Stock Creative Commons menu-background artwork.
menu_background.png

There are quite a few things missing from this file.  It works, but there's no objective, there's only 3 monsters, there's only 2 items that are able to be equipped, there's really only two color-schemes for dungeon levels, the story needs work, the formatting needs work, and it needs character classes (perhaps), we also could use a different background image for the main menu.  This is the file that I ended up with straight out of the libtcod tutorial, and that's why I think it would be a great point for jumping off.  Almost every piece of code in it is explained in the above linked tutorial.  Any changes in it were things that I played with while working through the tutorial on the library, so they're pretty minor.  (I liked my system for fov coloring much better, for instance.)

So, here's about 1200 lines of skeleton code to get you guys started on hacking out something.  I'll continue with the postings for basic python wizardry, but for everything that you learn I want you to try to apply it somewhere to actually improve the fun and functionality of our project.

I want everyone to be getting the credit for their work on the project, so if you have a github acct that differs from your screen name...please let me know how to credit who for what work.  Add your name or avatar's name to the README and the comment section of the program. 

Enjoy

Edit:  The files that you'll want IN the folder for developing the script further are 'libtcod.so' and 'libtcodpy.py' and obviously the two images posted above.  The "menu background" one is the correct size, so you just need to save it inside the folder for it to work.

Last edited by DebianJoe (2013-06-13 07:20:43)

Offline

#91 2013-06-11 08:42:23

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Classes - Baby's First Step Towards OOP

With the release of the group project, this one is something that I feel I may be pushing out of the gate a little fast.  We've just learned lists and dicts, slicing and popping and appends.  This is a much deeper rabbit hole, and there's a lot of things here that can be pretty confusing.  Without it, though, there are large portions of the group project that won't make any sense at all.  (How to explain this without discussing namespaces?  I'll see if we can make this work.)

Let's start by making a "Wizard Class" to play with.

class PythonWizard:
    """A simple example class"""
    spell_power = 9000
        
print PythonWizard.spell_power

That looks a lot like how we had assigned variables before, wouldn't you think?  Try to simply call "print spell_power" in the last line just for fun.  It won't work.  So, we've only managed at this point to totally screw up the extremely simple process of assigning variables.  That's because the real power of classes is that they should be flexible constructs that are portable and reusable.  Let's try doing that.

class SpellCaster(object):

    def __init__(self, name, spelltype):
        self.name = name
        self.spelltype = spelltype

    def getName(self):
        return self.name

    def getType(self):
        return self.spelltype

    def __str__(self):
        return "%s is a %s" % (self.name, self.spelltype)

That's significantly better.  The first word, class, indicates that we are creating a class. The second word, SpellCaster, is the name of the class. The word in parentheses, object, is the class that SpellCaster is inheriting from.  Inheriting is a tricky subject, but really all you should worry about now is the syntax and usage.  We'll get into the "how and why" later.  It's very confusing starting out, but the __init__ is a method (which is really just a function inside of a class) that python uses when a particular usage of a class is first created.  *note the format for __init__ is (underscore + underscore + 'init' + underscore + underscore) make sure you put two underscores on EACH side of the word 'init'.

This might make more sense if I created a line of code to initialize these values.

kbmonkey = SpellCaster("KBMonkey", "Code Reforging")
debianjoe = SpellCaster("Joe", "Code Generation")
zalew = SpellCaster("Zalew", "Best Practices")

Okay, so we now have kbmonkey as an instance of the SpellCaster class, who's name is "KBMonkey" and who's spelltype is "Code Reforging."  A debianjoe instance of the SpellCaster class who's named "Joe" and who's spelltype is "Code Generation", and a zalew instance of the SpellCaster class who's name is "Zalew" and who's spelltype is "Best Practices."  Pretty cool.  I also included a "string method" here that can be really useful for keeping up with what values we've stored in what classes.  Let's look at how that works.

class SpellCaster(object):

    def __init__(self, name, spelltype):
        self.name = name
        self.spelltype = spelltype

    def get_name(self):
        return self.name

    def get_type(self):
        return self.spelltype

    def __str__(self):
        return "%s is a %s wizard" % (self.name, self.spelltype)
        
kbmonkey = SpellCaster("KBMonkey", "Code Reforging")
debianjoe = SpellCaster("Joe", "Code Generation")
zalew = SpellCaster("Zalew", "Best Practices")

print kbmonkey.name
print debianjoe.spelltype
print zalew

Check that last line's output out!  When I just call "print zalew" I get the entire "string method" returned back to me.  That's what a __str__ does.  It gives you a way to double check the values you've placed into a class, which is extremely valuable for when you're dealing with numeric methods inside of a class.  The (get_type) is a method (again, it's just a function in a class, but we use different names for those) that will return the value of "spelltype" for a particular instance of a class when it's called.  (get_name) does the same thing but with the name of the instance in the class.  This doesn't make much sense for what we're doing here, so let's make a method that could actually be useful.  In order to do that, we'll also have to update the value in the initialization of each instance.

Let's see how this might actually be useful in usage.

class SpellCaster(object):

    def __init__(self, name, spelltype, def_power, off_power):
        self.name = name
        self.spelltype = spelltype
        self.def_power = def_power
        self.off_power = off_power

    def get_name(self):
        return self.name

    def get_type(self):
        return self.spelltype
        
    def get_spellpower(self):
    	self.spellpower = int(self.def_power) + int(self.off_power)
    	return int(self.spellpower)

    def __str__(self):
        return "%s is a %s wizard" % (self.name, self.spelltype)

        
kbmonkey = SpellCaster("KBMonkey", "Code Reforging", '2', '3')
debianjoe = SpellCaster("Joe", "Code Generation", '1', '1')
zalew = SpellCaster("Zalew", "Best Practices", '3', '2')

print kbmonkey
print debianjoe
print zalew

print "If Zalew attacked Joe"
print "Joe would be outmatched by"
battle = (zalew.get_spellpower() - debianjoe.get_spellpower())
print "%d total spell power." % (battle)

This can be a pretty daunting subject at first glance if you're totally new to OOP.  On the other hand, I strongly recommend making up some simple classes on your own and playing with using mathmatical values inside the methods so that you can get a better grasp of how classes can pay off when dealing with many similar objects.

Offline

#92 2013-06-11 09:25:34

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

Local vs. Global Variables
Things I should have discussed a LONG time before now.

I sometimes forget until I get into deeper subject that I missed out on an important concept that will be useful for what we're currently doing.  Back when we were talking about variables and basic functions, I should have covered this one.  Now that we're on classes, it's going to be far more difficult to get around not using them.

Assume that I have the desire to use a function to change the value of a variable.  I want to mutate it, and for the rest of the program, use my newly modified value.  Well, this means that I need to have a value that is set at a certain point, and then give ways to manipulate it within certain functions.

# Not going to work, and I want you to see "why"
number = 4

def increment():
	number += 1

print number
increment()
print number

So, I've built a very simple function that takes the number (which we declare at the beginning to be "4") and then simply add 1 to it.  When we try to run this code, though, we're going to get an error.  This is because in the function, the variable "number" is not the same as the one outside of the function.  Let's look at an example of implicit and explicit declarations of the value "number".

number = 4

def increment():
	number = 0
	number += 1
	print "Inside of our function " + str(number)
print "Outside of our function " + str(number)
increment()
print "Still outside of our function " + str(number)

This is a sort of built-in safety for making sure that you are intentionally meaning to adjust a global variable within python.  Inside of our functions, "number" is a LOCAL variable...outside of it, it's a GLOBAL variable.  This is a very important distinction, because my original function was to be used to add 1 to my global variable.  So, let's look at how we can declare it explicitly to do what I was trying to do in my "non-working" implementation.

number = 4

def increment():
	global number #important part here!
	number += 1
	
print number
increment()
print number
increment()
increment()
print number

By telling the function to use the global "number" variable, we can now reach outside of our individual functions to manipulate variables that we want to adjust.

Offline

#93 2013-06-11 11:04:47

Frostlock
Member
From: Belgium
Registered: 2013-05-27
Posts: 34

Re: Baby's First Programming, (In Python)

A thread using D&D references, about a language that encourages monthy python references. Loving it :-)
I had a good read (and some fun python trial and error) catching up on most of the lessons.
Then someone mentioned rogue like again and I got side tracked into nethack, ah well good fun.

I see I missed a few posts on the group project but I really love the idea, I hope to find some time later for a more in depth look at that stuff a few posts back. It looks promising!

Thanks for running this Joe!

-Frost

Last edited by Frostlock (2013-06-11 11:06:01)

Offline

#94 2013-06-11 14:29:43

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

I'm glad you're enjoying it Frostlock.  It's very much a "train of thought" writing process, and I hope that I don't leave too many gaps in the things that I'm trying to share.

Beyond that, do you guys want me to add the dependencies that I'm using to the project Github?  It might make cloning it easier, but I didn't see the need for us to be shoving files around that we wouldn't be editing.  If someone does do a new background image for the main menu, I'd certainly want that there, though.

Offline

#95 2013-06-11 19:45:18

Frostlock
Member
From: Belgium
Registered: 2013-05-27
Posts: 34

Re: Baby's First Programming, (In Python)

Getting dungeons to run proved a bit of a challenge, but finally success! Unfortunately my exploits in the depths were short lived: lol
death.jpg

Tricky bit is that libtcod 1.5.1 comes compiled for libc 2.14 and my waldorf 64-bit has libc 2.13. I have manged to partially recompile libtcod but I haven't gotten all the dependencies right yet. I got a new libtcod.so which was enough to run dungeons.py but I'm not sure if it is entirely without fault.
Also the libtcod 64 bit package comes without a libSDL.so , guess I'll have to find one myself :-)
Any tips on how you got this running cleanly would be appreciated!
In the mean time I'll look into it some more.

On a side note, this is drifting away a bit from the original topic of the thread smile

Btw I have to say that basic dungeons.py libtcod combo looks cool!

-Frost

Offline

#96 2013-06-11 19:49:30

kbmonkey
#! Die Hard
From: South Africa
Registered: 2011-01-14
Posts: 879
Website

Re: Baby's First Programming, (In Python)

Only saw the class project idea now, otherwise I would have replied, "awesome!"  - nice idea DebianJoe!

May I add a definition that helped me understand what a class is?

A nice analogy for classes is to think of them as blueprints:
I have a blueprint for a car class, it describes what values can be stored in the car (variables: number of seats, has power steering, max speed) and what actions the car can perform (methods: turn, honk horn, handbrake turn),
but you can't drive the blueprint itself, you have to assemble a car into an object first, using the blueprint to construct the car.
Thus you can create many car objects from the same blueprint.

Oh regarding global variables, I have a question Joe: if I only have a few variables it is still pretty manageable. But as my number of variables grow this becomes unwieldy. Is there any disadvantage / bad practice to store these inside a class, and pass that around or make it global? Example:

class GlobalValues(object):
    def __init__(self):
        self.number = 0
        self.color = 'white'
        self.level = 42

def increment():
    global allvalues
    allvalues.number += 1

allvalues = GlobalValues()
print(allvalues.number, allvalues.color, allvalues.level)

# OUT: (0, 'white', 42)

increment()
allvalues.color = 'green'
print(allvalues.number, allvalues.color, allvalues.level)

# OUT: (1, 'green', 42)

Thanks again mate smile Forking...

p.s. I don't see any reason to include dependencies either, source and resources (images/audio) are fine though.

Offline

#97 2013-06-11 19:55:47

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

I edited the original project post with what parts of libtcod's files you'd need to (for your architecture) simply paste them into the folder and hopefully run it.  That works well for our purposes, and it keeps the files in the repo as just the ones belonging to the project itself.

I'd simply pull the file provided in the link and put the files listed into the same folder as dungeons.py.  Put the images in the main directory with the above file and everything should "just werk (tm)". 

I don't want the dependencies to be so mind-boggling as to create extra complication as much as I want to see you guys start hacking away at the code.

Also, I don't have any audio in this project yet.  Feel free to find some that are CCommons licensed or totally free for use and add it. big_smile

As far as including the variables within the class, I would say that it's totally dependent upon what your needs are.  If what you have is simple, smooth, and works without fault...then it must be the right way.  I tend to try to minimize class usage, but that's because once you start down the chain of inheritance, things get confusing to keep up with.

It's a conundrum as to which will prove simpler in the end.  Normally, the better way is whichever one I didn't choose. big_smile

Last edited by DebianJoe (2013-06-11 20:00:11)

Offline

#98 2013-06-11 20:11:06

DebianJoe
#! Code Whisperer
From: The Bleeding Edge
Registered: 2013-03-13
Posts: 1,207
Website

Re: Baby's First Programming, (In Python)

I did adjust the difficulty of "rats" after seeing your screenshot Frost.  I loled, and then thought..."I think this is right after I added a rat type to monster classes."  I overpowered them horribly at first.

Changes pushed to the repo, for the sake of letting you see a bit more of the actual game play before imminent death.  ]:D

Offline

#99 2013-06-11 20:28:32

kbmonkey
#! Die Hard
From: South Africa
Registered: 2011-01-14
Posts: 879
Website

Re: Baby's First Programming, (In Python)

@DebianJoe in your required files list, it should be libtcodpy.py (not libtcodpy.pyc), also you need to copy arial10x10.png from the data/fonts/ directory in too, then it just works (tm) smile - edit: ah I see you have the arial font linked as the image, my bad.

I'm surprised github does not have a discussion page, not to clutter up your topic for the class, right. Unless it is considered on-topic?

*off to play some dungeon*

Last edited by kbmonkey (2013-06-11 20:30:17)

Offline

Help fund CrunchBang, donate to the project!

#100 2013-06-11 20:40:19

Frostlock
Member
From: Belgium
Registered: 2013-05-27
Posts: 34

Re: Baby's First Programming, (In Python)

That proposed solution still has the same problem, the libtcod.so is not compatible with my libc.
Like kbmonkey proposed I created an issue for this on Github (with a bit more detail). This should avoid poluting this fine python training any further :-)

With all this dependency fun I didn't even manage to look at the actual dungeons.py yet. But I did have fun and learned some things :-D

Offline

Board footer

Powered by FluxBB

Copyright © 2012 CrunchBang Linux.
Proudly powered by Debian. Hosted by Linode.
Debian is a registered trademark of Software in the Public Interest, Inc.
Server: acrobat

Debian Logo