ige.ospace.GalaxyGenerator.generatePlanet()   F
last analyzed

Complexity

Conditions 50

Size

Total Lines 85
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 50
eloc 73
nop 2
dl 0
loc 85
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like ige.ospace.GalaxyGenerator.generatePlanet() 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
21
import math
22
import os
23
import random
24
import sys
25
import tempfile
26
27
import data
28
29
import Const
30
31
class GalaxyTemplate(object):
32
    def __init__(self):
33
        self.galaxyType = self.__class__.__name__
34
        self.scenario = Const.SCENARIO_NONE
35
        self.minPlanets = 0
36
        self.maxPlanets = 0
37
        self.startR = (0.0, 999.0)
38
        self.players = 0
39
        self.playerGroup = 0
40
        self.groupDist = 0
41
        self.minR = 0
42
        # format {maxRadius: density, nextCircleRadius: differentDensity}
43
        self.density = {1: 1, 2: 2}
44
        self.minSystemLoneliness = 1.5
45
        self.maxSystemLoneliness = 5
46
        self.resources = {
47
            # format resourceID : [(minDist, maxDist, number of resources)]
48
            #Const.SR_TL1A : [(0, 0, 0)]
49
        }
50
        self.diseases = {
51
            # format diseaseID : (minDist, maxDist, number of diseases)
52
            #Const.DISEASE_MUTANT : [(0, 0, 0)]
53
        }
54
55
    @property
56
    def center(self):
57
        return (self.radius, self.radius)
58
59
    @property
60
    def radius(self):
61
        # making radius a bit bigger, as that is used in minimaps and chronicler
62
        return max(self.density.keys()) + 2
63
64 View Code Duplication
class Circle1SP(GalaxyTemplate):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
65
    def __init__(self):
66
        super(Circle1SP, self).__init__()
67
68
        self.scenario = Const.SCENARIO_SINGLE
69
        self.minPlanets = 100
70
        self.maxPlanets = 150
71
        self.startR = (9.0, 11.0)
72
        self.players = 1
73
        self.playerGroup = 1
74
        self.groupDist = 0
75
        self.minR = 2
76
        # format {minRadius: density, nextCircleRadius: differentDensity}
77
        self.density = {2: 4, 5: 4, 12: 4.5}
78
        self.resources = {
79
            # format resourceID : [(minDist, maxDist, number of resources)]
80
            Const.SR_TL1A : [(11, 13, 2)],
81
            Const.SR_TL1B : [(11, 13, 2)]
82
        }
83
        self.diseases = {
84
            # format diseaseID : (minDist, maxDist, number of diseases)
85
            Const.DISEASE_MUTANT : [(2, 5, 3)]
86
        }
87
88
89
class Circle3BP(Circle1SP):
90
    def __init__(self):
91
        super(Circle3BP, self).__init__()
92
93
        self.minPlanets = int(1.3 * self.minPlanets)
94
        self.maxPlanets = int(1.2 * self.maxPlanets)
95
        self.scenario = Const.SCENARIO_BRAWL
96
        self.startR = (0.0, 0.0)
97
        self.players = 3
98
        self.playerGroup = 3
99
        self.groupDist = 10
100
        self.resources = {
101
            # format resourceID : [(minDist, maxDist, number of resources)]
102
            Const.SR_TL1A : [(11, 13, 3)],
103
            Const.SR_TL1B : [(11, 13, 3)]
104
        }
105
        self.diseases = {}
106
107
108 View Code Duplication
class Circle3SP(GalaxyTemplate):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
109
    def __init__(self):
110
        super(Circle3SP, self).__init__()
111
112
        self.scenario = Const.SCENARIO_SINGLE
113
        self.minPlanets = 280
114
        self.maxPlanets = 350
115
        self.startR = (13.0, 15.0)
116
        self.players = 3
117
        self.playerGroup = 3
118
        self.groupDist = 3
119
        self.minR = 2
120
        # format {minRadius: density, nextCircleRadius: differentDensity}
121
        self.density = {2: 2.5, 6: 4, 12: 4.5, 20: 5}
122
        self.resources = {
123
            # format resourceID : [(minDist, maxDist, number of resources)]
124
            Const.SR_TL1A : [(15, 17, 3)],
125
            Const.SR_TL1B : [(15, 17, 3)]
126
        }
127
        self.diseases = {
128
            # format diseaseID : (minDist, maxDist, number of diseases)
129
            Const.DISEASE_MUTANT : [(2, 4, 3)]
130
        }
131
132
class Circle2CP(Circle3SP):
133
    def __init__(self):
134
        super(Circle2CP, self).__init__()
135
136
        self.players = 2
137
        self.playerGroup = 2
138
        self.scenario = Const.SCENARIO_COOP
139
140
        self.diseases = {
141
            # format diseaseID : (minDist, maxDist, number of diseases)
142
            Const.DISEASE_MUTANT : [(2, 4, 4)]
143
        }
144
145
class Circle3CP(Circle3SP):
146
    def __init__(self):
147
        super(Circle3CP, self).__init__()
148
149
        self.scenario = Const.SCENARIO_COOP
150
        self.diseases = {
151
            # format diseaseID : (minDist, maxDist, number of diseases)
152
            Const.DISEASE_MUTANT : [(2, 4, 5)]
153
        }
154
155
156
class Circle5BP(Circle3SP):
157
    def __init__(self):
158
        super(Circle5BP, self).__init__()
159
160
        self.scenario = Const.SCENARIO_BRAWL
161
        self.startR = (0.0, 0.0)
162
        self.players = 5
163
        self.playerGroup = 5
164
        self.groupDist = 10
165
        self.resources = {
166
            # format resourceID : [(minDist, maxDist, number of resources)]
167
            Const.SR_TL1A : [(15, 17, 5)],
168
            Const.SR_TL1B : [(15, 17, 5)]
169
        }
170
        self.diseases = {}
171
172
173
class Circle9P(GalaxyTemplate):
174
    def __init__(self):
175
        super(Circle9P, self).__init__()
176
177
        self.scenario = Const.SCENARIO_OUTERSPACE
178
        self.minPlanets = 500
179
        self.maxPlanets = 600
180
        self.startR = (15.0, 18.0)
181
        self.players = 9
182
        self.playerGroup = 3
183
        self.groupDist = 4
184
        self.minR = 5
185
        # format {minRadius: density, nextCircleRadius: differentDensity}
186
        self.density = {5: 4, 10: 4.5, 20: 4.5, 26: 5}
187
        self.resources = {
188
            # format resourceID : [(minDist, maxDist, number of resources)]
189
            Const.SR_TL1A : [(20, 25, 6)],
190
            Const.SR_TL1B : [(20, 25, 6)]
191
        }
192
        self.diseases = {
193
            # format diseaseID : (minDist, maxDist, number of diseases)
194
            Const.DISEASE_MUTANT : [(13, 20, 6), (5, 9, 6)]
195
        }
196
197 View Code Duplication
class Circle42P(GalaxyTemplate):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
198
    def __init__(self):
199
        super(Circle42P, self).__init__()
200
201
        self.scenario = Const.SCENARIO_OUTERSPACE
202
        self.minPlanets = 1500
203
        self.maxPlanets = 1800
204
        self.startR = (32.0, 36.0)
205
        self.players = 42
206
        self.playerGroup = 3
207
        self.groupDist = 4
208
        self.minR = 7.5
209
        # format {minRadius: density, nextCircleRadius: differentDensity}
210
        self.density = {7.5: 3, 10: 4, 20: 5, 30: 5.5, 40: 6, 50: 6}
211
        self.resources = {
212
            # format resourceID : [(minDist, maxDist, number of resources)]
213
            Const.SR_TL1A : [(20, 45, 15)],
214
            Const.SR_TL1B : [(20, 45, 15)],
215
            Const.SR_TL3A : [(8, 15, 7)],
216
            Const.SR_TL3B : [(8, 15, 7)],
217
            Const.SR_TL3C : [(8, 15, 7)],
218
            Const.SR_TL5A : [(7.5, 9, 1)],
219
            Const.SR_TL5B : [(7.5, 9, 1)],
220
            Const.SR_TL5C : [(7.5, 9, 1)]
221
        }
222
        self.diseases = {
223
            # format diseaseID : (minDist, maxDist, number of diseases)
224
            Const.DISEASE_MUTANT : [(20, 45, 16), (5, 15, 12), (0, 5, 3)]
225
        }
226
227 View Code Duplication
class Circle65P(GalaxyTemplate):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
228
    def __init__(self):
229
        super(Circle65P, self).__init__()
230
231
        self.scenario = Const.SCENARIO_OUTERSPACE
232
        self.minPlanets = 3200
233
        self.maxPlanets = 3500
234
        self.startR = (45.0, 52.5)
235
        self.players = 65
236
        self.playerGroup = 5
237
        self.groupDist = 8
238
        self.minR = 7.5
239
        # format {minRadius: density, nextCircleRadius: differentDensity}
240
        self.density = {7.5: 3, 10: 4, 20: 5, 30: 5.5, 60: 6, 75: 6}
241
        self.resources = {
242
            # format resourceID : [(minDist, maxDist, number of resources)]
243
            Const.SR_TL1A : [(20, 67.5, 45)],
244
            Const.SR_TL1B : [(20, 67.5, 45)],
245
            Const.SR_TL3A : [(10, 20, 10)],
246
            Const.SR_TL3B : [(10, 20, 10)],
247
            Const.SR_TL3C : [(10, 20, 10)],
248
            Const.SR_TL5A : [(7.5, 9, 2)],
249
            Const.SR_TL5B : [(7.5, 9, 2)],
250
            Const.SR_TL5C : [(7.5, 9, 2)]
251
        }
252
        self.diseases = {
253
            # format diseaseID : (minDist, maxDist, number of diseases)
254
            Const.DISEASE_MUTANT : [(20, 67.5, 32), (5, 15, 18), (0, 5, 6)]
255
        }
256
257
class Test(GalaxyTemplate):
258
    def __init__(self):
259
        super(Test, self).__init__()
260
261
        self.scenario = Const.SCENARIO_OUTERSPACE
262
        self.minPlanets = 0
263
        self.maxPlanets = 200
264
        self.startR = (1.0, 7.0)
265
        self.players = 1
266
        self.playerGroup = 1
267
        self.groupDist = 1
268
        self.minR = 1
269
        # format {minRadius: density, nextCircleRadius: differentDensity}
270
        self.density = {1:1, 7: 2}
271
        self.resources = {
272
            # format resourceID : [(minDist, maxDist, number of resources)]
273
            Const.SR_TL1A : [(1, 7, 1)],
274
            Const.SR_TL1B : [(1, 7, 1)],
275
            Const.SR_TL3A : [(1, 7, 1)],
276
            Const.SR_TL3B : [(1, 7, 1)],
277
            Const.SR_TL3C : [(1, 7, 1)],
278
            Const.SR_TL5A : [(1, 7, 1)],
279
            Const.SR_TL5B : [(1, 7, 1)],
280
            Const.SR_TL5C : [(1, 7, 1)]
281
        }
282
        self.diseases = {
283
            # format diseaseID : (minDist, maxDist, number of diseases)
284
            Const.DISEASE_MUTANT : [(1, 7, 2)]
285
        }
286
287
class GalaxyGenerator:
288
    def __init__(self):
289
        self.templates = {}
290
        # TODO: I guess we can autodetect this somehow, in a future
291
        for templateClass in [Circle1SP, Circle3BP, Circle2CP, Circle3SP, Circle3CP, Circle5BP, Circle9P, Circle42P, Circle65P, Test]:
292
            templateInstance = templateClass()
293
            self.templates[templateInstance.galaxyType] = templateInstance
294
295
    def generateGalaxy(self, galaxyType):
296
        if not galaxyType in self.templates:
297
            return False
298
        while True:
299
            try:
300
                galaxy = generateGalaxy2(self.templates[galaxyType])
301
                break
302
            except IndexError:
303
                # this happens, if generator fails to place special
304
                # planet - easier than handling it inside is to roll
305
                # dice again
306
                continue
307
        self.shiftSystems(galaxy)
308
309
        return self.saveGalaxy(galaxy)
310
311
    def getGalaxyTypes(self):
312
        return self.templates.keys()
313
314
    def getGalaxyTemplate(self, galaxyType):
315
        return self.templates[galaxyType]
316
317
    def saveGalaxy(self, galaxy):
318
        """ saving galaxy - instance of Galaxy object into xml-formated file
319
320
            returns file name
321
        """
322
        # names
323
        loadSystemNames()
324
        fileHandle, galaxyFileName = tempfile.mkstemp(text = True)
325
        fh = os.fdopen(fileHandle, "w")
326
        # save
327
        print >>fh, '<?xml version="1.0" encoding="UTF-8"?>'
328
        print >>fh, '<universe>'
329
        print >>fh, '\t<galaxy galaxyType="%s" x="%.2f" y="%.2f">' % (
330
            galaxy.galaxyType, galaxy.centerX, galaxy.centerY
331
        )
332
        print >>fh, '\t\t<properties radius="%.2f" scenario="%s"/>' % (galaxy.radius, galaxy.scenario)
333
        for system in galaxy.systems:
334
            self.saveSystem(fh, system)
335
        print >>fh, '\t</galaxy>'
336
        print >>fh, '</universe>'
337
        fh.close()
338
        return galaxyFileName
339
340
    def saveSystem(self, fh, system):
341
        print >>fh, '\t\t<system x="%.2f" y="%.2f">' % (system.x, system.y)
342
        # name = 'SCN-%04d%04d' % (system.x * 10, system.y * 10)
343
        global systemNames
344
        name = random.choice(systemNames)
345
        systemNames.remove(name)
346
        print >>fh, '\t\t\t<properties starClass="%s%d" name="%s"/>' % \
347
            (system.starClass, system.starSubclass, name)
348
        for planet in system.planets:
349
            self.savePlanet(fh, planet)
350
        print >>fh, '\t\t</system>'
351
352
    def savePlanet(self, fh, planet):
353
        print >>fh, '\t\t\t<planet>'
354
        print >>fh, '\t\t\t\t<properties plType="%s" plMin="%d" plBio="%d" plEn="%d" plDiameter="%d" plSlots="%d" plMaxSlots="%d" plStratRes="%d" plDisease="%d" plStarting="%d"/>' % \
355
            (planet.type, planet.minerals, planet.environ, planet.energy, planet.diameter, planet.slots, planet.maxSlots, planet.strategicRes, planet.disease, planet.starting)
356
        if planet.starting:
357
            print >>fh, '\t\t\t\t<startingpoint/>'
358
        print >>fh, '\t\t\t</planet>'
359
360
    def shiftSystems(self, galaxy):
361
        """ makes sure no two systems are closer than _min and there are
362
            no systems further than _max parsecs from their closest three neighbours).
363
364
            Quite naive implementation."""
365
        MAX_STEP = 25
366
        DELTA = 0.25
367
        galaxyTemplate = self.templates[galaxy.galaxyType]
368
        _min = galaxyTemplate.minSystemLoneliness
369
        _max = galaxyTemplate.maxSystemLoneliness
370
        for i in xrange(MAX_STEP):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable xrange does not seem to be defined.
Loading history...
371
            newMin, newMax = self._shiftSystems(galaxy, _min, _max, DELTA)
372
            if newMin >= _min and newMax <= _max:
373
                break
374
375
    def _shiftSystems(self, galaxy, _min, _max, delta):
376
        # _min and _max are squared, so dist frequently calculated later
377
        # doesn't have to be square rooted
378
        print 'Shifting...'
379
        _min = _min * _min
380
        _max = _max * _max
381
        minMinDist = 1000000
382
        maxMinDist = 0
383
        for system1 in galaxy.systems:
384
            if not system1._moveable:
385
                continue
386
            minDist = [1000000, 100000, 100000]
387
            closestSystems = [None, None, None]
388
            for system2 in galaxy.systems:
389
                if system1 == system2 or not system2._moveable:
390
                    continue
391
                dist = (system1.x - system2.x) ** 2 + (system1.y - system2.y) ** 2
392
                if dist < minDist[0]:
393
                    minDist.pop()
394
                    minDist.insert(0, dist)
395
                    closestSystems.pop()
396
                    closestSystems.insert(0, system2)
397
                elif dist < minDist[1]:
398
                    minDist.pop()
399
                    minDist.insert(1, dist)
400
                    closestSystems.pop()
401
                    closestSystems.insert(1, system2)
402
                elif dist < minDist[2]:
403
                    minDist.pop()
404
                    minDist.insert(2, dist)
405
                    closestSystems.pop()
406
                    closestSystems.insert(2, system2)
407
            system1._closest = closestSystems
408
            for closestSystem in closestSystems:
409
                if not closestSystem:
410
                    continue
411
                # this has to be calculated again, even though we had it before in minDist
412
                # because every move can alter others
413
                dist = (system1.x - closestSystem.x) ** 2 + (system1.y - closestSystem.y) ** 2
414
                if dist < _min and closestSystem:
415
                    # move system away
416
                    if system1.x > closestSystem.x:
417
                        system1.x += random.uniform(0, delta)
418
                        closestSystem.x -= random.uniform(0, delta)
419
                    else:
420
                        system1.x -= random.uniform(0, delta)
421
                        closestSystem.x += random.uniform(0, delta)
422
                    if system1.y > closestSystem.y:
423
                        system1.y += random.uniform(0, delta)
424
                        closestSystem.y -= random.uniform(0, delta)
425
                    else:
426
                        system1.y -= random.uniform(0, delta)
427
                        closestSystem.y += random.uniform(0, delta)
428
                elif dist > _max and closestSystem:
429
                    # move systems closer
430
                    if system1.x < closestSystem.x:
431
                        system1.x += random.uniform(0, delta)
432
                        closestSystem.x -= random.uniform(0, delta)
433
                    else:
434
                        system1.x -= random.uniform(0, delta)
435
                        closestSystem.x += random.uniform(0, delta)
436
                    if system1.y < closestSystem.y:
437
                        system1.y += random.uniform(0, delta)
438
                        closestSystem.y -= random.uniform(0, delta)
439
                    else:
440
                        system1.y -= random.uniform(0, delta)
441
                        closestSystem.y += random.uniform(0, delta)
442
                if dist < minMinDist: minMinDist = dist
443
                if dist > maxMinDist: maxMinDist = dist
444
        print 'Finished [min. dist = <%.2f; %.2f>]' % (math.sqrt(minMinDist), math.sqrt(maxMinDist))
445
        return math.sqrt(minMinDist), math.sqrt(maxMinDist)
446
447
class Galaxy:
448
449
    def __init__(self):
450
        self.systems = []
451
        self.centerX = 0.0
452
        self.centerY = 0.0
453
        self.radius = 0.0
454
455
class System:
456
457
    def __init__(self):
458
        self.x = 0.0
459
        self.y = 0.0
460
        self.name = '?'
461
        self.compOf = None
462
        self.starClass = '?'
463
        self.starSubclass = 0
464
        self.planets = []
465
        self._closest = []
466
        self.hasSR = 0
467
        self.hasDisease = 0
468
        self._moveable = 1
469
470
class Planet:
471
472
    def __init__(self):
473
        self.compOf = None
474
        self.type = '?'
475
        self.diameter = 0
476
        self.minerals = 0
477
        self.environ = 0
478
        self.energy = 0
479
        self.slots = 0
480
        self.maxSlots = 0
481
        self.starting = 0
482
        self.strategicRes = 0
483
        self.disease = 0
484
485
def generateGalaxy2(galaxyTemplate):
486
    galaxy = Galaxy()
487
    stats = galaxyTemplate
488
    galaxy.galaxyType = stats.galaxyType
489
    galaxy.centerX, galaxy.centerY = stats.center
490
    galaxy.radius = stats.radius
491
    galaxy.scenario = stats.scenario
492
    r = stats.minR + random.uniform(0, 0.5)
493
    dkeys = stats.density.keys()
494
    dkeys.sort()
495
    dkeys.reverse()
496
    prevR = 5
497
    while r <= galaxy.radius:
498
        for key in dkeys:
499
            if key <= r:
500
                density = stats.density[key]
501
                break
502
        d = 2 * math.pi * r
503
        aoff = random.uniform(0, math.pi * 2)
504
        dangle = density / d * math.pi * 0.9
0 ignored issues
show
introduced by
The variable density does not seem to be defined for all execution paths.
Loading history...
505
        for i in range(0, int(d / density)):
506
            angle = aoff + i * density / d * math.pi * 2
507
            angle += random.uniform(-dangle, dangle)
508
            tr = random.uniform(prevR + 0.1, r)
509
            while 1:
510
                acceptable = 0
511
                system = System()
512
                generateSystem(system)
513
                # check requirements
514
                for planet in system.planets:
515
                    if planet.type in ('D', 'R', 'C', 'H', 'M', 'E') and \
516
                        planet.slots > 0:
517
                        acceptable = 1
518
                        break
519
                if acceptable:
520
                    break
521
            galaxy.systems.append(system)
522
            system.x = math.cos(angle) * tr + galaxy.centerX
523
            system.y = math.sin(angle) * tr + galaxy.centerY
524
            system.compOf = galaxy
525
            system.dist = tr
526
            system.angle = angle
527
        prevR = r
528
        r += random.uniform(2, 4)
529
    # generate central black hole
530
    system = System()
531
    system.x = galaxy.centerX
532
    system.y = galaxy.centerY
533
    system.starClass = "b-"
534
    system.starSubclass = 7
535
    system.compOf = galaxy
536
    system._moveable = 0
537
    galaxy.systems.append(system)
538
    # generate starting systems
539
    if stats.players:
540
        r = (stats.startR[0] + stats.startR[1]) / 2
541
        d = 2 * math.pi * r
542
        print "Player distance:", d / stats.players
543
        gaoff = random.uniform(0, math.pi * 2)
544
        for i in range(0, stats.players / stats.playerGroup):
545
            print "Placing group:", i + 1, "of", stats.players / stats.playerGroup
546
            angle = gaoff + i * math.pi * 2 / (stats.players / stats.playerGroup)
547
            tr = random.uniform(stats.startR[0], stats.startR[1])
548
            gx = math.cos(angle) * tr + galaxy.centerX
549
            gy = math.sin(angle) * tr + galaxy.centerY
550
            aoff = random.uniform(0, math.pi * 2)
551
            for j in range(0, stats.playerGroup):
552
                angle = aoff + j * math.pi * 2 / stats.playerGroup
553
                x = math.cos(angle) * stats.groupDist + gx
554
                y = math.sin(angle) * stats.groupDist + gy
555
                while 1:
556
                    system = System()
557
                    system.x = x
558
                    system.y = y
559
                    system.compOf = galaxy
560
                    generateSystem(system)
561
                    # check system properties
562
                    e = 0
563
                    h = 0
564
                    d = 0
565
                    ok = 1
566
                    for planet in system.planets:
567
                        if planet.type == 'E': e += 1; planet.starting = 1
568
                        elif planet.type in ('D', 'R', 'C'):
569
                            if planet.slots > 5: d += 1
570
                            else: ok = 0; break
571
                        elif planet.type == 'H': h += 1
572
                        elif planet.type == 'M': ok = 0; break
573
                    # fast rule
574
                    #if ok and e == 1:
575
                    #    break
576
                    # slow (better) rule
577
                    if ok and e == 1 and h == 1 and d == 1:
578
                        break
579
                galaxy.systems.append(system)
580
    # strategic resources
581
    keys = stats.resources.keys()
582
    keys.sort()
583
    keys.reverse()
584
    for key in keys:
585
      print "Placing resource", key
586
      for minR, maxR, count in stats.resources[key]:
587
        aoff = random.uniform(0, math.pi * 2)
588
        for i in range(0, count):
589
            angle = aoff + i * math.pi * 2 / count
590
            tr = random.uniform(minR, maxR)
591
            x = math.cos(angle) * tr + galaxy.centerX
592
            y = math.sin(angle) * tr + galaxy.centerY
593
            # find closest system
594
            closest = galaxy.systems[0]
595
            minDist = 99999 #(closest.x - x) ** 2 + (closest.y - y) ** 2
596
            for system in galaxy.systems:
597
                dist = (system.x - x) ** 2 + (system.y - y) ** 2
598
                if dist < minDist and system.hasSR == 0:
599
                    hasDRC = 0
600
                    starting = 0
601
                    # find suitable planet
602
                    for planet in system.planets:
603
                        if planet.starting:
604
                            starting = 1
605
                        if planet.type in ("D", "R", "C"):
606
                            hasDRC = 1
607
                    if not starting and hasDRC:
608
                        minDist = dist
609
                        closest = system
610
            print "    System", closest.x, closest.y, math.sqrt(minDist)
611
            # find planet on the closest system
612
            planets = []
613
            for planet in closest.planets:
614
                if planet.type in ("D", "R", "C"):
615
                    planets.append(planet)
616
            planet = random.choice(planets)
617
            # now make sure resources are placed on big enough planets
618
            # to promote more strategic and less tactical fights over them
619
            # and ensure some minimal barrier is there for player to
620
            # overcome
621
            planet.diameter = dice(1, 6, 12) * 1000
622
            planet.maxSlots = int(planet.diameter / 1000.)
623
            planet.slots = dice(1, 2, 7)
624
            planet.strategicRes = key
625
            system = planet.compOf
626
            system.hasSR = 1
627
            print "    Planet", planet.type
628
    # diseases
629
    keys = stats.diseases.keys()
630
    keys.sort()
631
    keys.reverse()
632
    for key in keys:
633
      print "Placing disease", key
634
      for minR, maxR, count in stats.diseases[key]:
635
        aoff = random.uniform(0, math.pi * 2)
636
        for i in range(0, count):
637
            angle = aoff + i * math.pi * 2 / count
638
            tr = random.uniform(minR, maxR)
639
            x = math.cos(angle) * tr + galaxy.centerX
640
            y = math.sin(angle) * tr + galaxy.centerY
641
            # find closest system
642
            closest = galaxy.systems[0]
643
            minDist = 99999 #(closest.x - x) ** 2 + (closest.y - y) ** 2
644
            for system in galaxy.systems:
645
                dist = (system.x - x) ** 2 + (system.y - y) ** 2
646
                if dist < minDist and system.hasDisease == 0:
647
                    hasHME = 0
648
                    starting = 0
649
                    # find suitable planet
650
                    for planet in system.planets:
651
                        if planet.starting:
652
                            starting = 1
653
                        if planet.type in ("M", "E"):
654
                            hasHME = 1
655
                    if not starting and hasHME:
656
                        minDist = dist
657
                        closest = system
658
            print "    System", closest.x, closest.y, math.sqrt(minDist)
659
            # find planet on the closest system
660
            planets = []
661
            for planet in closest.planets:
662
                if planet.type in ("M", "E"):
663
                    planets.append(planet)
664
            planet = random.choice(planets)
665
            planet.disease = key
666
            system = planet.compOf
667
            system.hasDisease = 1
668
            print "    Planet", planet.type
669
    # check if number of planets is in desired interval
670
    noOfPlanets = 0
671
    for system in galaxy.systems:
672
        noOfPlanets += len(system.planets)
673
    if noOfPlanets < stats.minPlanets or noOfPlanets > stats.maxPlanets:
674
        print 'There was {0} planets.\nStarting new generation...'.format(noOfPlanets)
675
        return generateGalaxy2(galaxyTemplate)
676
    else:
677
        return galaxy
678
679
def generateSystem(system, ranges = None):
680
    # system class and subclass
681
    # c -> supergiant
682
    # g -> giant
683
    # D -> dwarf
684
    # NS -> neutron star
685
    # BH -> black hole
686
    num = random.randrange(1, 1000000 + 1)
687
    system.starSubclass = random.randrange(0, 10)
688
    if   num < 10: system.starClass = 'cB'
689
    elif num < 20: system.starClass = 'cA'
690
    elif num < 40: system.starClass = 'cF'
691
    elif num < 60: system.starClass = 'cG'
692
    elif num < 80: system.starClass = 'cK'
693
    elif num < 100: system.starClass = 'cM'
694
    elif num < 500: system.starClass = 'gF'
695
    elif num < 1000: system.starClass = 'gG'
696
    elif num < 5500: system.starClass = 'gK'
697
    elif num < 10000: system.starClass = 'gM'
698
    elif num < 20000: system.starClass = 'mO'; system.starSubclass = random.randrange(5, 10)
699
    elif num < 30000: system.starClass = 'mB'
700
    elif num < 40000: system.starClass = 'mA'
701
    elif num < 120000: system.starClass = 'mF'
702
    elif num < 225000: system.starClass = 'mG'
703
    elif num < 465000: system.starClass = 'mK'
704
    elif num < 930000: system.starClass = 'mM'
705
    elif num < 940000: system.starClass = 'dB'
706
    elif num < 960000: system.starClass = 'dA'
707
    elif num < 980000: system.starClass = 'dF'
708
    elif num < 990000: system.starClass = 'dG'
709
    elif num < 999500: system.starClass = 'dK'
710
    elif num < 999995: system.starClass = 'n-'
711
    elif num < 1000000: system.starClass = 'b-'
712
    else: system.starClass = 'b-'
713
    # planets
714
    num = random.randrange(0, 100)
715
    planets = (0, 0, 0)
716
    mod = 1.0 / 2.0 # was 2 / 3
717
    if system.starClass[0] in ('c', 'g'):
718
        if num < 25:
719
            planets = distributePlanets(mod * random.randrange(1, 7))
720
    elif system.starClass[1] in ('O', 'B'):
721
        if num < 25:
722
            planets = distributePlanets(mod * random.randrange(1, 11))
723
    elif system.starClass[1] == 'A':
724
        if num < 75:
725
            planets = distributePlanets(mod * random.randrange(1, 11))
726
    elif system.starClass[1] == 'F' or system.starClass[1] == 'G':
727
        if num < 95:
728
            num = random.randrange(1, 7) + random.randrange(1, 7) + 3
729
            planets = distributePlanets(mod * num)
730
    elif system.starClass[1] == 'K':
731
        if num < 95:
732
            num = random.randrange(1, 7) + random.randrange(1, 7)
733
            planets = distributePlanets(mod * num)
734
    elif system.starClass[1] == 'M':
735
        if num < 95:
736
            num = random.randrange(1, 7)
737
            planets = distributePlanets(mod * num)
738
    elif system.starClass[0] == 'd':
739
        if num < 10:
740
            num = int(mod * random.randrange(1, 7) / 2)
741
            planets = (0, 0, num)
742
    elif system.starClass[0] == 'n' or system.starClass[0] == 'b':
743
        if num < 5:
744
            num = int(mod * random.randrange(1, 7) / 2)
745
            planets = (0, 0, num)
746
    # planets
747
    zone = 0
748
    for num in planets:
749
        for i in xrange(0, num):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable xrange does not seem to be defined.
Loading history...
750
            planet = Planet()
751
            planet.compOf = system
752
            system.planets.append(planet)
753
            generatePlanet(zone, planet)
754
        zone += 1
755
    # sort planets by energy
756
    system.planets.sort(key=lambda a: a.energy, reverse = True)
757
758
def distributePlanets(num):
759
    num = int(num)
760
    if num <= 3: return (0, 1, num - 1)
761
    elif num <= 5:    return (1, 1, num - 2)
762
    elif num <=7: return (1, 2, num - 3)
763
    elif num <=11: return (2, 2, num - 4)
764
    elif num <=15: return (2, 3, num - 5)
765
766
def generatePlanet(zone, planet):
767
    sc = planet.compOf.starClass
768
    if sc == 'mF' or sc == 'mG' or sc == 'mK': isFGK = 1
769
    else: isFGK = 0
770
    if sc[0] == 'd' or sc == 'n-' or sc == 'b-': isDNB = 1
771
    else: isDNB = 0
772
    # diameter and type of planet
773
    num = random.randrange(0, 100)
774
    if zone == 0: # Zone A
775
        if num < 5: planet.type = 'A'
776
        elif num < 10: planet.type = 'G'; planet.diameter = dice(3, 6, 0) * 10000
777
        elif num < 60: planet.type = 'R'; planet.diameter = dice(1, 10, 0) * 1000
778
        elif num < 70: planet.type = 'D'; planet.diameter = dice(2, 6, 2) * 1000
779
        elif num < 100: planet.type = 'H'; planet.diameter = dice(3, 6, 1) * 1000
780
    elif zone == 1: # Zone B
781
        if num < 10: planet.type = 'A'
782
        elif num < 15: planet.type = 'G'; planet.diameter = dice(3, 6, 0) * 10000
783
        elif num < 25: planet.type = 'R'; planet.diameter = dice(1, 10, 0) * 1000
784
        elif num < 45: planet.type = 'D'; planet.diameter = dice(2, 6, 2) * 1000
785
        elif num < 70: planet.type = 'H'; planet.diameter = dice(3, 6, 1) * 1000
786
        elif num < 90:
787
            if isFGK:
788
                planet.type = 'M'; planet.diameter = dice(2, 6, 5) * 1000
789
            else:
790
                planet.type = 'H'; planet.diameter = dice(3, 6, 1) * 1000
791
        elif num < 100:
792
            if isFGK:
793
                # planet.type = 'E'; planet.diameter = dice(2, 6, 5) * 1000
794
                planet.type = 'E'; planet.diameter = dice(1, 4, 13) * 1000
795
            else:
796
                planet.type = 'H'; planet.diameter = dice(3, 6, 1) * 1000
797
    elif zone == 2: # Zone C
798
        if num < 15: planet.type = 'A'
799
        elif num < 75: planet.type = 'G'; planet.diameter = dice(3, 6, 0) * 10000
800
        elif num < 80: planet.type = 'R'; planet.diameter = dice(1, 10, 0) * 1000
801
        elif num < 90: planet.type = 'C'; planet.diameter = dice(1, 10, 0) * 1000
802
        elif num < 95: planet.type = 'D'; planet.diameter = dice(2, 6, 2) * 1000
803
        elif num < 100:
804
            if isDNB:
805
                planet.type = 'C'; planet.diameter = dice(1, 10, 0) * 1000
806
            else:
807
                planet.type = 'H'; planet.diameter = dice(3, 6, 1) * 1000
808
    # energy
809
    planet.energy = random.randrange(100 - zone * 50, 150 - zone * 50)
810
    # minerals
811
    if planet.type[0] in ('R', 'D', 'H', 'M'):
812
        density = dice(1, 6, 0) / 2.0 + 3
813
        planet.minerals = int(((planet.diameter / 500.0) + density * 10.0 + random.randrange(1, 101) / 2.0 - 45) * 2)
814
    elif planet.type[0] == 'A':
815
        diameter = dice(1, 10, 0) * 1000 # rock planet
816
        density = dice(1, 6, 0) / 2.0 + 3
817
        planet.minerals = int(((diameter / 500.0) + density * 10.0 + random.randrange(1, 101) / 2.0 - 45) * 2)
818
    elif planet.type[0] == 'G':
819
        diameter = dice(3, 6, 1) * 1000 # earth like planet
820
        density = dice(1, 6, 0) / 2.0 + 3
821
        planet.minerals = int(((diameter / 500.0) + density * 10.0 + random.randrange(1, 101) / 2.0 - 45) * 2)
822
    elif planet.type == 'E':
823
        planet.minerals = 100
824
    else:
825
        planet.minerals = 0
826
    if planet.minerals < 0:
827
        planet.minerals = 0
828
    # environment
829
    if planet.type == 'E': planet.environ = 100
830
    elif planet.type == 'M': planet.environ = random.randrange(25, 51)
831
    elif planet.type == 'H': planet.environ = random.randrange(12, 26)
832
    elif planet.type == 'D': planet.environ = random.randrange(6, 13)
833
    elif planet.type == 'C': planet.environ = random.randrange(0, 7)
834
    elif planet.type == 'R': planet.environ = random.randrange(0, 7)
835
    else: planet.environ = 0
836
    # slots
837
    slotsMod = 0.67
838
    planet.maxSlots = int((planet.diameter / 1000) * 1.5 * slotsMod)
839
    if planet.type == 'E': planet.slots = 9 # planet.slots = int(planet.maxSlots * 0.50)
840
    elif planet.type == 'M': planet.slots = int(planet.maxSlots * 0.50)
841
    elif planet.type == 'H': planet.slots = int(planet.maxSlots * 0.50)
842
    elif planet.type == 'D': planet.slots = int(planet.maxSlots * 0.75)
843
    elif planet.type == 'C': planet.slots = int(planet.maxSlots * 0.75)
844
    elif planet.type == 'R': planet.slots = int(planet.maxSlots * 0.75)
845
    else: planet.slots = 0
846
    # make sure that all planets except A and G has at least one slot
847
    if planet.type in "EMHDCR" and planet.slots == 0:
848
        #@print "Fixing slots", planet.type, planet.slots, planet.maxSlots
849
        planet.maxSlots = max(1, planet.maxSlots)
850
        planet.slots = max(1, planet.slots)
851
    #print planet.type, planet.environ, planet.minerals
852
853
def dice(num, range, offset):
854
    result = offset
855
    for i in xrange(0, num):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable xrange does not seem to be defined.
Loading history...
856
        result += random.randrange(1, range + 1)
857
    return result
858
859
860
## info
861
def getInfo(galaxy):
862
    starTypes = {}
863
    planetTypes = {}
864
    planets = 0
865
    maxPlanets = 0
866
    minPlanets = 999
867
    planetDist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
868
    for system in galaxy.systems:
869
        starTypes[system.starClass] = starTypes.get(system.starClass, 0) + 1
870
        for planet in system.planets:
871
            planetTypes[planet.type] = planetTypes.get(planet.type, 0) + 1
872
            planets += 1
873
        sysPlanets = len(system.planets)
874
        maxPlanets = max(maxPlanets, sysPlanets)
875
        minPlanets = min(minPlanets, sysPlanets)
876
        planetDist[sysPlanets] += 1
877
    stars = len(galaxy.systems)
878
    print 'Systems:', stars
879
    print starTypes
880
    print 'Planets per system:', planetDist
881
    print 'Planets:', planets
882
    print 'min %d, max %d, avg %.2f' % (minPlanets, maxPlanets, float(planets) / stars)
883
    print 'Types:', planetTypes
884
    return stars, starTypes, planets, planetTypes
885
886
887
## load names
888
systemNames = []
889
890
def loadSystemNames():
891
    global systemNames
892
    names = set([])
893
894
    with open(data.SYSTEM_NAMES_FILE) as names_file:
895
        for line in names_file:
896
            names.add(line.strip())
897
    systemNames = list(names)
898
899
if __name__ == '__main__':
900
    import sys
901
902
    galaxyType = sys.argv[1]
903
    targetFile = sys.argv[2]
904
    with open(targetFile, 'w') as fileHandle:
905
        GenerateGalaxy(galaxyType, fileHandle)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable GenerateGalaxy does not seem to be defined.
Loading history...
906