From 77a1b78ff22aa32eee3029a1cae4a58564f90b07 Mon Sep 17 00:00:00 2001 From: C'tri Goudie Date: Fri, 26 Jan 2024 15:23:59 +0000 Subject: [PATCH 1/2] alter scan behaviour to scan everything possible instead of 20 at a time. --- README.md | 48 +++++---------------------- behaviours/buy_and_deliver_or_sell.py | 7 ++-- behaviours/buy_and_sell_dripfeed.py | 9 ++--- behaviours/explore_system.py | 32 ++++++++---------- behaviours/extract_and_sell.py | 4 +-- behaviours/manage_supply_chain.py | 7 ++-- behaviours/scan_behaviour.py | 39 +++++++++------------- dispatcherWK25.py | 2 ++ 8 files changed, 53 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 43e0ce8..d5bfdb5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ -# Readme outline -Executive Summary +# Executive Summary -An API wrapper for the [SpaceTraders API](https://spacetraders.io/) written in Python. -Implemented as an object-oriented wrapper around the [requests](https://docs.python-requests.org/en/master/) library. +SpaceTraders.io is a headless game that is played via executing commands via the Rest API. +This project contains a series `behaviours` - a set of instructions that a ship follows. -Reinventing the wheel for fun, and to express recent learnings. +The project also contains a `dispatcher` which based on values in a configured data -Eventually will be used to build an interactive gameplay UI built on top of the API. [![PyTest](https://github.com/Ctri-The-Third/SpaceTraders/actions/workflows/main.yml/badge.svg)](https://github.com/Ctri-The-Third/SpaceTraders/actions/workflows/main.yml) @@ -17,38 +15,8 @@ Eventually will be used to build an interactive gameplay UI built on top of the ## Overview -A series of helper classes for interacting with the API. -* `client_api` - directly interacts with the API -* `client_postgres` - updates info in / fetches info from a configured postgres database instead of bothering the API -* `client_pg_logger` - a client that just puts in logs to the postgres database whenever its methods are called (useful for tracking API usage & behaviours efficacy -* `client_stub` - a stub client that just does nothing. -* ✨`client_mediator`✨ - a client that can connect all of the above, checking the DB before bothering the API, feeding API responses into the DB, and logging API calls to the DB. - -All the clients implement the same abstract interface, so can be used interchangably (most useful when going from the basic API class to the mediator class / vice versa.) - -## Setup - -```bash -# build -py setup.py bdist_wheel - -# install -py -m pip install dist/spacetraders-0.4.0-py3-none-any.whl -``` - -## Usage! - -The package has a number of client classes that can be used to interact with the API. They are intended to be largely interchangable. - -Quickstart - API only -```python -from straders_sdk.client_api import SpaceTradersApiClient as SpaceTraders -st = SpaceTraders("") -st.register("SAMPLE_AGENT") -ships = st.ships_view() - for ship in ships: - print (f"{ship.name} is at {ship.nav.waypoint_symbol}") - - -``` +* `dispatcherWK25.py` - takes a user token from the user.json configuration file (or tries to register a user if one is not found) +dispatcher reads the database for behaviours and 1-off tasks and executes matching `behaviours` +* `conductorWK25.py` - assigns behaviours to ships based on the contents of a custom game plan file like or populates its own default game plan. +* `behaviours\` is a folder of python classes that inherit `generic_behaviour.py`. They all execute and initialise in the same way, and can be run from command line, or automatically the dispatcher. diff --git a/behaviours/buy_and_deliver_or_sell.py b/behaviours/buy_and_deliver_or_sell.py index 0c8c704..e49cf78 100644 --- a/behaviours/buy_and_deliver_or_sell.py +++ b/behaviours/buy_and_deliver_or_sell.py @@ -62,9 +62,10 @@ def run(self): self.end() def end(self): - self.st.logging_client.log_ending( - BEHAVIOUR_NAME, self.ship.name, self.st.view_my_self().credits - ) + if self.ship: + self.st.logging_client.log_ending( + BEHAVIOUR_NAME, self.ship_name, self.st.view_my_self().credits + ) super().end() def default_params_obj(self): diff --git a/behaviours/buy_and_sell_dripfeed.py b/behaviours/buy_and_sell_dripfeed.py index fb776e8..31fb961 100644 --- a/behaviours/buy_and_sell_dripfeed.py +++ b/behaviours/buy_and_sell_dripfeed.py @@ -205,14 +205,15 @@ def sell_half(self): self.sell_cargo(self.target_tradegood, amount_to_sell, sell_market_mkt) def end(self, error=None): - super().end() - self.st.logging_client.log_ending( - BEHAVIOUR_NAME, self.ship.name, self.agent.credits - ) + if self.ship: + self.st.logging_client.log_ending( + BEHAVIOUR_NAME, self.ship.name, self.agent.credits + ) if error: self.logger.error(error) self.st.release_connection() self.st.sleep(SAFETY_PADDING) + super().end() def find_cheapest_markets_for_good(self, tradegood_sym: str) -> list[str]: sql = """select market_symbol from market_tradegood_listings diff --git a/behaviours/explore_system.py b/behaviours/explore_system.py index 9130c97..69c8ee4 100644 --- a/behaviours/explore_system.py +++ b/behaviours/explore_system.py @@ -14,6 +14,7 @@ import time BEHAVIOUR_NAME = "EXPLORE_ONE_SYSTEM" +SAFETY_PADDING = 180 class ExploreSystem(Behaviour): @@ -65,7 +66,7 @@ def _run(self): st = self.st agent = st.view_my_self() # check all markets in the system - o_sys = st.systems_view_one(ship.nav.system_symbol) + self.o_sys = o_sys = st.systems_view_one(ship.nav.system_symbol) path = None if self.behaviour_params and "target_sys" in self.behaviour_params: @@ -76,7 +77,7 @@ def _run(self): st.system_jumpgate(jg, True) path = self.pathfinder.astar(o_sys, d_sys, force_recalc=True) else: - d_sys = self.find_unexplored_jumpgate() + d_sys = self.route_to_unexplored_jumpgate() if d_sys: d_sys = st.systems_view_one(d_sys) if not d_sys: @@ -120,23 +121,15 @@ def _run(self): # travel to target system # scan target system - def find_unexplored_jumpgate(self): - hq_sys_sym = waypoint_slicer(self.agent.headquarters) - sql = """select count(*) from jumpgate_connections""" - rows = try_execute_select(self.connection, sql, ()) - if not rows or rows[0][0] == 0: - jump_gate = self.st.find_waypoints_by_type_one(hq_sys_sym, "JUMP_GATE") - if not jump_gate: - return None - self.st.system_jumpgate(jump_gate) - - sql = """select system_symbol from systems_on_network_but_uncharted - order by random() - limit 1 """ - rows = try_execute_select(self.connection, sql, ()) - if not rows: + def route_to_unexplored_jumpgate(self): + source = self.st.find_waypoints_by_type(self.o_sys.symbol, "JUMP_GATE") + if not source: + self.st.sleep(SAFETY_PADDING) return None - return rows[0][0] + + gate = self.st.system_jumpgate(source[0], True) + for connected_system in gate.connected_waypoints: + print(connection) if __name__ == "__main__": @@ -147,7 +140,8 @@ def find_unexplored_jumpgate(self): ship_number = sys.argv[2] if len(sys.argv) > 2 else "1" ship = f"{agent}-{ship_number}" behaviour_params = None - behaviour_params = {"priority": 3.5, "target_sys": "X1-DZ36"} # X1-TF72 X1-YF83 + # behaviour_params = {"priority": 3.5, "target_sys": "X1-DZ36"} # X1-TF72 X1-YF83 + behaviour_params = {"priority": 3.5} bhvr = ExploreSystem(agent, ship, behaviour_params or {}) lock_ship(ship, "MANUAL", duration=120) diff --git a/behaviours/extract_and_sell.py b/behaviours/extract_and_sell.py index a7eba8b..c501016 100644 --- a/behaviours/extract_and_sell.py +++ b/behaviours/extract_and_sell.py @@ -233,11 +233,11 @@ def get_market_and_jettison_waste( from dispatcherWK16 import lock_ship agent = sys.argv[1] if len(sys.argv) > 2 else "CTRI-U-" - ship_number = sys.argv[2] if len(sys.argv) > 2 else "1" + ship_number = sys.argv[2] if len(sys.argv) > 2 else "23" ship = f"{agent}-{ship_number}" set_logging(logging.DEBUG) behaviour_params = { - "asteroid_wp": "X1-PK16-B40", + "asteroid_wp": "X1-TN14-C40", "script_name": "EXTRACT_AND_SELL", "cargo_to_transfer": ["*"], } diff --git a/behaviours/manage_supply_chain.py b/behaviours/manage_supply_chain.py index 4c9e791..717caa1 100644 --- a/behaviours/manage_supply_chain.py +++ b/behaviours/manage_supply_chain.py @@ -84,9 +84,10 @@ def run(self): self.end() def end(self): - self.st.logging_client.log_ending( - BEHAVIOUR_NAME, self.ship.name, self.st.view_my_self().credits - ) + if self.ship: + self.st.logging_client.log_ending( + BEHAVIOUR_NAME, self.ship.name, self.st.view_my_self().credits + ) super().end() def _run(self): diff --git a/behaviours/scan_behaviour.py b/behaviours/scan_behaviour.py index 635bb03..f848327 100644 --- a/behaviours/scan_behaviour.py +++ b/behaviours/scan_behaviour.py @@ -80,40 +80,31 @@ def _run(self): # rows = [1] wayps = [1] + self.pathfinder.load_jump_graph_from_db() + self.pathfinder.save_graph() + while len(wayps) > 0 or len(rows) > 0: wayps = ( - self.get_twenty_unscanned_waypoints("ORBITAL_STATION") - or self.get_twenty_unscanned_waypoints("ASTEROID_FIELD") - or self.get_twenty_unscanned_waypoints("JUMP_GATE") - or self.get_twenty_unscanned_waypoints("PLANET") - or self.get_twenty_unscanned_waypoints("MOON") - or [] + self.get_unscanned_waypoints("JUMP_GATE") + + self.get_unscanned_waypoints("ORBITAL_STATION") + + self.get_unscanned_waypoints("ASTEROID_FIELD") + + self.get_unscanned_waypoints("PLANET") + + self.get_unscanned_waypoints("MOON") ) for wayp in wayps: resp = st.waypoints_view_one(wayp[0], True) + if resp.type == "JUMP_GATE": + st.system_jumpgate(resp, True) + if "MARKETPLACE" in [trait.symbol for trait in resp.traits]: + st.system_market(resp, True) + if "SHIPYARD" in [trait.symbol for trait in resp.traits]: + st.system_shipyard(resp, True) # # get 20 unscanned jump gates # - rows = self.get_twenty_unscanned_jumpgates() - - for row in rows: - jump_gate_sym = row[0] - sys = waypoint_slicer(jump_gate_sym) - - wp = st.waypoints_view_one(jump_gate_sym) - if not wp.is_charted: - wp = st.waypoints_view_one(jump_gate_sym, True) - if not wp.is_charted: - continue - resp = st.system_jumpgate(wp, True) - if ship.seconds_until_cooldown > 0: - continue - if ship.nav.travel_time_remaining > 0: - continue - # # MARKETS and SHIPYARDS # @@ -149,7 +140,7 @@ def _run(self): st.logging_client.log_ending(BEHAVIOUR_NAME, ship.name, agent.credits) - def get_twenty_unscanned_waypoints(self, type: str = r"%s") -> list[str]: + def get_unscanned_waypoints(self, type: str = r"%s") -> list[str]: sql = """ select * from waypoints_not_scanned where type = %s diff --git a/dispatcherWK25.py b/dispatcherWK25.py index 0e69ab6..235a744 100644 --- a/dispatcherWK25.py +++ b/dispatcherWK25.py @@ -430,11 +430,13 @@ def map_behaviour_to_class( def upload_behaviour_definitions(self): for behaviour_id, bhvr_class in behaviours_and_classes.items(): bhvr_obj = bhvr_class("", "", {}) + bhvr_obj: Behaviour params = json.dumps(bhvr_obj.default_params_obj()) sql = "insert into behaviour_definitions (behaviour_id, default_params) values (%s, %s) on conflict (behaviour_id) do update set default_params = EXCLUDED.default_params;" try_execute_upsert(sql, (behaviour_id, params), self.connection) + bhvr_obj.end() pass def maybe_scan_all_systems(self): From 5203e2c613faa6608aa538b4bfa86b98fdc05eaa Mon Sep 17 00:00:00 2001 From: C'tri Goudie Date: Fri, 26 Jan 2024 15:24:26 +0000 Subject: [PATCH 2/2] Update generic_behaviour.py --- behaviours/generic_behaviour.py | 1 + 1 file changed, 1 insertion(+) diff --git a/behaviours/generic_behaviour.py b/behaviours/generic_behaviour.py index d6517a6..8cb499e 100644 --- a/behaviours/generic_behaviour.py +++ b/behaviours/generic_behaviour.py @@ -589,6 +589,7 @@ def fulfil_any_relevant(self, excpetions: list = []): if self.ship.nav.status != "DOCKED": self.st.ship_dock(self.ship) + matching_items = None for cargo in self.ship.cargo_inventory: matching_items = [item for item in items if item.symbol == cargo.symbol] if not matching_items: