Passed
Pull Request — master (#242)
by Marek
03:22
created

AIs.ai.AI._get_researchable()   B

Complexity

Conditions 8

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 17
nop 1
dl 0
loc 19
rs 7.3333
c 0
b 0
f 0
1
#
2
#  Copyright 2001 - 2016 Ludek Smid [http://www.ospace.net/]
3
#
4
#  This file is part of Outer Space.
5
#
6
#  Outer Space 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
#  Outer Space 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 Outer Space; if not, write to the Free Software
18
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
#
20
import copy
21
import random
22
from ige import log
23
from ige.ospace import Const
24
from ige.ospace import Rules
25
from ige.ospace import Utils
26
27
import ai_tools as tool
28
29
class AI(object):
30
    def __init__(self, client, enemyTypes=None):
31
        if enemyTypes is None:
32
            enemyTypes = []
33
        self.client = client
34
        self.db = client.db
35
        self.player = client.getPlayer()
36
37
        self.data = tool.tool_parseDB(self.client, self.db, enemyTypes)
38
39
    def economy_manager(self):
40
        raise NotImplementedError
41
42
    def defense_manager(self):
43
        raise NotImplementedError
44
45
    def offense_manager(self):
46
        raise NotImplementedError
47
48
    def _filter_res_requirements(self, techs):
49
        for tech_id in copy.copy(techs):
50
            tech = self.client.getTechInfo(tech_id)
51
            failed_requirements = False
52
            for req_tech, req_tech_improv in tech.researchRequires:
53
                if req_tech not in self.player.techs or self.player.techs[req_tech] < req_tech_improv:
54
                    failed_requirements = True
55
                    break
56
            if failed_requirements:
57
                techs.remove(tech_id)
58
59
    def _get_researchable(self):
60
        researchable = set()
61
        # already available
62
        for tech_id in self.player.techs.keys():
63
            tech = self.client.getTechInfo(tech_id)
64
            improvement = self.player.techs[tech_id]
65
            if improvement < Rules.techMaxImprovement and\
66
                    improvement < tech.maxImprovement:
67
                researchable.add(tech_id)
68
        # new tech
69
        for tech_id in self.client.getAllTechIDs():
70
            tech = self.client.getTechInfo(tech_id)
71
            if not hasattr(tech, "partialData") or not hasattr(tech, 'researchMod'):
72
                continue
73
        for task in self.player.rsrchQueue:
74
            researchable -= set([task.techID])
75
        self._filter_res_requirements(researchable)
76
        print(researchable)
77
        return researchable
78
79
    def research_manager(self, weighted_techs):
80
        """ weighted_techs is dictionary, with weight:list_of_techs pairs
81
        """
82
        if len(self.player.rsrchQueue) >= 2:
83
            return
84
        researchable = self._get_researchable()
85
        weights = []
86
        tech_choices = []
87
        for weight, techs in weighted_techs.iteritems():
88
            for tech in researchable.intersection(techs):
89
                weights.append(weight)
90
                tech_choices.append(tech)
91
        log.debug(techs, weights)
0 ignored issues
show
introduced by
The variable techs does not seem to be defined in case the for loop on line 87 is not entered. Are you sure this can never be the case?
Loading history...
92
        if sum(weights):
93
            tech = Utils.weightedRandom(tech_choices, weights)
94
            self.player.rsrchQueue = self.client.cmdProxy.startResearch(self.player.oid, tech)
95
96
    def _find_best_planet(self, planet_ids):
97
        # right now, it's simply the largest one
98
        max_slots = 0
99
        largest_planet_id = None
100
        for planet_id in planet_ids:
101
            planet = self.db[planet_id]
102
            if max_slots < planet.plSlots:
103
                max_slots = planet.plSlots
104
                largest_planet_id = planet_id
105
        return largest_planet_id
106
107
    def _explore(self, explorer_design_id):
108
        should_repeat = False
109
        explorer_fleets = self.data.myFleetsWithDesign.get(explorer_design_id, set())
110
        for fleet_id in copy.copy(explorer_fleets & self.data.idleFleets):
111
            max_range = tool.subfleetMaxRange(self.client, self.db, {explorer_design_id:1}, fleet_id)
112
            nearest = tool.findNearest(self.db, self.db[fleet_id], self.data.unknownSystems, max_range)
113
            if len(nearest) > 0:
114
                system_id = nearest[0]
115
                # send the fleet
116
                fleet, new_fleet, my_fleets = tool.orderPartFleet(self.client, self.db,
117
                    {explorer_design_id:1}, True, fleet_id, Const.FLACTION_MOVE, system_id, None)
118
                self.data.myFleetSheets[fleet_id][explorer_design_id] -= 1
119
                if self.data.myFleetSheets[fleet_id][explorer_design_id] == 0:
120
                    del self.data.myFleetSheets[fleet_id][explorer_design_id]
121
                    explorer_fleets.remove(fleet_id)
122
                else:
123
                    should_repeat = True
124
                self.data.unknownSystems.remove(system_id)
125
        return should_repeat
126
127
    def _colonize_free_systems(self, valid_systems, colony_design_id):
128
        should_repeat = False
129
        colony_fleets = self.data.myFleetsWithDesign.get(colony_design_id, set())
130
        for fleet_id in copy.copy(colony_fleets & self.data.idleFleets):
131
            max_range = tool.subfleetMaxRange(self.client, self.db, {colony_design_id:1}, fleet_id)
132
            nearest = tool.findNearest(self.db, self.db[fleet_id], valid_systems, max_range)
133
            if len(nearest) > 0:
134
                system_id = nearest[0]
135
                system = self.db[system_id]
136
                target_id = self._find_best_planet(system.planets)
137
                fleet, new_fleet, my_fleets = tool.orderPartFleet(self.client, self.db,
138
                    {colony_design_id:1}, True, fleet_id, Const.FLACTION_DEPLOY, target_id, colony_design_id)
139
                self.data.myFleetSheets[fleet_id][colony_design_id] -= 1
140
                if self.data.myFleetSheets[fleet_id][colony_design_id] == 0:
141
                    del self.data.myFleetSheets[fleet_id][colony_design_id]
142
                    colony_fleets.remove(fleet_id)
143
                else:
144
                    should_repeat = True
145
                self.data.freeSystems.remove(system_id)
146
                valid_systems.remove(system_id)
147
        return should_repeat
148
149
    def diplomacy_manager(self, friendly_types = None, pacts = None):
150
        if friendly_types is None:
151
            return
152
        if pacts is None:
153
            return
154
        for contact_id in self.player.diplomacyRels:
155
            contact = self.client.get(contact_id, publicOnly = True)
156
            if contact.type not in friendly_types:
157
                continue
158
            dipl = self.client.getDiplomacyWith(contact_id)
159
            for pact_id in pacts:
160
                pactSpec = Rules.pactDescrs[pact_id]
161
                if dipl.relation < pactSpec.validityInterval[0] or dipl.relation > pactSpec.validityInterval[1]:
162
                    # not friendly enough
163
                    continue
164
                if pact_id in dipl.pacts and dipl.pacts[pact_id][0] in [Const.PACT_ACTIVE, Const.PACT_INACTIVE]:
165
                    # nothing more to do, move along
166
                    continue
167
                # hey, we should enable this pact!
168
                conditions = [pact_id]
169
                self.player.diplomacyRels = self.client.cmdProxy.changePactCond(self.player.oid, contact_id, pact_id, Const.PACT_INACTIVE, conditions)
170
171
    def run(self):
172
        self.economy_manager()
173
        self.defense_manager()
174
        self.offense_manager()
175
        self.research_manager()
176
        self.diplomacy_manager()
177
178