Passed
Push — master ( 3da424...a0c806 )
by Marek
01:50
created

AIs.ais_renegade.systemManager()   F

Complexity

Conditions 15

Size

Total Lines 50
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 46
nop 0
dl 0
loc 50
rs 2.9998
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like AIs.ais_renegade.systemManager() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 random
21
22
from ige import log
23
from ige.ospace import Const
24
from ige.ospace import Rules
25
26
from ai import AI
27
import ai_tools as tool
28
29
30
class Renegade(AI):
31
    """ Renegade is purely defensive AI, very static. It allows CP pacts and refuel
32
    for civilian ships, and has 5 pregenerated designs.
33
34
    1: Fighter [Small hull, Cockpit, 1x Cannon, 2x STL Engine]
35
    2: Corvette [Small hull, Cockpit, 2x Cannon, 1x Steel Armor, 1x STL Engine]
36
    3: Frigate [Medium hull, Bridge, 2x Cannon, 2x SS Rocket, 2x STL Engine]
37
    special using uranium:
38
    4: Destroyer [Medium hull, Bridge, 4x Cannon, 2x SS Rocket, 3x Nuclear STL Engine]
39
    special using titanium:
40
    5: Frigate [Crude Titanium Medium hull, Bridge, 5x Cannon, 3x SS Rocket, 4x STL Engine]
41
    """
42
43
    def _build_special_ships(self, planet):
44
        uranium_spec = self.player.shipDesigns[4]
45
        titanium_spec = self.player.shipDesigns[5]
46
        if self.player.stratRes.get(Const.SR_TL1A, 0) >= uranium_spec.buildSRes[Const.SR_TL1A]:
47
            planet.prodQueue, self.player.stratRes = self.client.cmdProxy.startConstruction(planet.oid, 4, 1, planet.oid, True, False, Const.OID_NONE)
48
            return True
49
        elif self.player.stratRes.get(Const.SR_TL1B, 0) >= titanium_spec.buildSRes[Const.SR_TL1B]:
50
            planet.prodQueue, self.player.stratRes = self.client.cmdProxy.startConstruction(planet.oid, 5, 1, planet.oid, True, False, Const.OID_NONE)
51
            return True
52
53
    def _build_normal_ships(self, planet):
54
            ship_draw = random.randint(1, 10)
55
            # if there is enough special resources for our unique designs, build those!
56
            # 1/10 - Frigate
57
            # 3/10 - Corvette
58
            # 6/10 - Fighter
59
            if ship_draw == 1:
60
                planet.prodQueue, self.player.stratRes = self.client.cmdProxy.startConstruction(planet.oid, 3, 1, planet.oid, True, False, Const.OID_NONE)
61
            elif ship_draw <= 4:
62
                planet.prodQueue, self.player.stratRes = self.client.cmdProxy.startConstruction(planet.oid, 2, 1, planet.oid, True, False, Const.OID_NONE)
63
            else:
64
                planet.prodQueue, self.player.stratRes = self.client.cmdProxy.startConstruction(planet.oid, 1, 1, planet.oid, True, False, Const.OID_NONE)
65
66
    def _build_ships(self, idle_planets):
67
        for planet_id in idle_planets:
68
            planet = self.db[planet_id]
69
            if self._build_special_ships(planet):
70
                continue
71
            self._build_normal_ships(planet)
72
73
    def _prepare_free_planet_plan(self, planet_id):
74
        return {Rules.Tech.RENEGADEBASE:1}
75
76
    def _prepare_planet_plan(self, actual_stats, planet_id):
77
        planet = self.db[planet_id]
78
        if Rules.Tech.RENEGADECOSMODROME in actual_stats.planets[planet_id] or\
79
                Rules.Tech.RENEGADEBASE3 in actual_stats.planets[planet_id] or\
80
                Rules.Tech.RENEGADEBASE3MINOR in actual_stats.planets[planet_id]:
81
            return {Rules.Tech.RENEGADEBASE3:1,
82
                    Rules.Tech.RENEGADECOSMODROME:min(planet.plSlots - 1, 1),
83
                    Rules.Tech.RENEGADEBASE3MINOR:max(planet.plSlots - 2, 0)}
84
        elif planet.plStratRes and\
85
                tool.compareBuildStructPlans(actual_stats.planets[planet_id], {
86
                                            Rules.Tech.RENEGADEBASE2:1,
87
                                            Rules.Tech.RENEGADEBASE2MINOR:planet.plSlots - 1}):
88
            return {Rules.Tech.RENEGADEBASE3:1,
89
                    Rules.Tech.RENEGADEBASE2MINOR:planet.plSlots - 1}
90
        elif Rules.Tech.RENEGADEBASE2 in actual_stats.planets[planet_id]:
91
            return {Rules.Tech.RENEGADEBASE2:1,
92
                    Rules.Tech.RENEGADEBASE2MINOR:planet.plSlots - 1}
93
        elif Rules.Tech.RENEGADEBASE in actual_stats.planets[planet_id] and planet_id in self.data.myPlanets:
94
            planet.prodQueue, self.player.stratRes = \
95
                    self.client.cmdProxy.startConstruction(planet_id, Rules.Tech.RENEGADEBASE2,
96
                                                      1, planet_id, False, False, Rules.Tech.RENEGADEBASE)
97
            return actual_stats.planets[planet_id]
98
        else:
99
            return {Rules.Tech.RENEGADEBASE:1}
100
101
    def economy_manager(self):
102
        for planet_id in self.data.myPlanets:
103
            tool.sortStructures(self.client, self.db, planet_id)
104
        for system_id in self.data.mySystems:
105
            system = self.db[system_id]
106
            # creation of final system plans
107
            final_system_plan = {}
108
            actual_stats = tool.getSystemStructStats(self.data, self.client, self.db, system_id)
109
            build_stats = tool.getSystemStructStats(self.data, self.client, self.db, system_id, False)
110
            for planet_id in self.data.myPlanets & set(system.planets):
111
                final_system_plan[planet_id] = self._prepare_planet_plan(actual_stats, planet_id)
112
            for planet_id in self.data.freePlanets & set(system.planets):
113
                final_system_plan[planet_id] = self._prepare_free_planet_plan(planet_id)
114
            idle_planets = tool.buildSystem(self.data, self.client, self.db, system_id, self.data.myProdPlanets & set(system.planets), final_system_plan)
115
            # build ships just in case cosmodrome is present, or being build, in the system
116
            has_cosmodrome = False
117
            for planet_id in self.data.myPlanets & set(system.planets):
118
                if Rules.Tech.RENEGADECOSMODROME in build_stats.planets[planet_id]:
119
                    has_cosmodrome = True
120
                    break
121
            if has_cosmodrome:
122
                self._build_ships(idle_planets)
123
124
    def run(self):
125
        self.economy_manager()
126
        self.diplomacy_manager(friendly_types=[Const.T_PLAYER, Const.T_AIPLAYER, Const.T_AIRENPLAYER],
127
                               pacts=[Const.PACT_ALLOW_CIVILIAN_SHIPS, Const.PACT_ALLOW_TANKING,
128
                                      Const.PACT_MINOR_CP_COOP, Const.PACT_MAJOR_CP_COOP])
129
130
131
def run(aclient):
132
    ai = Renegade(aclient)
133
    ai.run()
134
    aclient.saveDB()
135
136