Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord
Is there a better way to do this? I snipped the code but pretend there are dozens of these. It may be that there is a better way to handle this in django too, but I'll look into that later -- I'm more curious if there is a better way to go about doing this pattern in python.

Python code:
# hero = django model instance of a hero object
# Starting stats for different races, pretend there are many of these.
human = {'str': 50, 'int': 70, 'dex': 50, 'agi': 40, 'vit': 50, 'luk': 60}
orc = {'str': 100, 'int': 10, 'dex': 70, 'agi': 30, 'vit': 100, 'luk': 10}
#etc.

# One of these for each of the above races, it is pulling 
# 'HU' and 'OR' from the already created model object.
if hero.hero_race == 'HU':
    race = human
elif hero.hero_race == 'OR':
    race = orc
#etc.

hero.strength = race['str']
hero.intelligence = race['int']
hero.dexterity = race['dex']
hero.agility = race['agi']
hero.vitality = race['vit']
hero.luck = race['luk']

The March Hare fucked around with this message at 17:39 on Sep 17, 2013

Adbot
ADBOT LOVES YOU

DSA_Key
Dec 9, 2004
minimalist
I posted earlier in the thread that I had used pexpect to create an ssh program, someone suggested I use paramiko, so I finally rewrote it using paramiko and used some tips from the feedback I got to make it a little better.

Python code:

#!/usr/bin/python

import getpass
import paramiko
import logging
from pprint import pprint

failedhosts=[]

#Define main function for looping though the hostnames
def main(): 
  
  #Variables
  USERNAME = getusername()
  PASSWORD = getpass.getpass()
  COMMAND = getcommand()
  SSH = paramiko.SSHClient()
  TIMEOUT = 3

  #Lists
  hosts=[]

  #Open file for reading hostnames, should be return deliniated
  with open('targets.txt') as f:
    data = f.read()

  #Splits hostnames or host ip addresses into the list hosts
  hosts = data.split('\n')

  for host in hosts:  #This is the loop that runs through the list of hosts in your file

    if host:    #Check for null host in list, happens at blank return lines
      
      login(host, SSH, USERNAME, PASSWORD, COMMAND, TIMEOUT)  


#Login to the host and run the command
def login(host, SSH, USERNAME, PASSWORD, COMMAND, TIMEOUT) :

  #Automatically add SSH keys
  SSH.set_missing_host_key_policy(
    paramiko.AutoAddPolicy())
    
  try:

    print 'Connecting to %s.......' %(host,)  
    SSH.connect(host, username=USERNAME, password=PASSWORD, timeout=TIMEOUT)
    print '- OK sending command { %s } ' %(COMMAND,)
    stdin, stdout, stderr = SSH.exec_command(COMMAND)
    hostoutput = stdout.read()
    logoutput(host, COMMAND, hostoutput)
    
  except Exception,e:
  
    print '%s - ERROR %s ' %(e,host)
    errorlogging(host,e)
    failedhosts.append(host)
    pass


def logoutput(host, COMMAND, hostoutput) :
  spacer = '\n \n ----------%s---------- Command: %s \n \n' %(host, COMMAND) 
  fout = file ('logfile.txt', "ab") 
  fout.write(spacer)  
  fout.write(hostoutput)
  fout.close()
  

def errorlogging(host, exception) :
  logging.basicConfig(filename='error.log', level=logging.WARNING)
  logging.warning('\n ERROR %s on host : %s \n' %(exception,host))
  
        
#Functions for getting user input-
def getusername():

  username = raw_input("Enter Username: ")
  return username
  

def getcommand():

  command = raw_input("Enter Command: ")
  return command  

  
if __name__ == "__main__":
    main()
    
print 'Commands Complete! Grats! - Check logfile.txt for output and error.txt for errors.'
print 'These Hosts Failed: '
pprint(failedhosts)

I'm getting a little better at this, but can someone explain classes in python to me? Well I suppose I can look it up on the web.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

DSA_Key posted:

Well I suppose I can look it up on the web.

Do that and then ask questions.

Pollyanna
Mar 5, 2005

Milk's on them.


I'm trying to throw up an error and a prompt upon getting an exception. Like so:

Python code:
while True:
	try:
		data = fin.quotes_historical_yahoo(symbol, (int(past_date.year) - 1, past_date.month, past_date.day), (current_date.year, current_date.month, current_date.day), asobject=None)
		break
	except urllib2.HTTPError:
		print "Symbol not found!"
		ask_symbol()
What happens is that if the symbol that's input doesn't exist, the url 404s and gives this exception:

Python code:
urllib2.HTTPError: HTTP Error 404: Not Found
However, if I try to do except urllib2.HTTPError: , it gives me this error:

code:
Traceback (most recent call last):
  File "ta.py", line 38, in <module>
    except urrlib2.HTTPError:
NameError: name 'urrlib2' is not defined
Isn't the name of the exception urllib2.HTTPError? How come it doesn't recognize that?

And yes, I imported urllib2...

good jovi
Dec 11, 2000

"urrlib". Two r's.

Pollyanna
Mar 5, 2005

Milk's on them.


oh my god

FoiledAgain
May 6, 2007

The March Hare posted:

Is there a better way to do this? I snipped the code but pretend there are dozens of these. It may be that there is a better way to handle this in django too, but I'll look into that later -- I'm more curious if there is a better way to go about doing this pattern in python.

Python code:
# hero = django model instance of a hero object
# Starting stats for different races, pretend there are many of these.
human = {'str': 50, 'int': 70, 'dex': 50, 'agi': 40, 'vit': 50, 'luk': 60}
orc = {'str': 100, 'int': 10, 'dex': 70, 'agi': 30, 'vit': 100, 'luk': 10}
#etc.

# One of these for each of the above races, it is pulling 
# 'HU' and 'OR' from the already created model object.
if hero.hero_race == 'HU':
    race = human
elif hero.hero_race == 'OR':
    race = orc
#etc.

hero.strength = race['str']
hero.intelligence = race['int']
hero.dexterity = race['dex']
hero.agility = race['agi']
hero.vitality = race['vit']
hero.luck = race['luk']

Stick all the race dictionaries into another dictionary. Then use setattr(hero, key, value) inside a loop of hero_dictionary[hero.race].iteritems()
(iteritems() doesn't work in 3, so if you're using 3, it looks like you just use .items())

FoiledAgain fucked around with this message at 18:12 on Sep 17, 2013

The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord

FoiledAgain posted:

Stick all the race dictionaries into another dictionary. Then use setattr(hero, key, value) inside a loop of hero_dictionary[hero.race].iteritems()
(iteritems() doesn't work in 3, so if you're using 3 look up how to do that)

I'm using 2 and I totally forgot you could nest dicts, thank you for helping my frazzled brain.

Dren
Jan 5, 2001

Pillbug

The March Hare posted:

Is there a better way to do this? I snipped the code but pretend there are dozens of these. It may be that there is a better way to handle this in django too, but I'll look into that later -- I'm more curious if there is a better way to go about doing this pattern in python.

Python code:
# hero = django model instance of a hero object
# Starting stats for different races, pretend there are many of these.
human = {'str': 50, 'int': 70, 'dex': 50, 'agi': 40, 'vit': 50, 'luk': 60}
orc = {'str': 100, 'int': 10, 'dex': 70, 'agi': 30, 'vit': 100, 'luk': 10}
#etc.

# One of these for each of the above races, it is pulling 
# 'HU' and 'OR' from the already created model object.
if hero.hero_race == 'HU':
    race = human
elif hero.hero_race == 'OR':
    race = orc
#etc.

hero.strength = race['str']
hero.intelligence = race['int']
hero.dexterity = race['dex']
hero.agility = race['agi']
hero.vitality = race['vit']
hero.luck = race['luk']

I don't know Django but this is a pretty textbook use-case for classes and inheritance.

Python code:
class Hero(object):
    def defend(self, atk_points):
        self.vitality -= atk_points

class Orc(Hero):
    def __init__(self):
        self.strength = 100
        self.intelligence = 10
        self.dexterity = 70
        self.agility = 30
        self.vitality = 100
        self.luck = 10

class Human(Hero):
    def __init__(self):
        self.strength = 50
        self.intelligence = 70
        self.dexterity = 50
        self.agility = 40
        self.vitality = 50
        self.luck = 60

# make an Orc
orc = Orc()
I went one step further and had the Hero base class and provide both subclasses a common 'defend' method.

Pollyanna
Mar 5, 2005

Milk's on them.


Stuck. Again. :shepface:

So, I'm trying to create a beginning date and an end date. Basically, I'm using datetime.timedelta() to return one year, three months, or one day ago. Doing a timeframe of one year ago works, but the rest don't. I get this message instead:

code:
Exception in Tkinter callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 276, in resize
    self.show()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 348, in draw
    FigureCanvasAgg.draw(self)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 439, in draw
    self.figure.draw(self.renderer)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/artist.py", line 54, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/figure.py", line 999, in draw
    func(*args)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/artist.py", line 54, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axes.py", line 2086, in draw
    a.draw(renderer)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/artist.py", line 54, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axis.py", line 1048, in draw
    ticks_to_draw = self._update_ticks(renderer)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axis.py", line 935, in _update_ticks
    tick_tups = [t for t in self.iter_ticks()]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axis.py", line 879, in iter_ticks
    majorLocs = self.major.locator()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/dates.py", line 752, in __call__
    self.refresh()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/dates.py", line 761, in refresh
    dmin, dmax = self.viewlim_to_dt()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/dates.py", line 533, in viewlim_to_dt
    return num2date(vmin, self.tz), num2date(vmax, self.tz)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/dates.py", line 292, in num2date
    if not cbook.iterable(x): return _from_ordinalf(x, tz)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/dates.py", line 206, in _from_ordinalf
    dt = datetime.datetime.fromordinal(ix)
ValueError: ordinal must be >= 1
What could possibly cause this? The dates are the same format no matter how far back I go. What's the deal with this?

Dominoes
Sep 20, 2007

Pollyanna posted:

Stuck. Again. :shepface:

So, I'm trying to create a beginning date and an end date. Basically, I'm using datetime.timedelta() to return one year, three months, or one day ago. Doing a timeframe of one year ago works, but the rest don't. I get this message instead:


What could possibly cause this? The dates are the same format no matter how far back I go. What's the deal with this?
Post your code that caused this.

This works for me:
Python code:
one_year = datetime.date.today() - datetime.timedelta(days=365)
one_month = datetime.date.today() - datetime.timedelta(days=31*3)
one_day = datetime.date.today() - datetime.timedelta(days=1)
print(one_year, one_month, one_day, sep='\n')
Keep in mind that timedelta objects only work with days, seconds and microseconds; other units are created from them.

Dominoes fucked around with this message at 21:10 on Sep 17, 2013

Pollyanna
Mar 5, 2005

Milk's on them.


Dominoes posted:

Post your code that caused this.

This works for me:
Python code:
one_year = datetime.date.today() - datetime.timedelta(days=365)
one_month = datetime.date.today() - datetime.timedelta(days=31*3)
one_day = datetime.date.today() - datetime.timedelta(days=1)
print(one_year, one_month, one_day, sep='\n')
Keep in mind that timedelta objects only work with days, seconds and microseconds; other units are created from them.

This is the snippet of code in question:

Python code:
# Establish the current date.

current_date = datetime.date.today()

# Establish the beginning date and timeframe.

timeframe = ask_timeframe()

while True:
	if timeframe == 'a':
		past_date = current_date - datetime.timedelta(days=365) # One year ago.
		break
	elif timeframe == 'b':
		past_date = current_date - datetime.timedelta(weeks=4) # One month ago.
		break
	elif timeframe == 'c':
		past_date = current_date - datetime.timedelta(days=1) # One day ago.
		break
	else:
		print 'Invalid option!\n'
		timeframe = ask_timeframe()

print 'Beginning from ' + str(past_date) + '...'

# Download date and price data from Yahoo. Ask the user to reinput the symbol if it doesn't exist.

while True:
	try:
		data = fin.quotes_historical_yahoo(symbol, (past_date.year, past_date.month, past_date.day), (current_date.year, current_date.month, current_date.day), asobject=None)
		break
	except urllib2.HTTPError:
		print 'Symbol not found!\n'
		symbol = ask_symbol()
The error doesn't specify which line is the problem, so I have to guess. :(

edit: Hahahaha gently caress. It was the weeks thing that stopped it from working. :allears: Sorry about that.

I mean, well, option 'c' still doesn't work - but I think I know why, and it's unavoidable.

Pollyanna fucked around with this message at 21:16 on Sep 17, 2013

NtotheTC
Dec 31, 2007


Given a list of 10 players:

Python code:
    self.player_list = ["player1", "player2", ..., "player10"]
I want to get all possible combinations of 5player teams. My current solution is this:

Python code:
    def shuffle_teams(self):
        # Get list of distinct team combinationsw
        team_combos = list(combinations(self.player_list, 5))
        halfway_point = len(team_combos) / 2
        # Split list into halves, reversing second half lines up
        # team1 with it's team2 counterpart
        team1_list, team2_list = team_combos[:halfway_point], team_combos[:halfway_point-1:-1]
This solution relies on the fact that the ordering of the combinations() object is consistent (splitting the combo list in half and reversing the second half means that I get the unique matchups lined up).

Is there a better way of doing this?

NtotheTC fucked around with this message at 22:15 on Sep 17, 2013

evilentity
Jun 25, 2010

NtotheTC posted:

Python code:
	team_combos = list(combinations(self.player_list, 5))

Already give you all unique combinations. Whats your question again?

NtotheTC
Dec 31, 2007


Sorry I wasn't clear, that gives me the unique team combinations, but I want the unique MATCHUP combinations (team1 vs team2). For any given 5 man team combination in that list, it has it's counterpart (the team combination containing the other 5 players).

VVV Excellent, missed that in the docs. Thanks!

NtotheTC fucked around with this message at 10:10 on Sep 18, 2013

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

NtotheTC posted:

This solution relies on the fact that the ordering of the combinations() object is consistent (splitting the combo list in half and reversing the second half means that I get the unique matchups lined up).

From the itertools documentation:

quote:

Combinations are emitted in lexicographic sort order. So, if the input iterable is sorted, the combination tuples will be produced in sorted order.

Since the description of the function's behaviour specifies that the combinations will come out in the observed order, you are fine. (If the behaviour was merely observed, not explicitly specified, it would not be safe to rely upon it.)

Ireland Sucks
May 16, 2004

Is there a good resource out there for working with winsock in python? There don't seem to be any other options for working with Bluetooth devices using Python 3 (on Windows)

the wizards beard
Apr 15, 2007
Reppin

4 LIFE 4 REAL
Why winsock? Surely if you need sockets the socket module is a better choice? It has native Bluetooth support on Python3 http://docs.python.org/2/library/socket.html

Ireland Sucks
May 16, 2004

the wizards beard posted:

Why winsock? Surely if you need sockets the socket module is a better choice? It has native Bluetooth support on Python3 http://docs.python.org/2/library/socket.html

Not on Windows

code:
C:\Users\UserX\workspace\cblue>c:\python33\python.exe
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit (AM
D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RF
COMM)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'AF_BLUETOOTH'

Ireland Sucks fucked around with this message at 15:32 on Sep 19, 2013

the wizards beard
Apr 15, 2007
Reppin

4 LIFE 4 REAL

Ireland Sucks posted:

Not on Windows

code:
C:\Users\UserX\workspace\cblue>c:\python33\python.exe
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit (AM
D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RF
COMM)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'AF_BLUETOOTH'

I get the same result :( Googling says that Bluetooth isn't supported on Windows, that sucks. I guess you're stuck with talking to winsock with ctypes?

Ireland Sucks
May 16, 2004

the wizards beard posted:

I get the same result :( Googling says that Bluetooth isn't supported on Windows, that sucks. I guess you're stuck with talking to winsock with ctypes?

Yep, or turning everything into 2 and using the old pybluez module

the wizards beard
Apr 15, 2007
Reppin

4 LIFE 4 REAL

Ireland Sucks posted:

Yep, or turning everything into 2 and using the old pybluez module

Have you looked through the pybluez source? At some point it must wrap around the native Windows calls, you could just rip out some of the code?

nonathlon
Jul 9, 2004
And yet, somehow, now it's my fault ...
More of a docutils / restructured text / Sphinx question but maybe the solution involves Python:

So, I'm writing a book using Sphinx. That's all working well except that I would like to group the chapters into sections or parts: "Part 1 - The Basics" will include a number of chapters, "Part 2 - Advanced Use" will include the next batch of chapters and so on. But how to do this in Sphinx? One webpage I saw makes an oblique reference to document part headings, but I haven't tracked that down to specific markup. Any ideas? Is there something you can do with the table-of-contents?

(It strikes me that actually many books have a structure like this, except its reflected in the frontmatter and backmatter, i.e. the foreword and appendices etc.)

Goon Danton
May 24, 2012

Don't forget to show my shitposts to the people. They're well worth seeing.

I'm starting to learn Python in my free time after some exposure to C/C++ in college, and I have a question about if something would be feasible.

I'm going to write a program at work that would need to communicate with some old hardware via serial port. Basically all I'll need would be to send and receive data on that, and to have a GUI my coworkers would understand. Is this within reach for a Python3 novice with some experimentation? Also would the code need to be changed at all if we switched to a different version of Windows? The only reason I ask that last question is because our current program is written in Visual Basic and won't run on anything newer than Windows XP, which is one of the many reasons I'm replacing it.

BeefofAges
Jun 5, 2004

Cry 'Havoc!', and let slip the cows of war.

Nolanar posted:

I'm starting to learn Python in my free time after some exposure to C/C++ in college, and I have a question about if something would be feasible.

I'm going to write a program at work that would need to communicate with some old hardware via serial port. Basically all I'll need would be to send and receive data on that, and to have a GUI my coworkers would understand. Is this within reach for a Python3 novice with some experimentation? Also would the code need to be changed at all if we switched to a different version of Windows? The only reason I ask that last question is because our current program is written in Visual Basic and won't run on anything newer than Windows XP, which is one of the many reasons I'm replacing it.

That's all pretty easy, and it shouldn't require any modification to run on different versions of Windows. Without too much extra work the same code will even work in Linux and OS X. Check out PySerial, it's super easy to use.

Dren
Jan 5, 2001

Pillbug
It shouldn't be a problem. Break it up into two parts. First, write a command line app to do the serial interface control. Second, write the GUI. I suspect writing the GUI is going to be the hard part.

Pollyanna
Mar 5, 2005

Milk's on them.


So I said I was working on learning OOP, right? Well, I think I get the hang of classes and inheritance now. I coded a list of classes for that theoretical game I was talking about, and I was wondering if you guys could look at my code and see if I made any mistakes or if there's anything I could do better?

Python code:
# game-classes

# A list of classes and objects in the game.



class Mobile(object):

	"""Mobiles are entities or 'characters' on the field.
	Obviously, they don't have to be literally moving.
	You could maybe call a sign a mobile...
	But I'll get to that later.

	Attributes: typing"""

	def __init__(self, typing="I'm a mob!"):

		# self.typing: "Typing" method. Returns what kind of object this is.
		self.typing = typing


class Villager(Mobile):

	"""Villagers are other humans, and bear no ill will towards you.
	They live in villages (obviously) and some have certain professions.
	They are distinguished by having names and, for certain subclasses, hats.

	Attributes: typing, name"""

	def __init__(self, name="Generic Billy"):

		# self.name: "Name" method. Returns the name of the mobile.
		# They're all named Generic Billy unless given a particular name when created.
		super(Villager, self).__init__()
		self.name = name

class Civilian(Villager):

	"""Truth be told, there's nothing special about Civilians.
	Meaning, the difference between a generic Villager and a generic Civvie is small.
	Right now, they just inherit typing and name.
	Actually, maybe I'll give them a line to say...

	Attributes: typing, name, line"""

	def __init__(self, line = "Good luck on your quest!"):

		# self.line: "Line" method. Returns a line to say to the player.
		# Hey, they needed a reason to exist...
		super(Civilian, self).__init__()
		self.line = line

class Baker(Villager):

	"""The baker is, well, a baker. They bake bread and cakes and pastries.
	They wear a chef's hat, as in the big poofy ones.
	Right now, they're flavoring and don't say or do anything.

	Attributes: typing, name, hat"""

	def __init__(self, hat="Baker"):

		# self.hat: "Hat" method. Determines what hat they're wearing.
		# Actually, maybe this method should show up earlier in the class tree.
		super(Baker, self).__init__()
		self.hat = hat

class Blacksmith(Villager):

	"""The blacksmith creates weapons and armor for the player.
	They wear a welding mask to protect themselves from the heat.
	I plan to have them sell, upgrade, and scrap weapons and armor.

	Attributes: typing, name, hat"""

	def __init__(self, hat="Welder"):

		super(Blacksmith, self).__init__()
		self.hat = hat

class Chief(Villager):

	"""The chief is the leader of the village.
	He wears, uh...let's say a gold crown.
	Wouldn't that make him a king or something?
	Anyway, I plan to have him give out quests.

	Attributes: typing, name, hat"""

	def __init__(self, hat="Crown"):

		super(Chief, self).__init__()
		self.hat = hat



class Monster(Mobile):

	"""Ahh, monsters. They'll be trying to kill the player.
	You'll be able to kill them too, eventually.
	They all have a certain amount of initial HP.
	This is equal to max HP, unless it isn't.
	That'll depend on the kind of monster, though.

	Attributes: typing, name"""

	def __init__(self, name="Generic Goomba"):

		super(Monster, self).__init__()
		self.name = name

class Rat(Monster):

	"""Rats are the most basic enemy.
	They have 10 HP.
	They don't attack right now, but eventually they will.
	Mostly harmless. Maybe.

	Attributes: typing, name, HP"""

	def __init__(self, hp=10):

		# self.hp: "HP" method. Returns the hit points (HP) of an object.
		super(Rat, self).__init__()
		self.hp = hp

class Orc(Monster):

	"""Orcs are a mid-level enemy.
	They have 25 HP.
	They don't attack right now, but eventually they will.
	You should be familiar with these guys.

	Attributes: typing, name, HP"""

	def __init__(self, hp=25):

		super(Orc, self).__init__()
		self.hp = hp

class Dragon(Monster):

	"""Dragons are high-level enemies.
	They have 50 HP.
	They don't attack right now, but eventually they will.
	The ubiquitous end-game enemy. They're suitably tough.

	Attributes: typing, name, HP"""

	def __init__(self, hp=50):

		super(Dragon, self).__init__()
		self.hp = hp





class Item(object):

	"""Items are important, uh, items, that will help the player in their quest.
	They include (but are not limited to) weapons and potions.
	Each item has a certain amount associated with it.
	As in, how many of the item you have.

	Attributes: typing, amount"""

	def __init__(self, typing= "I'm an item!", amount = 1):

		self.typing = typing

		# self.amount: "Amount" method. Sets the amount you have of an item.
		self.amount = amount

class Weapon(Item):

	"""Weapons are used to defeat enemies.
	Eventually, I want to add durability and the ability to break them down.
	They deal a certain amount of HP damage, or power.
	That depends on what weapon it is, though.
	drat, uh...can I create an empty class, or does that not make sense?

	Attributes: typing, amount, stabbity"""

	def __init__(self, stabbity = "Stabbity status is TRUE!"):

		# self.stabbity: ...yeah, no, I'm gonna remove this eventually.
		super(Weapon, self).__init__()
		self.stabbity = stabbity

class Knife(Weapon):

	"""Knives are the most basic weapon.
	Small, but easy to use.
	They deal about 2 HP damage.

	Attributes: typing, amount, stabbity, power"""

	def __init__(self, power=2):

		# self.power = "Power" method. Amount of damage it deals.
		super(Knife, self).__init__()
		self.power = power

class Dagger(Weapon):

	"""Slightly larger and slightly more powerful than knives.
	Middle-of-the-road weapon.
	Probably the best for everyday enemy ganking.
	They deal about 5 damage.

	Attributes: typing, amount, stabbity, power"""

	def __init__(self, power=5):

		super(Dagger, self).__init__()
		self.power = power

class Sword(Weapon):

	"""Currently the most powerful weapon available.
	High power, relatively huge.
	They deal about 10 damage.
	I'm planning to have them come in either longsword or katana flavor.

	Attributes: typing, amount, stabbity, power"""

	def __init__(self, power=10):

		super(Sword,self).__init__()
		self.power = power



class Potion(Item):

	"""Potions are used for various things.
	Some heal health, some heal mana.
	Although right now, nothing uses mana.
	They are differentiated by their color.

	Attributes: typing, amount, color"""

	def __init__(self, color = "Generic Gray"):

		# self.color: "Color" method. Sets the color of a potion.
		super(Potion, self).__init__()
		self.color = color

class Health(Potion):

	"""Heals a certain amount of health points.
	Is associated with the health bar - which isn't implemented yet.
	Depending on the potion, it might be associated with one of two bars.
	Heals 5 health points.

	Attributes: typing, amount, color, points, bar"""

	def __init__(self, color="Red",points=5,bar="HP"):

		super(Health, self).__init__()

		self.color = color

		# self.points: "Points" method. Amount of HP or MP points healed.
		self.points = points

		# self.bar: "Bar" method. The bar associated with the potion (health or magic).
		self.bar = bar

class Mana(Potion):

	"""Heals a certain amount of mana points.
	Is associated with the mana bar - which isn't implemented yet.
	Heals 5 mana points.

	Attributes: typing, amount, color, points, bar"""

	def __init__(self, color="Blue", points=5, bar="MP"):

		super(Mana, self).__init__()

		self.color = color

		self.points = points

		self.bar = bar

class Water(Potion):

	"""A flask of water.
	Does nothing. Doesn't heal HP or MP, anyway.
	If you drink it, you drink water. Duh.
	That may have more significance later on.

	Attributes: typing, amount, color"""

	def __init__(self, color = "Clear"):

		super(Water, self).__init__()

		self.color = color
edit: Code was slightly incorrect. Fixed.

What's bugging me is that doing

Python code:
sally = Civilian(name="Sally",line="Hi! I\'m Sally!")

print sally.name
results in an error. Doesn't it inherit the name attribute from Villager()? So why doesn't it have the attribute?

Pollyanna fucked around with this message at 06:33 on Sep 21, 2013

Kumquat
Oct 8, 2010
I'm more of a beginner than you are so sorry if I'm off base here: You define the Civilian init function without using super to also call the parent class' init (where name is established).

Pollyanna
Mar 5, 2005

Milk's on them.


Yup, that was part of the problem. :shobon: I just updated to reflect that. But I still have an issue where I can't do sally = Civilian(name="Sally",line="Hi! I\'m Sally!") without it bitching that name is an unknown argument. Why?

Kumquat
Oct 8, 2010
http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ check the code example under "Practical Advice" to see how you can use **kwargs to pass your extra arguments up to the super.__init__. Sorry for badposting, I've only got my phone at the moment. Hope this helps.

Pollyanna
Mar 5, 2005

Milk's on them.


Kumquat posted:

http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ check the code example under "Practical Advice" to see how you can use **kwargs to pass your extra arguments up to the super.__init__. Sorry for badposting, I've only got my phone at the moment. Hope this helps.

Yayyyyy that fixed it :3: Thankee!!!!

God, this is complicated as gently caress.

edit:

I've actually just thought of something: Is there a way to just write a list of monsters and their attributes in like a .txt file, and just have mobs.py bring in the stuff from there? Or does that not make sense? Seems like kind of a pain in the rear end to have to add a new class every time I want to add a type of monster.

Pollyanna fucked around with this message at 07:58 on Sep 21, 2013

QuarkJets
Sep 8, 2008

Pollyanna posted:

Yayyyyy that fixed it :3: Thankee!!!!

God, this is complicated as gently caress.

edit:

I've actually just thought of something: Is there a way to just write a list of monsters and their attributes in like a .txt file, and just have mobs.py bring in the stuff from there? Or does that not make sense? Seems like kind of a pain in the rear end to have to add a new class every time I want to add a type of monster.

I don't see how that would save time; you'd be loading the information from a text file (expensive) and then doing the same stuff with it as you already are. A better alternative might be to just have a Monster class with a type attribute that can be set to "Orc" or "Goblin" or whatever. If all monsters behave fundamentally the same and only differ by name, then this is fine. If you want Orcs and Goblins to have different abilities, then it may make more sense to make them unique classes and then spawn several instances of them (goblin1, orc1, orc2, etc).

Your example code would be great for a village where you want to have several bakers, several blacksmiths, etc. If you just want one of each then it might not be necessary to have a class for each; you could just have a "profession" attribute. So let's say that you want all villagers to pop up some sort of dialog box when the player interacts with them. You'd put that code into the Villager class. But you also want some villagers to have a merchant interaction. You'd create a new class called Merchant, have it inherit from Villager, and then code up the merchant interactions inside of the Merchant class. Now you have villagers that can create dialog boxes and merchants that can create dialog boxes or merchant windows.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
You'll quickly find out that inheritance for behavior like that is going to become unusable for many reasons, but this can really only be understood once you do it wrong first, so I'll let you do that.

Don't be afraid of being messy and putting numbers like "orcs have 20 HP" in the code for now; getting your game up and running is much more important than designing the best code in the world. Code is code; you can always change it later, and you can always change it to read from an external file later so that different orcs have different HPs.

Opinion Haver
Apr 9, 2007

Suspicious Dish posted:

You'll quickly find out that inheritance for behavior like that is going to become unusable for many reasons, but this can really only be understood once you do it wrong first, so I'll let you do that.

Why is that? I've never built any kind of large game or whatever in an OO language.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

After reading these posts on my phone, I was going to post basically what Dish said when I got home.

I don't know what he had in mind, but one thing that comes to mind when doing OO in a game is that it becomes kind of hard to reason about.

A good google search is "composition versus inheritance".

NtotheTC
Dec 31, 2007


I remember a blog from a while ago written by an ex-Blizzard dev talking about Starcraft development and the problems they faced using inheritance. I think he talked about composition over inheritance too.

Correct me I'm wrong though but I thought the main problem with this sort of thing came from the multiple inheritance/diamond problem? Does Python's Method Resolution Order not take care of that in this instance?

E: Found the blog

NtotheTC fucked around with this message at 18:01 on Sep 21, 2013

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

yaoi prophet posted:

Why is that? I've never built any kind of large game or whatever in an OO language.

The big reason is that inheritance is hard to change once built.

You can easily change ORC_HP to self.hp if you want to load that from somewhere else, but it's not so easy to unwind all the various little pieces of code you're reusing from a subclass and split that out.

This is a problem with all things using OOP, but it's even worse in games because the inheritance tends to model intuition rather than code reuse and the Liskov substitution principle. As an example, "Orc extends Monster" sounds fairly sane, but if Orc is the class that does the animating of the Orc sprite, and Monster is the class that makes enemies fightable, it might be hard to make an Orc NPC that you talk to and roams around town.

Try splitting out the Orc animation code into a separate class and unwinding everything that has to do with that without breaking your game.

Pollyanna
Mar 5, 2005

Milk's on them.


QuarkJets posted:

I don't see how that would save time; you'd be loading the information from a text file (expensive) and then doing the same stuff with it as you already are. A better alternative might be to just have a Monster class with a type attribute that can be set to "Orc" or "Goblin" or whatever. If all monsters behave fundamentally the same and only differ by name, then this is fine. If you want Orcs and Goblins to have different abilities, then it may make more sense to make them unique classes and then spawn several instances of them (goblin1, orc1, orc2, etc).

Your example code would be great for a village where you want to have several bakers, several blacksmiths, etc. If you just want one of each then it might not be necessary to have a class for each; you could just have a "profession" attribute. So let's say that you want all villagers to pop up some sort of dialog box when the player interacts with them. You'd put that code into the Villager class. But you also want some villagers to have a merchant interaction. You'd create a new class called Merchant, have it inherit from Villager, and then code up the merchant interactions inside of the Merchant class. Now you have villagers that can create dialog boxes and merchants that can create dialog boxes or merchant windows.

Suspicious Dish posted:

You'll quickly find out that inheritance for behavior like that is going to become unusable for many reasons, but this can really only be understood once you do it wrong first, so I'll let you do that.

Don't be afraid of being messy and putting numbers like "orcs have 20 HP" in the code for now; getting your game up and running is much more important than designing the best code in the world. Code is code; you can always change it later, and you can always change it to read from an external file later so that different orcs have different HPs.

Oh :saddowns:

Yeah, you might be right. I somehow got confused and made the different types of monsters their own subclasses, when being objects is more obvious. Hmm...I'll try rewriting the code. Thanks!

And yeah, this probably isn't a huge big ol' project like I'm actually making a game. I'm trying to see if I "get" OOP. Although, maybe I will make something more of it...

Suspicious Dish posted:

The big reason is that inheritance is hard to change once built.

You can easily change ORC_HP to self.hp if you want to load that from somewhere else, but it's not so easy to unwind all the various little pieces of code you're reusing from a subclass and split that out.

This is a problem with all things using OOP, but it's even worse in games because the inheritance tends to model intuition rather than code reuse and the Liskov substitution principle. As an example, "Orc extends Monster" sounds fairly sane, but if Orc is the class that does the animating of the Orc sprite, and Monster is the class that makes enemies fightable, it might be hard to make an Orc NPC that you talk to and roams around town.

Try splitting out the Orc animation code into a separate class and unwinding everything that has to do with that without breaking your game.

Er...so, how would you say I should structure my code? Here's a cleaned up version of my items:

Python code:
# game-classes

# A list of classes and objects in the game.



class Item(object):

	"""Items are important, uh, items, that will help the player in their quest.
	They include (but are not limited to) weapons and potions.
	Each item has a certain amount associated with it.
	As in, how many of the item you have.

	Attributes: typing, amount"""

	def __init__(self, typing= "I'm an item!", amount = 1):

		self.typing = typing

		# self.amount: "Amount" method. Sets the amount you have of an item.
		self.amount = amount

class Weapon(Item):

	"""Weapons are used to defeat enemies.
	Eventually, I want to add durability and the ability to break them down.
	They deal a certain amount of HP damage, or power.
	That depends on what weapon it is, though.

	Attributes: typing, amount, power"""

	def __init__(self, power=2, *args, **kwargs):

		super(Weapon, self).__init__(*args, **kwargs)
		self.power = power

class Potion(Item):

	"""Potions are used for various things.
	Some heal health, some heal mana.
	Although right now, nothing uses mana.
	They are differentiated by their color.

	Attributes: typing, amount, color, points, bar"""

	def __init__(self, color = "Generic Gray", points=0, bar=None, *args, **kwargs):

		# self.color: "Color" method. Sets the color of a potion.
		super(Potion, self).__init__(*args, **kwargs)
		self.color = color
		self.points = points
		self.bar = bar
Does this make more sense? Now I have my list of classes in a subdirectory, and I can call:

Python code:
from classes import mobs
from classes import items

sally = mobs.Villager(name="Sally", line="Hello there!")

print sally.name
print sally.line
print sally.hat

print "\n"

water = items.Potion(color="Clear")

print water.color
print water.points
and get:

code:
Sally
Hello there!
None


Clear
0

Pollyanna fucked around with this message at 21:36 on Sep 21, 2013

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Pollyanna posted:

Er...so, how would you say I should structure my code? Well, let me get back to you once I clean my code up a bit...

There's many different ways to do it, and even AAA games haven't found something that works 100%. What I would do highly depends on the kind of game and the scale of the project. If I was making an action RPG-style game a la Zelda or Ys, I'd probably try a component-based style -- split out the idea of "animation" from "behavior". So an enemy orc you can fight is a combination of an "Orc animation" and an "Orc behavior".

This is just some basic thoughts, though. If I actually sat down and made an ARPG-type game, I'd probably find that there are lots of problems with it, especially when movement and animation are tied together highly, and that fighting style and movement go hand in hand. Perhaps I'd write a generic state-based animation system that still keeps the split, but all the behavior does is say "display the 'running left' state please" and the animation system paints the frames of the Orc running left.

As I said before, the important thing is to get your game up and running, and when you find it's too fragile, sit down and think about what the issues with your codebase are, and work towards fixing them.

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Pollyanna posted:

Er...so, how would you say I should structure my code? Here's a cleaned up version of my items:

(sorry; didn't see the edit)

I'm not exactly sure what the "typing" attribute is.

I wouldn't have a amount associated with each item, but instead, naturally have an "amount" by representing each instance of an item with... its own instance:

Python code:
class GreenPotion(object):
    def use(self, hero):
        # green potions heal 20 magic points
        hero.magic += 20

# ...

inventory = [ GreenPotion(), WarpItem(), GreenPotion(), RedPotion() ]

# user selects first item in inventory
used_item = inventory[0]
used_item.use(hero)
Also, it depends on how your game is designed, but I probably wouldn't model weapons as items.

  • Locked thread