def main(): parser = OptionParser() parser.add_option("-f", "--file", dest="filename", help="Insturctions file (not yet implemented)") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Print lots of debug logging") parser.add_option("-l", "--log-level", dest="log_level", default=logging.WARN) parser.add_option("-c", "--config", help="Config file to read from (not implemented).") parser.add_option( "--page-cache", help="Directory to dump pages to (for debugging only).") parser.add_option("-u", "--username", help="Username for player.") parser.add_option("-p", "--password", help="Password for player. (can be defined in conf too)") (options, args) = parser.parse_args() if(options.debug): options.log_level = 10 logging.basicConfig(level=int(options.log_level)) logging.basicConfig(level=logging.WARN) #Actual logic log.info("Instanciating player") player = UtopiaRobot() if(options.page_cache): player.page_cache = options.page_cache player.username = options.username log.info("set username = %s" % player.username) player.password = options.password log.info("set password = %s (masked)" % "".join(["*" for c in player.password])) log.info("Log in player (%s)...", player.username) available_spells = player.get_available_spells() log.debug("available_spells: %s" % available_spells) active_spells = player.get_active_spells() resources = player.get_resources() if 'Patriotism' in available_spells: #Check for presence in available spells (to avoid a future KeyError exception) if 'Patriotism' not in active_spells: # If the spell is not active, set it to -1 (again, to avoid KeyError exeptions) active_spells['Patriotism'] = -1 while active_spells['Patriotism'] <= 1 and resources['Runes'] > available_spells['Patriotism'][1] and 20 < player.get_mana(): if player.cast_spell('Patriotism') is not None: log.info("Cast Patriotism: Success") break log.info("Cast Patriotism: Failed") resources = player.get_resources() log.info("Cast Patriotism: Done") resources = player.get_resources() if 'Fertile Lands' in available_spells: if 'Fertile Lands' not in spells: active_spells['Fertile Lands'] = -1 while active_spells['Fertile Lands'] <= 1 and resources['Food'] < 20000 and resources['Runes'] > available_spells['Fertile Lands'][1] and 20 < player.get_mana(): if player.cast_spell('Fertile Lands') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fertile Lands: Done") resources = player.get_resources() if 'Love and Peace' in available_spells: if 'Love and Peace' not in active_spells: active_spells['Love and Peace'] = -1 while active_spells['Love and Peace'] <= 1 and resources['Runes'] > available_spells['Love and Peace'][1] and 20 < player.get_mana(): if player.cast_spell('Love and Peace') is not None: log.info("Cast Love and Peace: Success") break log.info("Cast Love and Peace: Failed") resources = player.get_resources() log.info("Cast Love and Peace: Done") resources = player.get_resources() print "DONE"
def main(): parser = OptionParser() parser.add_option("-f", "--file", dest="filename", help="Insturctions file (not yet implemented)") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Print lots of debug logging") parser.add_option("-l", "--log-level", dest="log_level", default=logging.WARN) parser.add_option("-c", "--config", help="Config file to read from (not implemented).") parser.add_option( "--page-cache", help="Directory to dump pages to (for debugging only).") parser.add_option("-u", "--username", help="Username for player.") parser.add_option("-p", "--password", help="Password for player. (can be defined in conf too)") (options, args) = parser.parse_args() if(options.debug): options.log_level = 10 logging.basicConfig(level=int(options.log_level)) logging.basicConfig(level=logging.WARN) #Actual logic log.info("Instanciating player") player = UtopiaRobot() if(options.page_cache): player.page_cache = options.page_cache player.username = options.username log.info("set username = %s" % player.username) player.password = options.password log.info("set password = %s (masked)" % "".join(["*" for c in player.password])) log.info("Log in player (%s)...", player.username) log.info("Get five random kds") for _ in range(5): kd = random.randint(1,10) island = random.randint(1,40) log.info("Fetching kd:%d, island:%d" % (kd, island)) kd_info = player.get_kd_info(kd,island) kd_json = json.dumps(kd_info).replace("'",'"') with open("%d-%d.txt"%(kd,island),'w') as f: f.write(kd_json) # post to db values={"textarea": kd_json} data = urllib.urlencode(values) headers={} req = urllib2.Request("127.0.0.1:5001/post_kd/", data, headers) mana = player.get_mana() available_spells = player.get_available_spells() log.debug("available_spells: %s" % available_spells) spells = player.get_active_spells() resources = player.get_resources() # First and foremost, Make sure we have Minor Protection if 'Minor Protection' in available_spells: if 'Minor Protection' not in spells: spells['Minor Protection'] = 0 while spells['Minor Protection'] <= 1 and resources['Runes'] > available_spells['Minor Protection'][1] and 20 < player.get_mana(): if player.cast_spell('Minor Protection') is not None: log.info("Cast Minor Protection: Success") break log.info("Cast Minor Protection: Failed") resources = player.get_resources() log.info("Cast Minor Protection: Done") resources = player.get_resources() # if we got plague, remove it. # Because we still don't detect plague-removal, we reload the throne page on each iteraton if "Nature's Blessing" in available_spells: if "Nature's Blessing" not in spells: spells["Nature's Blessing"] = 0 while player.get_plague() and spells["Nature's Blessing"] <= 1 and resources['Runes'] > available_spells["Nature's Blessing"][1] and 10 < player.get_mana(): if player.cast_spell("Nature's Blessing") is not None: log.info("Cast Nature's Blessing: Success") break log.info("Cast Nature's Blessing: Failed") resources = player.get_resources() log.info("Cast Nature's Blessing: Done") resources = player.get_resources() # If we are low on food, make sure we cast Fertile lands. if 'Fertile Lands' in available_spells: if 'Fertile Lands' not in spells: spells['Fertile Lands'] = 0 while spells['Fertile Lands'] <= 1 and resources['Food'] < 30000 and resources['Runes'] > available_spells['Fertile Lands'][1] and 20 < player.get_mana(): if player.cast_spell('Fertile Lands') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fertile Lands: Done") # If we are low on food, make sure we cast Fertile lands. if 'Fountain of Knowledge' in available_spells: if 'Fountain of Knowledge' not in spells: spells['Fountain of Knowledge'] = 0 while spells['Fountain of Knowledge'] <= 1 and resources['Runes'] > available_spells['Fountain of Knowledge'][1] and 20 < player.get_mana(): if player.cast_spell('Fountain of Knowledge') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fontain of Knowledge: Done") counter = 0 resources = player.get_resources() while 20 < player.get_mana() and player.get_soldiers() > 0: counter +=1 if counter > 7: break resources = player.get_resources() leet_count = resources['Money'] / 500 while 1 > leet_count and player.get_mana() >= 20 and player.get_soldiers() > 0: counter += 1 if counter > 7: break player.cast_spell("Tree of Gold") available_spells = player.get_available_spells() resources = player.get_resources() leet_count = resources['Money'] / 500 #spec_count = resources['Money'] / 350 #troops={'o-spec': spec_count} troops={'elite': leet_count} trained_troops = player.train_military(troops) # if 1 > leet_count: # troops={'o-spec': spec_count} # if 1 > spec_count: # break # else: # troops={'elite': leet_count} log.info("train_military(%s): %s" % (troops, trained_troops)) # If we reach this point, and we're out of money. Let's try to spend our spec-credits resources = player.get_resources() if (0 < player.get_spec_credits() or 350 > resources['Money']) and 0 < player.get_soldiers(): troops={'o-spec': min(player.get_soldiers(), player.get_spec_credits())} trained_military = player.train_military(troops) log.debug("spec-credits: train_military(%s): %s" % (troops, trained_military)) info_msg = "" if 'Paradise' in available_spells: if resources['Runes'] > available_spells['Paradise']: info_msg = "Not enough runes (have: %s, need: %s)" % (resources['Runes'], available_spells['Paradise']) elif 10 >= player.get_mana(): info_msg = "Not enough mana (%s%)" % player.get_mana() else: while resources['Runes'] > available_spells['Paradise'][1] and 20 < player.get_mana(): result = player.cast_spell('Paradise') log.info("Cast Paradise - Result: %s" % result) resources = player.get_resources() else: info_msg = "Paradise not available to cast." log.info("Paradise done: %s"% info_msg) log.info("Prep building.") build_info = player.get_build_info() buildings = player.get_buildings() resources = player.get_resources() iterations_counter = 0 while 6 < iterations_counter and 0 < build_info['Total Undeveloped land'] and build_info['Construction Cost'] < resources['Money']: iterations_counter += 1 for k,v in buildings.items(): buildings[k]['total'] = v['built'] + v['incoming'] to_build = {} # min 8% farms if 0.08 < buildings['Farms']['total'] / build_info['Total Land']: to_build['Farms'] = int((0.07 - (buildings['Farms']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Farms'] : %s" % to_build['Farms']) if 0.15 < buildings['Guilds']['total'] / build_info['Total Land']: to_build['Guilds'] = int((0.15 - (buildings['Guilds']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Guilds'] : %s" % to_build['Guilds']) if 0.09 < buildings['Forts']['total'] / build_info['Total Land']: to_build['Forts'] = int((0.12 - (buildings['Forts']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Forts'] : %s" % to_build['Forts']) if 0.25 < buildings['Banks']['total'] / build_info['Total Land']: to_build['Banks'] = int((0.12 - (buildings['Banks']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Banks'] : %s" % to_build['Banks']) if 0.14 < buildings['Towers']['total'] / build_info['Total Land']: to_build['Towers'] = int((0.15 - (buildings['Towers']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Towers'] : %s" % to_build['Towers']) if 0.2 < buildings['Schools']['total'] / build_info['Total Land']: to_build['Schools'] = int((0.12 - (buildings['Schools']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Schools'] : %s" % to_build['Schools']) if 0.09 < buildings['Training Grounds']['total'] / build_info['Total Land']: to_build['Training Grounds'] = int((0.12 - (buildings['Training Grounds']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Training Grounds'] : %s" % to_build['Training Grounds']) if 0 <= len(to_build): log.info("No need to build anything.") break log.info("Want to build: %s"% to_build) player.build(to_build) log.info("build_info: %s" ,player.get_build_info()) log.info("buildings: %s", player.get_buildings()) build_info = player.get_build_info() resources = player.get_resources() if 0 < build_info['Total Undeveloped land']: # If we are low on food, make sure we cast Fertile lands. while 'Tree of Gold' in available_spells and resources['Runes'] > available_spells['Tree of Gold'][1] and 20 < player.get_mana() and player.cast_spell('Tree of Gold') is not None: resources = player.get_resources() # SCIENCE!!! available_books = player.get_science_info()['Books to Allocate'] if 3 < available_books: buy_sci = { "Alchemy": int(round(available_books/4)), "Tools": int(round(available_books/4)), "Housing": int(round(available_books/4)+random.randrange(0,10)), "Food": int(round(available_books/16)), "Military": int(round(available_books/16)), "Crime": int(round(available_books/16)), "Channeling": int(round(available_books/16)), } result = player.buy_science(buy_sci) info_msg="Bought science: %s"%result else: info_msg = "Less than 3 books (have: %s)"%available_books log.info("Buying science DONE: %s", info_msg) print "DONE"
class player_tests(object): def setup(self): self.player = UtopiaRobot() @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_resources(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/throne_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True resources = self.player.get_resources() print "Resources:", resources assert(480594 == resources['Money']) assert(10065 == resources['Peasants']) assert(78481 == resources['Food']) assert(13244 == resources['Runes']) assert(213924 == resources['Net Worth']) assert(1398 == resources['Land']) assert(153.021 == resources['Net Worth/Acre']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_plague_false(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/throne_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True plague = self.player.get_plague() assert(False == plague) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_plague_true(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/throne_plague.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True plague = self.player.get_plague() assert(True == plague) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_mana(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/mystic_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True mana = self.player.get_mana() print "Mana:", mana assert(68 == mana) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_available_spells(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/mystic_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True available_spells = self.player.get_available_spells() print "Available spells:", available_spells assert(('FERTILE_LANDS',815) == available_spells['Fertile Lands']) assert(('PARADISE', 4891) == available_spells['Paradise']) assert(('LOVE_AND_PEACE', 1141) == available_spells['Love and Peace']) assert(('SHADOW_LIGHT', 3098) == available_spells['Shadow Light']) assert(('NATURES_BLESSING', 978) == available_spells["Nature's Blessing"]) assert(('INSPIRE_ARMY', 1793) == available_spells['Inspire Army']) assert(('FOUNTAIN_OF_KNOWLEDGE', 2527) == available_spells['Fountain of Knowledge']) assert(('TREE_OF_GOLD', 1304) == available_spells['Tree of Gold']) assert(('FERTILE_LANDS', 815) == available_spells['Fertile Lands']) assert(('WAR_SPOILS', 2364) == available_spells['War Spoils']) assert(('PARADISE', 4891) == available_spells['Paradise']) assert(('MAGIC_SHIELD', 815) == available_spells['Magic Shield']) assert(('ANONYMITY', 2119) == available_spells['Anonymity']) assert(('BUILDERS_BOON', 1630) == available_spells['Builders Boon']) assert(('MINOR_PROTECTION', 570) == available_spells['Minor Protection']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_active_spells(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/mystic_advisor.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True active_spells = self.player.get_active_spells() print "Active spells:", active_spells assert(14 == active_spells['Fountain of Knowledge']) assert( 3 == active_spells["Nature's Blessing"]) assert(15 == active_spells['Minor Protection']) assert( 1 == active_spells['Love and Peace']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_cast_paradise_success(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/spell_paradise.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True print ("assert()") assert(5 == self.player.cast_spell('Paradise')) mystic_form = self.player.parser.get_mystic_form() print mystic_form assert('88e2dabb2a8b615561e743d05668d47d' == mystic_form['inputs']['csrfmiddlewaretoken']['value']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_troops(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/military_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True troops = self.player.get_troops() print "troops:", troops assert(1530 == troops['o-spec']['home']) assert(1530 == troops['o-spec']['home']) assert(807 == troops['o-spec']['training']) assert(350 == troops['o-spec']['cost']) assert(806 == troops['o-spec']['max']) assert(839 == troops['d-spec']['home']) assert(165 == troops['d-spec']['training']) assert(350 == troops['d-spec']['cost']) assert(806 == troops['d-spec']['max']) assert(11184 == troops['elite']['home']) assert(53 == troops['elite']['training']) assert(500 == troops['elite']['cost']) assert(564 == troops['elite']['max']) assert(2222 == troops['thief']['home']) assert(0 == troops['thief']['training']) assert(500 == troops['thief']['cost']) assert(564 == troops['thief']['max']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_soldiers(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/military_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True soldiers = self.player.get_soldiers() print "soldiers:", soldiers assert(1293 == soldiers) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_spec_credits(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/military_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True credits = self.player.get_spec_credits() print "credits:", credits assert(123 == credits) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_train_troops(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/military_trained.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True military={} military['o-spec'] = 44 military['d-spec'] = 33 military['elite'] = 22 military['thief'] = 11 print "Want to train: %s" % military military_result = self.player.train_military(military) print "Militarty result: %s" % military_result assert(44 == military_result['o-spec']) assert(33 == military_result['d-spec']) assert(22 == military_result['elite']) assert(11 == military_result['thief']) print "self.player.get_draft_rate():", self.player.get_draft_rate() print "self.player.get_draft_rate()[1]:", self.player.get_draft_rate()[1] assert('AGGRESSIVE' == self.player.get_draft_rate()[1]) military_form = self.player.parser.get_military_form() print military_form assert('88e2dabb2a8b615561e743d05668d47d' == military_form['inputs']['csrfmiddlewaretoken']['value']) #train form-data # csrfmiddlewaretoken:88e2dabb2a8b615561e743d05668d47d # draft_rate:AGGRESSIVE # draft_target:66 # wage_rate:200 # unit-quantity_0:1 # unit-quantity_1:2 # unit-quantity_2:3 # unit-quantity_3:4 # train:Train troops #change recruitlvl # csrfmiddlewaretoken:88e2dabb2a8b615561e743d05668d47d # draft_rate:NORMAL # draft_target:65 # wage_rate:201 # unit-quantity_0: # unit-quantity_1: # unit-quantity_2: # unit-quantity_3: # train:Train troops @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_buildings(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/growth_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True buildings = self.player.get_buildings() print "buildings:", buildings assert(228 == buildings['Homes']['built']) assert( 36 == buildings['Homes']['incoming']) assert(167 == buildings['Farms']['built']) assert( 18 == buildings['Farms']['incoming']) assert( 0 == buildings['Mills']['built']) assert( 0 == buildings['Mills']['incoming']) assert(486 == buildings['Banks']['built']) assert( 50 == buildings['Banks']['incoming']) assert(106 == buildings['Training Grounds']['built']) assert( 0 == buildings['Training Grounds']['incoming']) assert( 0 == buildings['Armouries']['built']) assert( 0 == buildings['Armouries']['incoming']) assert( 0 == buildings['Military Barracks']['built']) assert( 0 == buildings['Military Barracks']['incoming']) assert( 98 == buildings['Forts']['built']) assert( 0 == buildings['Forts']['incoming']) assert( 0 == buildings['Guard Stations']['built']) assert( 0 == buildings['Guard Stations']['incoming']) assert( 0 == buildings['Hospitals']['built']) assert( 0 == buildings['Hospitals']['incoming']) assert(248 == buildings['Guilds']['built']) assert( 15 == buildings['Guilds']['incoming']) assert(196 == buildings['Towers']['built']) assert( 32 == buildings['Towers']['incoming']) assert( 28 == buildings["Thieves' Dens"]['built']) assert( 0 == buildings["Thieves' Dens"]['incoming']) assert( 0 == buildings['Watch Towers']['built']) assert( 0 == buildings['Watch Towers']['incoming']) assert( 0 == buildings['Libraries']['built']) assert( 0 == buildings['Libraries']['incoming']) assert( 0 == buildings['Schools']['built']) assert( 0 == buildings['Schools']['incoming']) assert( 96 == buildings['Stables']['built']) assert( 0 == buildings['Stables']['incoming']) assert( 0 == buildings['Dungeons']['built']) assert( 0 == buildings['Dungeons']['incoming']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_build(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/growth_built.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True buildings={ 'Homes': 1, 'Farms': 1, 'Banks': 1, 'Guilds': 1, 'Towers': 1, 'Stables': 1, } print "Want to build: %s" % buildings buildings_result = self.player.build(buildings) print "Build result: %s" % buildings_result assert(1 == buildings_result['Homes']) assert(1 == buildings_result['Farms']) assert(1 == buildings_result['Banks']) assert(1 == buildings_result['Guilds']) assert(1 == buildings_result['Towers']) assert(1 == buildings_result['Stables']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_build_info(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/growth_built.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True buildings={ 'Homes': 1, 'Farms': 1, 'Banks': 1, 'Guilds': 1, 'Towers': 1, 'Stables': 1, } print "Want to build: %s" % buildings buildings_result = self.player.build(buildings) print "Build result: %s" % buildings_result assert(1 == buildings_result['Homes']) assert(1 == buildings_result['Farms']) assert(1 == buildings_result['Banks']) assert(1 == buildings_result['Guilds']) assert(1 == buildings_result['Towers']) assert(1 == buildings_result['Stables']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_build_multiple(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/growth_built_plural.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True buildings={ 'Homes': 2, 'Farms': 2, 'Banks': 2, 'Training Grounds': 2, 'Forts': 2, 'Guilds': 2, 'Towers': 2, 'Stables': 2, } print "Want to build: %s" % buildings buildings_result = self.player.build(buildings) print "Build result: %s" % buildings_result assert(2 == buildings_result['Homes']) assert(2 == buildings_result['Farms']) assert(2 == buildings_result['Banks']) assert(2 == buildings_result['Training Grounds']) assert(2 == buildings_result['Forts']) assert(2 == buildings_result['Guilds']) assert(2 == buildings_result['Towers']) assert(2 == buildings_result['Stables']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_build_multiple(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/growth_built_plural.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True buildings={ 'Homes': 2, 'Farms': 2, 'Banks': 2, 'Training Grounds': 2, 'Forts': 2, 'Guilds': 2, 'Towers': 2, 'Stables': 2, } print "Want to build: %s" % buildings buildings_result = self.player.build(buildings) print "Build result: %s" % buildings_result assert(2 == buildings_result['Homes']) assert(2 == buildings_result['Farms']) assert(2 == buildings_result['Banks']) assert(2 == buildings_result['Training Grounds']) assert(2 == buildings_result['Forts']) assert(2 == buildings_result['Guilds']) assert(2 == buildings_result['Towers']) assert(2 == buildings_result['Stables']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_science(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/science_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True science = self.player.get_science() print "Sience:: %s" % science assert(21132 == science['Alchemy']['points']) assert(5.5 == science['Alchemy']['effect']) assert(0 == science['Alchemy']['incomming']) assert(73226 == science['Tools']['points']) assert(7.4 == science['Tools']['effect']) assert(9996 == science['Tools']['incomming']) assert(32578 == science['Housing']['points']) assert(3.2 == science['Housing']['effect']) assert(0 == science['Housing']['incomming']) assert(4892 == science['Food']['points']) assert(15.2 == science['Food']['effect']) assert(0 == science['Food']['incomming']) assert(4892 == science['Military']['points']) assert(2.7 == science['Military']['effect']) assert(0 == science['Military']['incomming']) assert(21340 == science['Crime']['points']) assert(23.8 == science['Crime']['effect']) assert(0 == science['Crime']['incomming']) assert(20860 == science['Channeling']['points']) assert(23.6 == science['Channeling']['effect']) assert(0 == science['Channeling']['incomming']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_get_science(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/science_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True science = self.player.get_science() print "Sience:: %s" % science assert(21132 == science['Alchemy']['points']) assert(5.5 == science['Alchemy']['effect']) assert(0 == science['Alchemy']['incomming']) assert(73226 == science['Tools']['points']) assert(7.4 == science['Tools']['effect']) assert(9996 == science['Tools']['incomming']) assert(32578 == science['Housing']['points']) assert(3.2 == science['Housing']['effect']) assert(0 == science['Housing']['incomming']) assert(4892 == science['Food']['points']) assert(15.2 == science['Food']['effect']) assert(0 == science['Food']['incomming']) assert(4892 == science['Military']['points']) assert(2.7 == science['Military']['effect']) assert(0 == science['Military']['incomming']) assert(21340 == science['Crime']['points']) assert(23.8 == science['Crime']['effect']) assert(0 == science['Crime']['incomming']) assert(20860 == science['Channeling']['points']) assert(23.6 == science['Channeling']['effect']) assert(0 == science['Channeling']['incomming']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_science_info(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/science_bought.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True info = self.player.get_science_info() print "Info: %s" % info assert(45258 == info['Total Money']) assert((23369, 15) == info['Estimated Research Cost']) assert(152553 == info['Daily Income']) assert(2276 == info['Books to Allocate']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_explore_info(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/explore_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True explore_info = self.player.get_explore_info() print "Explore info: %s" % explore_info assert( 50 == explore_info['Exploration Costs (Soldiers)']) assert( 50 == explore_info['soldiers']) assert(23264 == explore_info['Exploration Costs (Gold)']) assert(23264 == explore_info['gold']) assert( 8080 == explore_info['Available Uncharted Acres']) assert( 8080 == explore_info['available']) assert( 0 == explore_info['Currently Exploring']) assert( 5 == explore_info['Maximum Explorable Now']) @mock.patch('urllib2.urlopen') @mock.patch('urllib2.Request') @mock.patch.object(UtopiaRobot,'cache_page') @mock.patch.object(UtopiaRobot,'_simulate_wait') def test_kingdom_info(self, mock_simulate_wait, mock_cache_page, mock_request, mock_urlopen): mock_urlopen.return_value = mock_request mock_request.read.return_value = open('test/kingdom_page.html').read() mock_cache_page.return_value = True mock_simulate_wait.return_value = True kd = self.player.get_kd_info(1,17) print "kd: %s" % kd assert(1 == kd['kd']) assert(17 == kd['island']) assert(20 == kd['Total Provinces']) assert('normal' == kd['Stance']) assert(3077180 == kd['Total Networth']) assert(153859 == kd['Average Networth']) assert(0 == kd['Wars Won']) assert(2 == kd['Concluded Wars']) assert(18629 == kd['Total Land']) assert(103 == kd['Average Opponent Relative Size']) assert('normal' == kd['Their Attitude To Us']) assert('normal' == kd['Our Attitude To Them']) assert(True == kd['provinces']['house 1']['protected']) assert(False == kd['provinces']['house 1']['online']) assert(False == kd['provinces']['house 1']['monarch']) assert(1 == kd['provinces']['house 1']['Slot']) assert('house 1' == kd['provinces']['house 1']['Province']) assert('Avian' == kd['provinces']['house 1']['Race']) assert(354 == kd['provinces']['house 1']['Land']) assert(19272 == kd['provinces']['house 1']['Net Worth']) assert(54== kd['provinces']['house 1']['Net Worth/Acre']) assert('Lord' == kd['provinces']['house 1']['Nobility']) assert(True == kd['provinces']['house 1']['protected']) assert(1 == kd['provinces']['house 1']['Slot']) assert('house 1' == kd['provinces']['house 1']['Province']) assert('Avian' == kd['provinces']['house 1']['Race']) assert(354 == kd['provinces']['house 1']['Land']) assert(19272 == kd['provinces']['house 1']['Net Worth']) assert(54== kd['provinces']['house 1']['Net Worth/Acre']) assert('Lord' == kd['provinces']['house 1']['Nobility'])
def main(): parser = OptionParser() parser.add_option("-f", "--file", dest="filename", help="Insturctions file (not yet implemented)") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Print lots of debug logging") parser.add_option("-l", "--log-level", dest="log_level", default=logging.WARN) parser.add_option("-c", "--config", help="Config file to read from (not implemented).") parser.add_option( "--page-cache", help="Directory to dump pages to (for debugging only).") parser.add_option("-u", "--username", help="Username for player.") parser.add_option("-p", "--password", help="Password for player. (can be defined in conf too)") (options, args) = parser.parse_args() if(options.debug): options.log_level = 10 logging.basicConfig(level=int(options.log_level)) logging.basicConfig(level=logging.WARN) #Actual logic log.info("Instanciating player") player = UtopiaRobot() if(options.page_cache): player.page_cache = options.page_cache player.username = options.username log.info("set username = %s" % player.username) player.password = options.password log.info("set password = %s (masked)" % "".join(["*" for c in player.password])) log.info("Log in player (%s)...", player.username) available_spells = player.get_available_spells() log.debug("available_spells: %s" % available_spells) active_spells = player.get_active_spells() resources = player.get_resources() def ensure_spells_are_cast(spells, active_spells, player): log.debug("ensure_spells_are_cast: {0}".format(spells)) resources = player.get_resources() for spell in spells: log.info("Trying to cast {0}.".format(spell)) if spell in available_spells: if spell not in active_spells: active_spells[spell] = 0 while active_spells[spell] <= 1 and resources['Runes'] > available_spells[spell][1] and 20 < player.get_mana(): if player.cast_spell(spell) is not None: log.info("Cast {0}: Success".format(spell)) break log.info("Cast {0}: Failed".format(spell)) resources = player.get_resources() log.info("Cast {0}: Done".format(spell)) resources = player.get_resources() spells = ['Minor Protection', 'Fertile Lands', 'Love and Peace', "Patriotism"] ensure_spells_are_cast(spells, active_spells, player) if "Nature's Blessing" in available_spells: while player.get_plague() and resources['Runes'] > available_spells["Nature's Blessing"][1] and 15 < player.get_mana(): if player.cast_spell("Nature's Blessing") is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() if 'Fertile Lands' in available_spells: if 'Fertile Lands' not in active_spells: active_spells['Fertile Lands'] = 0 while active_spells['Fertile Lands'] <= 1 and resources['Food'] < 20000 and resources['Runes'] > available_spells['Fertile Lands'][1] and 20 < player.get_mana(): if player.cast_spell('Fertile Lands') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fertile Lands: Done") resources = player.get_resources() # counter = 0 # resources = player.get_resources() # troops_home = player.get_troops() # thief_tot = troops_home['thief']['home'] + troops_home['thief']['training'] # thief_target = resources['Land'] * 2 # if thief_target > thief_tot: # player.train_military({'thief': thief_target-thief_tot}) # resources = player.get_resources() # while resources['Money'] > 500 and player.get_soldiers() > 0: # counter +=1 # if counter > 4: # break # spec_count = min(player.get_soldiers(), resources['Money'] / 500) # troops={'elite': (spec_count) } # trained_troops = player.train_military(troops) # log.info("train_military(%s): %s" % (troops, trained_troops)) # SCIENCE!!! available_books = player.get_science_info()['Books to Allocate'] if 3 < available_books: buy_sci = { "Alchemy": int(round(available_books)), #"Tools": int(round(available_books/7)), #"Housing": int(round(available_books/7)), #"Food": int(round(available_books/7)), #"Military": int(round(available_books/7)), #"Crime": int(round(available_books/7)), #"Channeling": int(round(available_books/7)), } result = player.buy_science(buy_sci) info_msg="Bought science: %s"%result else: info_msg = "Less than 3 books (have: %s)"%available_books log.info("Buying science DONE: %s", info_msg) print "DONE" # Dice cost *2 gives enough margin to cast all spels next cycle. # So, if we have dice cost *3, spend one dice if 'Paradise' in available_spells: while resources['Runes'] > available_spells['Paradise'][1]*3 and 20 < player.get_mana(): if player.cast_spell('Paradise') is not None: log.info("Cast Paradise: Success") break log.info("Cast Paradise: Failed") resources = player.get_resources() log.info("Cast Paradise: Done") #everything is looking good. # Lets fetch a few KDs and we 'target search' islandlist=[] island=random.randint(0,41) iterations = random.randint(3,10) for _ in range(iterations+1): log.info("Islandlist: %s" % islandlist) while island in islandlist: island = random.randint(1,41) islandlist.append(island) for kd in range(1,10): log.info("Fetching kd:%d, island:%d" % (kd, island)) kd_info = player.get_kd_info(kd,island) kd_json = json.dumps(kd_info).replace("'",'"') with open("%d-%d.txt"%(kd,island),'w') as f: f.write(kd_json) # post to db values={"textarea": kd_json} data = urllib.urlencode(values) headers={} log.debug("Posting %s to 127.0.0.1.", kd_json) req = urllib2.Request("http://127.0.0.1:5006/post_kd/", data, headers) urllib2.urlopen(req) time.sleep(random.randint(4,10))
def main(): parser = OptionParser() parser.add_option("-f", "--file", dest="filename", help="Insturctions file (not yet implemented)") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Print lots of debug logging") parser.add_option("-l", "--log-level", dest="log_level", default=logging.WARN) parser.add_option("-c", "--config", help="Config file to read from (not implemented).") parser.add_option("--page-cache", help="Directory to dump pages to (for debugging only).") parser.add_option("-u", "--username", help="Username for player.") parser.add_option("-p", "--password", help="Password for player. (can be defined in conf too)") (options, args) = parser.parse_args() if (options.debug): options.log_level = 10 logging.basicConfig(level=int(options.log_level)) logging.basicConfig(level=logging.WARN) #Actual logic log.info("Instanciating player") player = UtopiaRobot() if (options.page_cache): player.page_cache = options.page_cache player.username = options.username log.info("set username = %s" % player.username) player.password = options.password log.info("set password = %s (masked)" % "".join(["*" for c in player.password])) log.info("Log in player (%s)...", player.username) log.info("Get five random kds") for _ in range(5): kd = random.randint(1, 10) island = random.randint(1, 40) log.info("Fetching kd:%d, island:%d" % (kd, island)) kd_info = player.get_kd_info(kd, island) kd_json = json.dumps(kd_info).replace("'", '"') with open("%d-%d.txt" % (kd, island), 'w') as f: f.write(kd_json) # post to db values = {"textarea": kd_json} data = urllib.urlencode(values) headers = {} req = urllib2.Request("127.0.0.1:5001/post_kd/", data, headers) mana = player.get_mana() available_spells = player.get_available_spells() log.debug("available_spells: %s" % available_spells) spells = player.get_active_spells() resources = player.get_resources() # First and foremost, Make sure we have Minor Protection if 'Minor Protection' in available_spells: if 'Minor Protection' not in spells: spells['Minor Protection'] = 0 while spells['Minor Protection'] <= 1 and resources[ 'Runes'] > available_spells['Minor Protection'][ 1] and 20 < player.get_mana(): if player.cast_spell('Minor Protection') is not None: log.info("Cast Minor Protection: Success") break log.info("Cast Minor Protection: Failed") resources = player.get_resources() log.info("Cast Minor Protection: Done") resources = player.get_resources() # if we got plague, remove it. # Because we still don't detect plague-removal, we reload the throne page on each iteraton if "Nature's Blessing" in available_spells: if "Nature's Blessing" not in spells: spells["Nature's Blessing"] = 0 while player.get_plague( ) and spells["Nature's Blessing"] <= 1 and resources[ 'Runes'] > available_spells["Nature's Blessing"][ 1] and 10 < player.get_mana(): if player.cast_spell("Nature's Blessing") is not None: log.info("Cast Nature's Blessing: Success") break log.info("Cast Nature's Blessing: Failed") resources = player.get_resources() log.info("Cast Nature's Blessing: Done") resources = player.get_resources() # If we are low on food, make sure we cast Fertile lands. if 'Fertile Lands' in available_spells: if 'Fertile Lands' not in spells: spells['Fertile Lands'] = 0 while spells['Fertile Lands'] <= 1 and resources[ 'Food'] < 30000 and resources['Runes'] > available_spells[ 'Fertile Lands'][1] and 20 < player.get_mana(): if player.cast_spell('Fertile Lands') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fertile Lands: Done") # If we are low on food, make sure we cast Fertile lands. if 'Fountain of Knowledge' in available_spells: if 'Fountain of Knowledge' not in spells: spells['Fountain of Knowledge'] = 0 while spells['Fountain of Knowledge'] <= 1 and resources[ 'Runes'] > available_spells['Fountain of Knowledge'][ 1] and 20 < player.get_mana(): if player.cast_spell('Fountain of Knowledge') is not None: log.info("Cast Fertile Lands: Success") break log.info("Cast Fertile Lands: Failed") resources = player.get_resources() log.info("Cast Fontain of Knowledge: Done") counter = 0 resources = player.get_resources() while 20 < player.get_mana() and player.get_soldiers() > 0: counter += 1 if counter > 7: break resources = player.get_resources() leet_count = resources['Money'] / 500 while 1 > leet_count and player.get_mana( ) >= 20 and player.get_soldiers() > 0: counter += 1 if counter > 7: break player.cast_spell("Tree of Gold") available_spells = player.get_available_spells() resources = player.get_resources() leet_count = resources['Money'] / 500 #spec_count = resources['Money'] / 350 #troops={'o-spec': spec_count} troops = {'elite': leet_count} trained_troops = player.train_military(troops) # if 1 > leet_count: # troops={'o-spec': spec_count} # if 1 > spec_count: # break # else: # troops={'elite': leet_count} log.info("train_military(%s): %s" % (troops, trained_troops)) # If we reach this point, and we're out of money. Let's try to spend our spec-credits resources = player.get_resources() if (0 < player.get_spec_credits() or 350 > resources['Money']) and 0 < player.get_soldiers(): troops = { 'o-spec': min(player.get_soldiers(), player.get_spec_credits()) } trained_military = player.train_military(troops) log.debug("spec-credits: train_military(%s): %s" % (troops, trained_military)) info_msg = "" if 'Paradise' in available_spells: if resources['Runes'] > available_spells['Paradise']: info_msg = "Not enough runes (have: %s, need: %s)" % ( resources['Runes'], available_spells['Paradise']) elif 10 >= player.get_mana(): info_msg = "Not enough mana (%s%)" % player.get_mana() else: while resources['Runes'] > available_spells['Paradise'][ 1] and 20 < player.get_mana(): result = player.cast_spell('Paradise') log.info("Cast Paradise - Result: %s" % result) resources = player.get_resources() else: info_msg = "Paradise not available to cast." log.info("Paradise done: %s" % info_msg) log.info("Prep building.") build_info = player.get_build_info() buildings = player.get_buildings() resources = player.get_resources() iterations_counter = 0 while 6 < iterations_counter and 0 < build_info[ 'Total Undeveloped land'] and build_info[ 'Construction Cost'] < resources['Money']: iterations_counter += 1 for k, v in buildings.items(): buildings[k]['total'] = v['built'] + v['incoming'] to_build = {} # min 8% farms if 0.08 < buildings['Farms']['total'] / build_info['Total Land']: to_build['Farms'] = int( (0.07 - (buildings['Farms']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Farms'] : %s" % to_build['Farms']) if 0.15 < buildings['Guilds']['total'] / build_info['Total Land']: to_build['Guilds'] = int( (0.15 - (buildings['Guilds']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Guilds'] : %s" % to_build['Guilds']) if 0.09 < buildings['Forts']['total'] / build_info['Total Land']: to_build['Forts'] = int( (0.12 - (buildings['Forts']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Forts'] : %s" % to_build['Forts']) if 0.25 < buildings['Banks']['total'] / build_info['Total Land']: to_build['Banks'] = int( (0.12 - (buildings['Banks']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Banks'] : %s" % to_build['Banks']) if 0.14 < buildings['Towers']['total'] / build_info['Total Land']: to_build['Towers'] = int( (0.15 - (buildings['Towers']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Towers'] : %s" % to_build['Towers']) if 0.2 < buildings['Schools']['total'] / build_info['Total Land']: to_build['Schools'] = int( (0.12 - (buildings['Schools']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Schools'] : %s" % to_build['Schools']) if 0.09 < buildings['Training Grounds']['total'] / build_info[ 'Total Land']: to_build['Training Grounds'] = int( (0.12 - (buildings['Training Grounds']['total'] / build_info['Total Land'])) * build_info['Total Land']) log.info("To build['Training Grounds'] : %s" % to_build['Training Grounds']) if 0 <= len(to_build): log.info("No need to build anything.") break log.info("Want to build: %s" % to_build) player.build(to_build) log.info("build_info: %s", player.get_build_info()) log.info("buildings: %s", player.get_buildings()) build_info = player.get_build_info() resources = player.get_resources() if 0 < build_info['Total Undeveloped land']: # If we are low on food, make sure we cast Fertile lands. while 'Tree of Gold' in available_spells and resources[ 'Runes'] > available_spells['Tree of Gold'][ 1] and 20 < player.get_mana() and player.cast_spell( 'Tree of Gold') is not None: resources = player.get_resources() # SCIENCE!!! available_books = player.get_science_info()['Books to Allocate'] if 3 < available_books: buy_sci = { "Alchemy": int(round(available_books / 4)), "Tools": int(round(available_books / 4)), "Housing": int(round(available_books / 4) + random.randrange(0, 10)), "Food": int(round(available_books / 16)), "Military": int(round(available_books / 16)), "Crime": int(round(available_books / 16)), "Channeling": int(round(available_books / 16)), } result = player.buy_science(buy_sci) info_msg = "Bought science: %s" % result else: info_msg = "Less than 3 books (have: %s)" % available_books log.info("Buying science DONE: %s", info_msg) print "DONE"