Created
December 15, 2014 18:24
-
-
Save atiaxi/7762693650ed2cbcbd24 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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