CitizenEconomy.get_market_offers() fixed

This commit is contained in:
Eriks K
2020-05-12 13:45:32 +03:00
parent d95c472ede
commit 05964f6c58
4 changed files with 76 additions and 82 deletions

View File

@ -5,7 +5,7 @@
__author__ = """Eriks Karls""" __author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv' __email__ = 'eriks@72.lv'
__version__ = '0.20.0' __version__ = '0.20.0'
__commit_id__ = "49726b8" __commit_id__ = "d95c472"
from erepublik import classes, utils from erepublik import classes, utils
from erepublik.citizen import Citizen from erepublik.citizen import Citizen

View File

@ -1,7 +1,7 @@
import datetime import datetime
import random import random
import time import time
from typing import Mapping, Any, Union, Dict, List from typing import Any, Dict, List, Mapping, Union
from requests import Response, Session from requests import Response, Session

View File

@ -5,14 +5,14 @@ from datetime import datetime, timedelta
from itertools import product from itertools import product
from threading import Event from threading import Event
from time import sleep from time import sleep
from typing import Any, Dict, List, Optional, Set, Tuple, Union, Callable, NoReturn from typing import Any, Callable, Dict, List, NoReturn, Optional, Set, Tuple, Union
from requests import RequestException, Response, HTTPError from requests import HTTPError, RequestException, Response
from erepublik import utils from erepublik import utils
from erepublik.classes import (Battle, BattleDivision, Config, Details, Energy, ErepublikException,
MyCompanies, MyJSONEncoder, Politics, Reporter, TelegramBot)
from erepublik.access_points import CitizenAPI from erepublik.access_points import CitizenAPI
from erepublik.classes import (Battle, BattleDivision, Config, Details, Energy, ErepublikException,
MyCompanies, MyJSONEncoder, OfferItem, Politics, Reporter, TelegramBot)
class BaseCitizen(CitizenAPI): class BaseCitizen(CitizenAPI):
@ -900,22 +900,21 @@ class CitizenEconomy(CitizenTravel):
def buy_and_activate_house(self, q: int) -> Dict[int, datetime]: def buy_and_activate_house(self, q: int) -> Dict[int, datetime]:
inventory = self.update_inventory() inventory = self.update_inventory()
original_region = self.details.current_country, self.details.current_region
ok_to_activate = False ok_to_activate = False
if not inventory['items']['final'].get('house', {}).get(q, {}): if not inventory['items']['final'].get('house', {}).get(q, {}):
offers = []
countries = [self.details.citizenship, ] countries = [self.details.citizenship, ]
if self.details.current_country != self.details.citizenship: if self.details.current_country != self.details.citizenship:
countries.append(self.details.current_country) countries.append(self.details.current_country)
for country in countries: offers = [self.get_market_offers("house", q, country)[f"q{q}"] for country in countries]
offers += [self.get_market_offers(country, "house", q)] local_cheapest = sorted(offers, key=lambda o: o.price)[0]
global_cheapest = self.get_market_offers(product_name="house", quality=q)
cheapest_offer = sorted(offers, key=lambda o: o["price"])[0] global_cheapest = self.get_market_offers("house", q)[f"q{q}"]
region = self.get_country_travel_region(global_cheapest['country']) if global_cheapest.price + 200 < local_cheapest.price:
if global_cheapest['price'] + 200 < cheapest_offer['price'] and region: self._travel(global_cheapest.country)
self._travel(global_cheapest['country'], region) buy = self.buy_from_market(global_cheapest.offer_id, 1)
buy = self.buy_from_market(global_cheapest['offer_id'], 1)
else: else:
buy = self.buy_from_market(cheapest_offer['offer_id'], 1) buy = self.buy_from_market(local_cheapest.offer_id, 1)
if buy["error"]: if buy["error"]:
msg = f"Unable to buy q{q} house! \n{buy['message']}" msg = f"Unable to buy q{q} house! \n{buy['message']}"
self.write_log(msg) self.write_log(msg)
@ -925,6 +924,8 @@ class CitizenEconomy(CitizenTravel):
ok_to_activate = True ok_to_activate = True
if ok_to_activate: if ok_to_activate:
self.activate_house(q) self.activate_house(q)
if original_region[1] != self.details.current_region:
self._travel(*original_region)
return self.check_house_durability() return self.check_house_durability()
def renew_houses(self, forced: bool = False) -> Dict[int, datetime]: def renew_houses(self, forced: bool = False) -> Dict[int, datetime]:
@ -1018,29 +1019,25 @@ class CitizenEconomy(CitizenTravel):
self.reporter.report_action("BUY_PRODUCT", ret.json()) self.reporter.report_action("BUY_PRODUCT", ret.json())
return json_ret return json_ret
def get_market_offers(self, country_id: int = None, product_name: str = None, quality: int = None) -> dict: def get_market_offers(self, product_name: str, quality: int = None, country_id: int = None) -> Dict[str, OfferItem]:
raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw") raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw")
q1_industries = ["aircraft"] + list(raw_short_names.values()) q1_industries = ["aircraft"] + list(raw_short_names.values())
if product_name: if product_name not in self.available_industries and product_name not in raw_short_names:
if product_name not in self.available_industries and product_name not in raw_short_names: self.write_log(f"Industry '{product_name}' not implemented")
self.write_log(f"Industry '{product_name}' not implemented") raise ErepublikException(f"Industry '{product_name}' not implemented")
raise ErepublikException(f"Industry '{product_name}' not implemented") elif product_name in raw_short_names:
elif product_name in raw_short_names: quality = 1
quality = 1 product_name = raw_short_names[product_name]
product_name = raw_short_names[product_name]
elif quality:
raise ErepublikException("Quality without product not allowed")
item_data = dict(price=999999., country=0, amount=0, offer_id=0, citizen_id=0) offers: Dict[str, OfferItem] = {}
items = {"food": dict(q1=item_data.copy(), q2=item_data.copy(), q3=item_data.copy(), q4=item_data.copy(), max_quality = 0
q5=item_data.copy(), q6=item_data.copy(), q7=item_data.copy()), if quality:
"weapon": dict(q1=item_data.copy(), q2=item_data.copy(), q3=item_data.copy(), q4=item_data.copy(), offers[f"q{quality}"] = OfferItem()
q5=item_data.copy(), q6=item_data.copy(), q7=item_data.copy()), else:
"house": dict(q1=item_data.copy(), q2=item_data.copy(), q3=item_data.copy(), q4=item_data.copy(), max_quality = 1 if product_name in q1_industries else 5 if product_name == 'house' else 7
q5=item_data.copy()), "aircraft": dict(q1=item_data.copy()), for q in range(max_quality):
"foodRaw": dict(q1=item_data.copy()), "weaponRaw": dict(q1=item_data.copy()), offers[f"q{q + 1}"] = OfferItem()
"houseRaw": dict(q1=item_data.copy()), "airplaneRaw": dict(q1=item_data.copy())}
if country_id: if country_id:
countries = [country_id] countries = [country_id]
@ -1048,58 +1045,41 @@ class CitizenEconomy(CitizenTravel):
countries = self.get_countries_with_regions() countries = self.get_countries_with_regions()
start_dt = self.now start_dt = self.now
iterable = [countries, [product_name] or items, [quality] if quality else range(1, 8)] iterable = [countries, [quality] if quality else range(1, max_quality + 1)]
for country, industry, q in product(*iterable): for country, q in product(*iterable):
if (q > 1 and industry in q1_industries) or (q > 5 and industry == "house"): r = self._post_economy_marketplace(country, self.available_industries[product_name], q).json()
continue obj = offers[f"q{q}"]
r = self._post_economy_marketplace(country, self.available_industries[industry], q).json()
obj = items[industry][f"q{q}"]
if not r.get("error", False): if not r.get("error", False):
for offer in r["offers"]: for offer in r["offers"]:
if obj["price"] > float(offer["priceWithTaxes"]): if (obj.price > float(offer["priceWithTaxes"]) or (
obj["price"] = float(offer["priceWithTaxes"]) obj.price == float(offer["priceWithTaxes"]) and obj.amount < int(offer["amount"])
obj["country"] = int(offer["country_id"]) )):
obj["amount"] = int(offer["amount"]) offers[f"q{q}"] = OfferItem(float(offer["priceWithTaxes"]), int(offer["country_id"]),
obj["offer_id"] = int(offer["id"]) int(offer["amount"]), int(offer["id"]), int(offer["citizen_id"]))
obj["citizen_id"] = int(offer["citizen_id"])
elif obj["price"] == float(offer["priceWithTaxes"]) and obj["amount"] < int(offer["amount"]):
obj["country"] = int(offer["country_id"])
obj["amount"] = int(offer["amount"])
obj["offer_id"] = int(offer["id"])
self.write_log(f"Scraped market in {self.now - start_dt}!") self.write_log(f"Scraped market in {self.now - start_dt}!")
if quality: return offers
ret = items[product_name[0]]["q%i" % quality]
elif product_name:
if product_name[0] in raw_short_names.values():
ret = items[product_name[0]]["q1"]
else:
ret = items[product_name[0]]
else:
ret = items
return ret
def buy_food(self, energy_amount: int = 0): def buy_food(self, energy_amount: int = 0):
hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20} hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20}
hp_needed = energy_amount if energy_amount else 48 * self.energy.interval * 10 - self.food["total"] hp_needed = energy_amount if energy_amount else 48 * self.energy.interval * 10 - self.food["total"]
local_offers = self.get_market_offers(country_id=self.details.current_country, product_name="food") local_offers = self.get_market_offers("food", country_id=self.details.current_country)
cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1]["price"] / hp_per_quality[v[0]])[0] cheapest_q, cheapest = sorted(local_offers.items(), key=lambda v: v[1].price / hp_per_quality[v[0]])[0]
if cheapest["amount"] * hp_per_quality[cheapest_q] < hp_needed: if cheapest["amount"] * hp_per_quality[cheapest_q] < hp_needed:
amount = cheapest["amount"] amount = cheapest.amount
else: else:
amount = hp_needed // hp_per_quality[cheapest_q] amount = hp_needed // hp_per_quality[cheapest_q]
if amount * cheapest["price"] < self.details.cc: if amount * cheapest.price < self.details.cc:
data = dict(offer=cheapest["offer_id"], amount=amount, price=cheapest["price"], data = dict(offer=cheapest.offer_id, amount=amount, price=cheapest.price,
cost=amount * cheapest["price"], quality=cheapest_q, energy=amount * hp_per_quality[cheapest_q]) cost=amount * cheapest.price, quality=cheapest_q, energy=amount * hp_per_quality[cheapest_q])
self.reporter.report_action("BUY_FOOD", json_val=data) self.reporter.report_action("BUY_FOOD", json_val=data)
self.buy_from_market(cheapest["offer_id"], amount) self.buy_from_market(cheapest.offer_id, amount)
self.update_inventory() self.update_inventory()
else: else:
s = f"Don't have enough money! Needed: {amount * cheapest['price']}cc, Have: {self.details.cc}cc" s = f"Don't have enough money! Needed: {amount * cheapest.price}cc, Have: {self.details.cc}cc"
self.write_log(s) self.write_log(s)
self.reporter.report_action("BUY_FOOD", value=s) self.reporter.report_action("BUY_FOOD", value=s)
@ -2307,13 +2287,12 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
amount = inv_resp.get("inventoryItems").get(category).get("items").get(item).get("amount", 0) amount = inv_resp.get("inventoryItems").get(category).get("items").get(item).get("amount", 0)
if amount >= 1: if amount >= 1:
lowest_price = self.get_market_offers(country_id=self.details.citizenship, lowest_price = self.get_market_offers(kind, int(quality), self.details.citizenship)[f'q{int(quality)}']
product_name=kind, quality=int(quality))
if lowest_price["citizen_id"] == self.details.citizen_id: if lowest_price.citizen_id == self.details.citizen_id:
price = lowest_price["price"] price = lowest_price.price
else: else:
price = lowest_price["price"] - 0.01 price = lowest_price.price - 0.01
self.post_market_offer(industry=self.available_industries[kind], amount=int(amount), self.post_market_offer(industry=self.available_industries[kind], amount=int(amount),
quality=int(quality), price=price) quality=int(quality), price=price)
@ -2341,12 +2320,12 @@ class Citizen(CitizenAnniversary, CitizenCompanies, CitizenEconomy, CitizenLeade
start_place = (self.details.current_country, self.details.current_region) start_place = (self.details.current_country, self.details.current_region)
while amount_needed > 0: while amount_needed > 0:
amount = amount_needed amount = amount_needed
best_offer = self.get_market_offers(product_name=f"{raw_kind}Raw") best_offer = self.get_market_offers(f"{raw_kind}Raw")['q1']
amount = best_offer['amount'] if amount >= best_offer['amount'] else amount amount = best_offer.amount if amount >= best_offer.amount else amount
if not best_offer['country'] == self.details.current_country: if not best_offer.country == self.details.current_country:
self.travel_to_country(best_offer['country']) self.travel_to_country(best_offer.country)
rj = self.buy_from_market(amount=best_offer['amount'], offer=best_offer['offer_id']) rj = self.buy_from_market(amount=best_offer.amount, offer=best_offer.offer_id)
if not rj.get('error'): if not rj.get('error'):
amount_needed -= amount amount_needed -= amount
else: else:

View File

@ -3,7 +3,7 @@ import decimal
import hashlib import hashlib
import threading import threading
from collections import defaultdict, deque from collections import defaultdict, deque
from typing import Any, Dict, Iterable, List, Tuple, Union from typing import Any, Dict, Iterable, List, NamedTuple, Tuple, Union
from requests import Response, Session, post from requests import Response, Session, post
@ -492,7 +492,14 @@ class MyJSONEncoder(json.JSONEncoder):
return list(o) return list(o)
elif isinstance(o, Citizen): elif isinstance(o, Citizen):
return o.to_json() return o.to_json()
return super().default(o) try:
return super().default(o)
except TypeError as e:
name = None
for ___, ____ in globals().copy().items():
if id(o) == id(____):
name = ___
return dict(__error__=str(e), __type__=str(type(o)), __name__=name)
class BattleSide: class BattleSide:
@ -743,3 +750,11 @@ class TelegramBot:
self.__queue.clear() self.__queue.clear()
return True return True
return False return False
class OfferItem(NamedTuple):
price: float = 99_999.
country: int = 0
amount: int = 0
offer_id: int = 0
citizen_id: int = 0