Skip to content

Instantly share code, notes, and snippets.

@atiaxi
Created December 15, 2014 18:24
Show Gist options
  • Save atiaxi/7762693650ed2cbcbd24 to your computer and use it in GitHub Desktop.
Save atiaxi/7762693650ed2cbcbd24 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#### PEP8: Module names should be lowercase, e.g. `chromeconomist.py`
#-------------------------------------------------------------------------------
# Name: module1
# Purpose:
#
# Author: James Boggs
#
# Created: 10/04/2014
# Copyright: (c) James Boggs 2014
# Licence: <your licence>
#-------------------------------------------------------------------------------
#### You probably should update this comment :)
import EconBuffs
import time
import datetime
import praw
import json
import string
from inflect import *
#### PEP8: It's usually bad form to do wild imports. I haven't used inflect so I'm not sure what
#### functions in this file are using it, but even if it's lots you can do multi-line imports.
class bot(object):
#### PEP8: class names usually start uppercase, e.g. 'Bot'. Unlike the other style stuff,
#### this particular one is a little confusing for reasons I'll get into in a bit
def __init__ (self, reddit,EconomistInfo):
#### PEP8: ordinary variable names tend to be lowercase, e.g. `economist_info`
self.log = open("ChromeconomistRunLog.txt","w+")
#### Rolling your own logging like this can work fine, but there are problems in
#### the way you're using it that I'll mention later. Python has some built-in
#### logging that works pretty well (I'm using it in Chromabot)
#### https://docs.python.org/2/howto/logging.html as an intro.
self.lands = ["midnight marsh","cote d'azure","oraistedearg"]
bot.log(self,"Lands: "+self.lands.__str__())
#### You should never need to call `__str__` on something; the built-in function
#### `str` does the equivalent, e.g. `str(self.lands)`.
#### This is also a good candidate for string interpolation.
####
#### Now I'll explain the logging and PEP8 weirdness:
#### You're calling the function `log` on the class `bot`.
#### The PEP8 weirdness is that the all-lowercase makes
#### this look like `bot` is an instance rather than a class itself
#### The other weirdness is that you're passing 'self' as the first
#### argument to 'bot.log', which you shouldn't have to do. Since
#### `log` is a function like any other function in the class, you
#### should be doing `self.log("Lands: "...)`
#### This should be applied anywhere you do `bot.log`, which is a lot of
#### places, so I won't point them all out since you might just switch
#### over to python logging anyway.
self.landInfo = EconomistInfo["LandInfo"]
self.userInfo = EconomistInfo["UserInfo"]
self.itemInfo = EconomistInfo["ItemInfo"]
self.data = {"LandInfo":self.landInfo,"UserInfo":self.userInfo,"ItemInfo":self.itemInfo}
bot.log(self,"JSON info loaded")
self.r = reddit
bot.log(self,"Connected to Reddit")
self.i = engine()
self.trade_number = 0
self.active_trades = dict()
#### It doesn't look like you're persisting this anywhere; this means that any time the bot
#### stops for any reason, all outstanding trades will be forgotten.
self.recruit_id = '2bfmr6'
self.mods = ['eliminioa','danster21','zthousand','twilight_octavia','cdos93','dalek1234']
bot.iterate(self)
def parseLand(self,land):
#### PEP8: parse_land
self.curSub = self.r.get_subreddit(self.landStats['srname'])
print self.curSub
#### Debug line, I'm assuming
bot.log(self,"Current sub: "+self.curSub.__str__())
#### As above, don't need `__str__`, can use interpolation
comments = self.r.get_comments(self.curSub,limit=None)
#### If your thread has over a certain number of comments (I think 200 by default),
#### you'll get a mixture of `Comment` and `MoreComments` objects rather than just
#### comments. MoreComments doesn't support a lot of the things that `Comment` does;
#### it's a placeholder for having to go back to the server and ask for more comments.
#### you can do all that now using a PRAW helper called `replace_more_comments`
#### Also: As written, this function will only consider top-level comments. (This
#### may be as intended, in which case don't worry about it :)
#### This is also a good spot to consider using @failable
bot.log(self," Comment generator:" +comments.__str__())
#### As above, don't need `__str__`, can use interpolation
BotCommands = [] #bot command will be a list [author(str),action,resource]
placeholder_ID = self.landInfo[land]["placeholder_ID"]
#### PEP8 for both these lines: variable names are lowercase, e.g. `bot_commands` and `placeholder_id`
for comment in comments:
if comment.id == placeholder_ID:
bot.log(self," Arrived at placeholder!\n")
print ("Arrived at placeholder!")
#### Debug line, I'm guessing
ref_id = comment.id
#### You set this but don't appear to be using it
break
if ("#" in comment.body.lower()):
#### No real need to lowercase the body in this case, given that '#' is case-insensitive :)
if len(BotCommands) == 0: #stores the comment id of the first new comment for reference
ref_id = comment.id
bot.log(self," Updated placeholder id to "+str(ref_id)+" @ "+str(time.asctime(time.gmtime(comment.created))))
#### This is the line I used as an example of string interpolation :)
self.landInfo[land]["placeholder_ID"] = ref_id
self.data["LandInfo"] = self.landInfo
if str(comment.author).lower() not in self.userInfo:
print ("User "+str(comment.author).lower()+" not found")
bot.log(self," User "+str(comment.author).lower()+" not found, alerting")
#### String interpolation, the print statement is probably redundant
comment.reply('User not found! Please register for the Chromeconomist bot [here](http://redd.it/'+self.recruit_id+')')
#### String interpolation, failable
bot.log(self," New command found: "+comment.__str__())
#### Interpolation
rawCmd = comment.body.splitlines()
for line in rawCmd:
if '#' in line:
cmdLine = line.strip('#')
#### `strip` only works for `#` at the beginning or end of the line.
#### If someone puts a `#` in the middle of the line, it'll remain there.
break
cmdParts = cmdLine.split()
cmdTime = comment.created
bot.log(self," Command time: "+str(time.asctime(time.gmtime(comment.created))))
#### Interpolation
author = str(comment.author).lower()
action = cmdParts[0].lower()
action = action.strip(string.punctuation)
#### I'm not sure in what circumstances punctuation would end up in the action
resource = cmdParts[1:]
command = [author,action,resource,cmdTime,comment]
#### It may be worthwhile to change this to a full-fledged class; packing and
#### unpacking this information in a list can be brittle.
bot.log(self," Parsed command as "+command.__str__())
#### Interpolation
BotCommands.append(command)
bot.parseCommands(self,BotCommands)
def parsePMs(self,PMCommands):
#### PEP8: parse_pms
####
#### I'm not going to full-review all of this function, because it's extremely similar to parseLand, above
#### Having extremely similar code in more than one place like this is generally a bad idea; if you change
#### anything in one command you have to remember to change it everywhere. I'd recommend refactoring
#### the parsing out into its own function that both parsePMs and parseLand call.
BotCommands = []
for PM in PMCommands:
#### PEP8: Variable names again: `pm`, `pm_commands` and `bot_commands`
author = str(PM.author)
author = author.lower()
if author not in self.userInfo:
print ("User "+author+" not found")
bot.log(self," User "+author+" not found, alerting")
PM.reply('User not found! Please register for the Chromeconomist bot [here](http://redd.it/'+self.recruit_id+')')
### Interpolation for these three, print probably redundant
cmdParts = PM.body.split()
bot.log(self,"Command parts: "+str(cmdParts))
cmdTime = PM.created
bot.log(self," Command time: "+str(time.asctime(time.gmtime(PM.created))))
action = cmdParts[0].lower()
action = action.strip(string.punctuation)
resource = cmdParts[1:]
command = [author,action,resource,cmdTime,PM]
bot.log(self," Parsed command as "+command.__str__())
BotCommands.append(command)
bot.parseCommands(self,BotCommands)
def parseCommands(self,BotCommands):
#### PEP8: parse_commands, bot_commands
for command in BotCommands:
author = command[0]
action = command[1]
resource = command[2]
cmdTime = command[3]
comment = command[4]
#### As mentioned above, the 'command' list might be more useful as a class, in which case you could
#### do things like e.g. command.author, command.action, etc.
#### However, if you don't want to do that, there's also a faster way to do what you're doing above
#### via unpacking:
#### author, action, resource, cmdTime, comment = command
#This is the part which reads prodcuce commands. DONE as of 6/6/2014
if action == 'produce':
bot.change_production(self,author,resource[0].strip(string.punctuation),comment)
#### This is the same problem as with the logging; it should be `self.change_production(author, ...)`
print (author +" changed their resource to "+resource[0]+"\n")
bot.log(self,author +" changed their resource to "+resource[0])
#### Interpolation, redundant print
#This is the part which reads creation commands. DONE as of 15/6/2014
elif action == 'create':
print ("User "+author+" is creating "+str(resource[0])+" "+resource[1]+"s")
bot.log(self,"User "+author+" is creating "+str(resource[0])+" "+self.i.plural_noun(resource[1],resource[0]))
#### Interpolation, redundant print
self.userInfo[author]["last_creation"] = cmdTime
bot.create(self,author,int(resource[0]),resource[1],comment)
#this reads balance display commands, and replies to the user with their account summary. DONE as of 7/1/2014
elif action == 'balance':
messageStr = "Hello "+author+", your account balance stands as follows:\n\n-----\n\n"
for item in self.userInfo[author]:
if item in ["last_produced","last_creation","producing","home"]:
continue
#### Having regular entries like 'last_produced' and 'home' alongside all the other
#### balances is a little strange; any time you add more metadata to the userInfo,
#### you'll have to add it to this list above and everywhere else you have this
#### list in the entire codebase.
#### I'd recommend putting balances one level deeper, e.g.
#### `userInfo[author]['balances']`; then it's safe to just iterate over those balances
#### and it's easy to add whatever else you need to userInfo without worrying about
#### keeping it in mind everywhere.
messageStr = messageStr + " "+self.i.plural_noun(item,self.userInfo[author][item])+": "+str(self.userInfo[author][item])+'\n\n'
time_to_production = datetime.timedelta(seconds=(self.userInfo[author]["last_produced"]+300-time.time()))
messageStr = messageStr + "-----\n\nYou will produce "+self.userInfo[author]["producing"]+" in "+str(time_to_production)+"."
#### This entire section is a good candidate for string interpolation, but there's an additional reason I
#### didn't go over in my initial message: repeatedly concatenating strings together tends to waste
#### a lot of memory; it creates an intermediate string for every '+', and each time you add on that
#### intermediate string gets bigger. That memory's not lost, it'll be reclaimed eventually, but
#### it's more than you need and can slow things down. The best practices are to, instead, put all
#### the messages in a list and then join that list, e.g.
####
#### messages = []
#### messages.append("Hello %s, your account balance stands as follows:\n\n-----\n\n" % author)
#### ...
#### comment.reply("\n".join(messages))
comment.reply(messageStr)
#this reads trading commands. A brief preface, becaus this command is a bit trickier than the rest DONE as of 7/15/2014:
#trade command is "trade [count] [item] for [count] [item] with [user]" therefore:
#resource[0] = the number of items the user is trading away
#resource[1] = the type of item the user is trading away
#resource[3] = the number of items the user is trading for
#resource[4] = the type of item the user is trading for
#resource[6] = the player the user is trading with
elif action == 'trade':
if resource[0] == 'accept':
trade_num = int(resource[1].strip("#"))
print (author+" has accepted trade offer #"+str(trade_num))
bot.log(self,author+" has accepted trade offer #"+str(trade_num))
#### Interpolation, redundant print/logging
bot.accept_trade_offer(self,author,trade_num)
else:
print (author+" is trying to trade "+str(resource[0])+" "+self.i.plural(resource[1],resource[0])+" for "+str(resource[3])+" "+self.i.plural(resource[4],resource[3])+" with "+resource[6])
bot.log(self,author+" is trying to trade "+str(resource[0])+" "+self.i.plural(resource[1],resource[0])+" for "+str(resource[3])+" "+self.i.plural(resource[4],resource[3])+" with "+resource[6])
#### Interpolation, redundant print/logging
bot.make_trade_offer(self,author,resource[:7],comment)
#this allows me to add items. DONE as of 7/24/14
#command resources:
#resource[0] = the name of the new item
#resource[1] = cost in format {"item":cost,"item":cost,etc}
#resource[2] = pre-reqs in format ("item","item",etc)
elif action =='add' and str(author)=='eliminioa':
print ('Adding '+resource[0])
bot.add_item(self,resource,comment)
else:
print ('"'+action+'" command is not ready yet!')
#this function parses a "produce" command, altering what the user produces every iteration
def change_production(self,author,resource,comment):
material_keywords = ["wood","lumber","stone","stones","brick","bricks","material","materials"]
luxury_keyowrds = ["gold","diamonds","pearls","ivory","silk","spice","spices","pearl","chocolate","luxury","luxuries"]
if resource in material_keywords:
resource = "material"
elif resource in luxury_keyowrds:
resource = "luxury"
else:
resource = 'food'
#### I'm assuming the specific kind of resource doesn't matter? You've overwriting e.g. 'brick' with 'material'.
self.userInfo[author]["producing"] = resource
self.data["UserInfo"] = self.userInfo
comment.reply("You are now producing "+resource)
#### Failable
#this function credits a user with produced goods every iteration
def produce(self,author):
if time.time() < self.userInfo[author]["last_produced"]+60:
bot.log(self," User "+author+" has already produced something this hour.")
#### Interpolation, but also depending on how often this runs you're doing to see a loooot
#### of this in the logs (one per user, per iteration)
return False
self.userInfo[author]["last_produced"] = time.time()
resource = self.userInfo[author]["producing"]
bot.log(self," Producing "+resource+" for "+author)
bonus = self.landInfo[self.userInfo[author]["home"]]["bonus"]
bot.log(self," Land bonus: "+bonus)
penalty = self.landInfo[self.userInfo[author]["home"]]['penalty']
bot.log(self," Land penalty: "+penalty)
#this part determines whether the amount a user receives is influenced by their homeland
if bonus == resource:
bonusNum = 1.5
elif penalty == resource:
bonusNum = .5
else:
bonusNum = 1
for bonus_item in self.itemInfo["craftBuffs"]: # this part needs work. Needs to apply production bonus to the right resource(s)
if bonus_item in self.userInfo[author]:
BICount = self.userInfo[author][bonus_item]#amount of the bonus item user has
bonusNum += self.itemInfo["craftBuffs"][bonus_item] * BICount
bot.log(self," "+author+" has "+str(BICount)+" "+bonus_item+"s, which grants them "+str(self.itemInfo["craftBuffs"][bonus_item] * BICount)+" more production!")
bot.log(self," Bonus multiplier: "+bonusNum.__str__())
bounty = 1*bonusNum
#### Multiplying by one doesn't really do much :)
bot.log(self," Produced resources: "+bounty.__str__()+" "+resource)
self.userInfo[author][resource] += bounty
self.data["UserInfo"] = self.userInfo
return True
#### You don't seem to actually use this return value anywhere
#as titled, this function parses a create command, credits the user with their items, and subtracts the appropriate ammount of resources
def create(self,author,amount,item,comment):
if self.i.singular_noun(item):
item = self.i.singular_noun(item)
bot.log(self," Item to be created: "+item)
bot.log(self," Amount to be created: "+str(amount))
try:
itemCost = self.itemInfo[item]
except KeyError:
comment.reply("The item you're trying to make isn't a thing yet. Sorry.")
return None
#### `None` is actually the default if you just do a `return`
bot.log(self," Item cost: "+str(itemCost))
good_for_it = True #can the user pay for it?
#actually make the user pay for it
for material in itemCost:
count = float(itemCost[material])*amount
bot.log(self," "+item+" requires "+str(count)+' '+self.i.plural_noun(material,count))
if material in self.userInfo[author].keys():
userAmount =self.userInfo[author][material]
else:
userAmount = 0
bot.log(self," User has "+str(userAmount)+" "+self.i.plural_noun(material,userAmount))
if userAmount < count:
messageStr ="You do not have enough "+material+" to make "+str(amount)+" "+item+"."
comment.reply(messageStr)
#### Failable
bot.log(self," Informed user that they do not have sufficient resources.")
good_for_it = False
if good_for_it:
for material in itemCost:
self.userInfo[author][material] -= int(itemCost[material])*amount #takes away cost for each item before crediting
bot.log(self," User's new amount of "+self.i.plural_noun(material,userAmount)+" is "+str(userAmount))
#debuffs a region if the material used was a buffer
if material in self.itemInfo['combatBuffs'].keys():
buffedLand = self.userInfo[author]['home'] #get the land to be buffed, based on the creator's homeland
self.landInfo[buffedLand]['DEFbuff'] -= self.itemInfo['combatBuffs'][material] * int(itemCost[material])*amount #add the proper buff to the land
if good_for_it:
#### This 'if' statement is redundant, as you already checked above
if item not in self.userInfo[author].keys():
self.userInfo[author][item] = 0
self.userInfo[author][item] = self.userInfo[author][item] + amount #credits item to user
self.data["UserInfo"] = self.userInfo
bot.log(self," Credited "+str(amount)+" "+self.i.plural_noun(item,amount)+" to "+author)
comment.reply("You have successfully created "+str(amount)+" "+self.i.plural_noun(item,amount)+" for "+str(count)+" "+self.i.plural_noun(material,count)+"!")
print (author + " successfully created "+str(amount)+" "+self.i.plural_noun(item,amount)+" for "+str(count)+" "+self.i.plural_noun(material,count)+"!")
bot.log(self," Sent completion message to "+author)
#this part checks to see if the item created is a buff giving item like a wall
if item in self.itemInfo['combatBuffs'].keys():
buffedLand = self.userInfo[author]['home'] #get the land to be buffed, based on the creator's homeland
self.landInfo[buffedLand]['DEFbuff'] += self.itemInfo['combatBuffs'][item] * amount #add the proper buff to the land
else:
print "User not good for it."
def make_trade_offer(self,author,trade_info,comment):
bot.log(self," User initiating trade: "+author)
outCount = float(trade_info[0])
bot.log(self," Number of items to be traded: "+str(outCount))
outItem = self.i.singular_noun(trade_info[1])
if not outItem:
outItem = trade_info[1]
bot.log(self," Type of item to be traded: "+outItem)
inCount = float(trade_info[3])
bot.log(self," Number of items to be traded for: "+str(inCount))
inItem = self.i.singular_noun(trade_info[4])
if not inItem:
inItem = trade_info[4]
bot.log(self," Type of item to be traded for: "+outItem)
toUser = trade_info[6]
bot.log(self," User to trade with: "+toUser)
outGFI = self.userInfo[author][outItem]>=outCount
bot.log(self," Initiating User is good for it: "+str(outGFI))
inGFI = self.userInfo[toUser][inItem]>=inCount
#### There should probably be logic here to check that toUser is actually someone registered with the bot;
#### otherwise this part will KeyError
bot.log(self," Receiving User is good for it: "+str(inGFI))
self.trade_number += 1
bot.log(self," Trade #"+str(self.trade_number))
if outGFI and inGFI:
comment.reply('Sending trade offer to '+toUser+".")
bot.log(self,' Sending trade off to '+toUser+'.')
trade_message = '/u/'+author+' has sent you the following trade offer:\n\n trade your '+str(inCount)+' '+self.i.plural(inItem,inCount)+' for his '+str(outCount)+' '+self.i.plural(outItem,outCount)+'\n\nYour current balance is:\n\n'
#### PEP8 recommends that line lengths be 80 characters or below. I haven't checked this
#### everywhere but this line is pretty obvious :)
for item in self.userInfo[author]:
if item in ["last_produced","last_creation","producing","home"]:
continue
trade_message += " "+self.i.plural_noun(item,self.userInfo[author][item])+": "+str(self.userInfo[author][item])+'\n\n'
trade_message += '-----\n\nTo accept this offer, reply to this message with\n\n>trade accept #'+str(self.trade_number)
#### As above, using interpolation and string joining on lists will help this
self.r.send_message(toUser,'Trade Offer From '+author.capitalize(),trade_message)
#### Failable
self.active_trades[self.trade_number]=(author,trade_info,comment)
return True
else:
comment.reply('One of you doesn\'nt have enough resources to complete this trade!')
#### Failable; also you can use double quotes here so you don't have to escape the single quote
bot.log(self," One of the parties can't fulfill the trade requirements.")
return False
def accept_trade_offer(self,author,trade_num):
#author is the user who is accepting the trade
#tAuthor is the user who initiated the trade
trade_data = self.active_trades[trade_num]
#### Need to check here to make sure the comment supplied a valid trade number
tAuthor = trade_data[0]
trade_info = trade_data[1]
tComment = trade_data[2]
#### Also, there should probably be a check that the author is the one who
#### actually initiated the trade in the first place; otherwise you can
#### accept any trade offer, no matter who it was offered to.
bot.log(self," User: "+author)
inCount = float(trade_info[0])
bot.log(self," Number of items to be received: "+str(inCount))
inItem = self.i.singular_noun(trade_info[1])
if not inItem:
inItem = trade_info[1]
bot.log(self," Type of item to be received: "+inItem)
outCount = float(trade_info[3])
bot.log(self," Number of items to be traded out: "+str(outCount))
outItem = self.i.singular_noun(trade_info[4])
if not outItem:
outItem = trade_info[4]
bot.log(self," Type of item to be traded out: "+outItem)
#add the inbound items to the recipient's inventory
try: self.userInfo[author][inItem] += inCount
except: self.userInfo[author][inItem] = inCount
#### Style-wise, this should definitely be broken up to four lines
#### Similarly, no wild 'except's; I'm guessing you're checking for `KeyError`
#this part checks to see if the item traded is a buff giving item like a wall
if inItem in self.itemInfo['combatBuffs'].keys():
#get the land to be buffed, based on the creator's homeland
buffedLand = self.userInfo[author]['home']
#add the proper buff to the land
self.landInfo[buffedLand]['DEFbuff'] += self.itemInfo['combatBuffs'][inItem] * inCount
#add the outbound items to the initiator's inventory
try: self.userInfo[tAuthor][outItem] += outCount
except: self.userInfo[tAuthor][outItem] = outCount
#### As above re: style, excepts
#this part checks to see if the item traded is a buff giving item like a wall
if outItem in self.itemInfo['combatBuffs'].keys():
#get the land to be buffed, based on the creator's homeland
buffedLand = self.userInfo[tAuthor]['home']
#add the proper buff to the land
self.landInfo[buffedLand]['DEFbuff'] += self.itemInfo['combatBuffs'][outItem] * outCount
#subtract the outbound items from the users' inventories
self.userInfo[author][outItem] -= outCount
if outItem in self.itemInfo['combatBuffs'].keys():
buffedLand = self.userInfo[author]['home']
self.landInfo[buffedLand]['DEFbuff'] -= self.itemInfo['combatBuffs'][outItem] * outCount
self.userInfo[tAuthor][inItem] -= inCount
if inItem in self.itemInfo['combatBuffs'].keys():
buffedLand = self.userInfo[tAuthor]['home']
self.landInfo[buffedLand]['DEFbuff'] -= self.itemInfo['combatBuffs'][inItem] * outCount
self.data["UserInfo"] = self.userInfo
tComment.reply('Trade completed!')
def add_item(self,resource,comment):
name = resource[0]
try:
cost = json.loads(resource[1])
except:
#### As before, wild `except` should be avoided
comment.reply("JSON format incorrect. Read up on JSON [here](http://json.org/) and use [this](http://www.jsoneditoronline.org/) to do it easier.")
if name not in self.itemInfo.keys():
self.itemInfo[name] = cost
self.data["ItemInfo"] = self.itemInfo
comment.reply("Added "+name+" to the item database for a cost of "+str(cost)+".")
else:
comment.reply("This is already an item!")
def register(self):
thread = self.r.get_submission(submission_id = self.recruit_id,comment_sort = 'new')
#### Failable
cmnts = thread.comments
#### As before, this'll have mixed Comment and MoreComments
recruit_links = self.userInfo.keys()
for cmnt in cmnts:
if str(cmnt.author).lower() not in recruit_links:
parts = cmnt.body.split()
try:
for part in parts:
if '#' in part:
raw_base = part
base = raw_base.strip('#')
base = base.replace('-',' ')
base = base.replace('_',' ')
base = base.replace('/r/','')
base = base.replace('r/','')
base = base.lower()
#### You do this same thing in ChromabotListener; you can either use that function directly
#### or refactor it out to a common utils.
if base not in self.landInfo.keys():
base = 'midnight marsh'
cmnt.reply('No base set, defaulting to the [Midnight Marsh](/r/MidnightMarsh)')
except ValueError:
base = 'midnight marsh'
cmnt.reply('No base set, defaulting to the [Midnight Marsh](/r/MidnightMarsh)')
print ("Adding new user "+str(cmnt.author).lower()+" to userInfo with citizenship in "+base+"!")
bot.log(self,"Adding new user "+str(cmnt.author).lower()+" to userInfo with citizenship in "+base+"!")
self.userInfo[str(cmnt.author).lower()]={"food": 0, "material": 0, "luxury": 0,"last_produced":0.0,"last_creation":0,"producing":'material',"home":base}
#### Interpolation, but also you do `str(cmd.author).lower()` repeatedly; in this sort of situation it's
#### perfectly fine to make a temporary variable and use that.
cmnt.reply('You have now registered as a citizen in '+base+'! By default, you are producing material goods.')
#### Failable
self.data["UserInfo"] = self.userInfo
def iterate(self):
bot.register(self)
#### As before, should be `self.register()`
chromaData = open("EconomyInfo.json",'w')
json.dump(self.data,chromaData)
chromaData.close()
#### Could use a `with` statement here
while True:
for land in self.lands:
bot.log(self,land+': '+(time.asctime()))
self.landStats = self.landInfo[land]
bot.parseLand(self,land)
chromaData = open("EconomyInfo.json",'w')
json.dump(self.data,chromaData)
chromaData.close()
#### Also `with`
self.log.flush()
#### Your logging command already does this
print "Reading PMs"
newPMs = self.r.get_unread(True,True)
#### Failable
#### Also, I speak from personal experience here when I say that this will not always
#### work; occasionally reddit has problems where messages do not get marked read
#### and if that happens your bot will repeatedly try to process a message over
#### and over again.
PMCommands = []
for PM in newPMs:
#### PEP8: `pm_commands`, `pm`, `new_pms`
if not PM.was_comment:
PMCommands.append(PM)
PM.mark_as_read()
bot.log(self,"PMs: "+str(time.asctime()))
bot.parsePMs(self,PMCommands)
print "Updating JSON file"
chromaData = open("EconomyInfo.json",'w')
json.dump(self.data,chromaData)
chromaData.close()
#### With; also you're dumping to the economy file multiple times.
bot.log(self,"User production: "+str(time.asctime()))
print("User production")
for user in self.userInfo:
bot.produce(self,user)
chromaData = open("EconomyInfo.json",'w')
json.dump(self.data,chromaData)
chromaData.close()
#### with
self.log.flush()
print "waiting 60 secs"
time.sleep(60)
## #except:
## chromaData = open("EconomyInfo.json",'w')
## json.dump(self.data,chromaData)
## chromaData.close()
## self.log.flush()
## bot.iterate(self)
def log(self,text):
self.log.write(text+'\n')
self.log.flush()
if __name__ == '__main__':
reddit = praw.Reddit('Chromeconomist Testing')
#### Reddit API rules say you should include your username in the useragent
reddit.login('Chromeconomist','BestEconomist')
#### All your currently hard-coded items would do well as an external configuration item, but
#### if your code is going to remain public on github you absolutely need to store the password
#### to the bot's account separately in a file not tracked by source control (also you will
#### need to change it, as it'll be in the file's history for all time)
print reddit
#### debug line?
chromaData = open("EconomyInfo.json",'r') #open('/home/ec2-user/Chroma.json','r'),open('/home/ec2-user/ChromaUsers.json','r')
try:
EconomistInfo = json.load(chromaData)
except ValueError as e:
print e
bot(reddit,EconomistInfo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment