Package horizons :: Package ai :: Package aiplayer :: Module specialdomestictrademanager
[hide private]
[frames] | no frames]

Source Code for Module horizons.ai.aiplayer.specialdomestictrademanager

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import logging 
 23  from collections import defaultdict 
 24   
 25  from horizons.component.storagecomponent import StorageComponent 
 26   
 27  from .mission.specialdomestictrade import SpecialDomesticTrade 
 28   
 29   
30 -class SpecialDomesticTradeManager:
31 """ 32 An object of this class manages the special domestic trade routes of one AI player. 33 34 These are called the special routes because they transport existing resources while 35 the regular routes transport resources that have been produced for other settlements. 36 37 The current implementation is limited to one active route between each (directed) 38 pair of settlements. The routes are automatically removed when they have 39 been used once or when the ship gets destroyed. 40 """ 41 42 log = logging.getLogger("ai.aiplayer.specialdomestictrade") 43
44 - def __init__(self, owner):
45 super().__init__() 46 self.owner = owner 47 self.world = owner.world 48 self.session = owner.session
49
50 - def _trade_mission_exists(self, source_settlement_manager, destination_settlement_manager):
51 for mission in self.owner.missions: 52 if not isinstance(mission, SpecialDomesticTrade): 53 continue 54 if mission.source_settlement_manager is source_settlement_manager and mission.destination_settlement_manager is destination_settlement_manager: 55 return True 56 return False
57
58 - def _add_route(self):
59 """ 60 Add a new special domestic trade route if possible. 61 62 The route is created between the two settlements that need resources with most 63 value transported between them but the actual mission will be unaware of the 64 initial reasons for creating it and pick up whatever resources need to be 65 transported when it gets to the source warehouse. 66 """ 67 68 ship = None 69 for possible_ship, state in self.owner.ships.items(): 70 if state is self.owner.shipStates.idle: 71 ship = possible_ship 72 break 73 if not ship: 74 #self.log.info('%s no available ships', self) 75 return 76 77 options = defaultdict(list) 78 # try to set up a new route where the first settlement gets an extra shipment of a resource from the second settlement 79 for source_settlement_manager in self.owner.settlement_managers: 80 for destination_settlement_manager in self.owner.settlement_managers: 81 if destination_settlement_manager is source_settlement_manager or self._trade_mission_exists(source_settlement_manager, destination_settlement_manager): 82 continue 83 84 source_resource_manager = source_settlement_manager.resource_manager 85 source_inventory = source_settlement_manager.settlement.get_component(StorageComponent).inventory 86 destination_resource_manager = destination_settlement_manager.resource_manager 87 destination_inventory = destination_settlement_manager.settlement.get_component(StorageComponent).inventory 88 89 for resource_id, limit in destination_resource_manager.resource_requirements.items(): 90 if destination_inventory[resource_id] >= limit: 91 continue # the destination settlement doesn't need the resource 92 if source_inventory[resource_id] <= source_resource_manager.resource_requirements[resource_id]: 93 continue # the source settlement doesn't have a surplus of the resource 94 95 price = self.session.db.get_res_value(resource_id) 96 tradable_amount = min(ship.get_component(StorageComponent).inventory.get_limit(resource_id), limit - destination_inventory[resource_id], 97 source_inventory[resource_id] - source_resource_manager.resource_requirements[resource_id]) 98 options[(source_settlement_manager, destination_settlement_manager)].append((tradable_amount * price, tradable_amount, price, resource_id)) 99 100 if not options: 101 #self.log.info('%s no interesting options', self) 102 return 103 104 final_options = [] 105 for (source_settlement_manager, destination_settlement_manager), option in sorted(options.items()): 106 total_amount = 0 107 total_value = 0 108 for _, amount, price, resource_id in option: 109 amount = min(amount, ship.get_component(StorageComponent).inventory.get_limit(resource_id) - total_amount) 110 total_value += amount * price 111 total_amount += amount 112 final_options.append((total_value, source_settlement_manager, destination_settlement_manager)) 113 114 source_settlement_manager, destination_settlement_manager = max(final_options)[1:] 115 self.owner.start_mission(SpecialDomesticTrade(source_settlement_manager, destination_settlement_manager, ship, self.owner.report_success, self.owner.report_failure))
116
117 - def tick(self):
118 self._add_route()
119
120 - def __str__(self):
121 return '{}.SpecialDomesticTradeManager'.format(self.owner)
122