Completed
Pull Request — master (#192)
by Marek
01:39
created

ige.ospace.Scanner.generateSectors()   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nop 3
dl 0
loc 15
rs 9.9
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
21
import time, math
22
from ige.ospace import Rules
23
import ige
24
from ige import log
25
26
def recordScanLevel(distance, tObj, tSigMod, scannerPwr, owner, playerMaps):
27
    level = min((tObj.signature + tSigMod) * scannerPwr / max(0.0001, distance), Rules.maxScanPwr)
28
    if level >= Rules.level1InfoScanPwr and owner > 0:
29
        if owner not in playerMaps:
30
            playerMaps[owner] = {}
31
        playerMaps[owner][tObj] = max(level, playerMaps[owner].get(tObj, 0))
32
33
def computeScanner(obj1, obj2, playerMaps, signatures):
34
    d = math.hypot(obj1.x - obj2.x, obj1.y - obj2.y)
35
    sigMod = signatures.get(obj2.oid, 0)
36
    if hasattr(obj1, "scannerPwr"):
37
        recordScanLevel(d, obj2, sigMod, obj1.scannerPwr, obj1.owner, playerMaps)
38
    elif hasattr(obj1, "scannerPwrs"):
39
        for owner, scannerPwr in obj1.scannerPwrs.iteritems():
40
            recordScanLevel(d, obj2, sigMod, scannerPwr, owner, playerMaps)
41
    else:
42
        raise ige.ServerException("Unsupported object")
43
44
def detectClose(obj1, obj2, signatures):
45
    # ignore itself
46
    if obj1.oid >= obj2.oid:
47
        return
48
    d = math.hypot(obj1.x - obj2.x, obj1.y - obj2.y)
49
    if d < 1.0:
50
        log.debug("CLOSE FLEET detected", obj1.oid, obj2.oid, obj1.signature, obj2.signature)
51
        signatures[obj1.oid] = signatures.get(obj1.oid, 0) + obj2.signature
52
        signatures[obj2.oid] = signatures.get(obj2.oid, 0) + obj1.signature
53
54
def computeMap(galaxyCmdObj, tran, galaxy):
55
    log.debug("SCAN2 Phase - starting")
56
57
    start = time.time()
58
    _map, fleets, alwaysVisible = generateMap(galaxyCmdObj, tran, galaxy)
59
60
    # compute close fleets
61
    sectors, surroundingSectors = generateSectors(fleets, sectorSize = 1, size = 1)
62
    signatures = {}
63
    processSectors(fleets, sectors, surroundingSectors, detectClose, (signatures,))
64
    log.debug("CLOSE FLEETS - result", signatures)
65
66
    # compute map
67
    start0 = time.time()
68
    sectors, surroundingSectors = generateSectors(_map, sectorSize = 5, size     = 10)
69
    playerMaps = {}
70
    processSectors(_map, sectors, surroundingSectors, computeScanner, (playerMaps, signatures))
71
72
    # add always visible items
73
    for owner in playerMaps:
74
        for visibleObject in alwaysVisible.values():
75
            playerMaps[owner][visibleObject] = max(Rules.level1InfoScanPwr, playerMaps[owner].get(visibleObject, 0))
76
    stop = time.time()
77
    log.debug("Time    : %0.3f s" % (stop - start))
78
    log.debug("Time    : %0.3f s (including sector generation)" % (stop - start0))
79
    return playerMaps
80
81
def processSectors(_map, sectors, surroundingSectors, callable, args):
82
    while sectors:
83
        # get (and remove) random sector
84
        (sX, sY), sObjs = sectors.popitem()
85
        # build list of objects in surrounding sectors
86
        objs = []
87
        for dx in surroundingSectors:
88
            for dy in surroundingSectors:
89
                sIdx = (sX + dx, sY + dy)
90
                if sIdx not in sectors:
91
                    continue
92
                objs.extend(sectors[sIdx])
93
        # check objects in current sector
94
        for obj1Idx in sObjs:
95
            obj1 = _map[obj1Idx]
96
            # with objects in surrounding sectors
97
            for obj2Idx in objs:
98
                obj2 = _map[obj2Idx]
99
                callable(obj1, obj2, *args)
100
                callable(obj2, obj1, *args)
101
            # with objects in current sector
102
            for obj2Idx in sObjs:
103
                # allow object scan on itself
104
                if obj1Idx > obj2Idx:
105
                    continue
106
                obj2 = _map[obj2Idx]
107
                callable(obj1, obj2, *args)
108
                callable(obj2, obj1, *args)
109
110
def generateSectors(_map, sectorSize = 5, size = 10):
111
    # generate sector map
112
    sectors = {}
113
    # can be optimized to not include corner sectors
114
    surroundingSectors = range(-size / sectorSize, size / sectorSize + 1)
115
116
    for i in _map:
117
        obj = _map[i]
118
        sIdx = (int(obj.x / sectorSize), int(obj.y / sectorSize))
119
        if sIdx in sectors:
120
            sectors[sIdx].append(obj.oid)
121
        else:
122
            sectors[sIdx] = [obj.oid]
123
124
    return sectors, surroundingSectors
125
126
def generateMap(cmdObj, tran, galaxy):
127
    _map = {}
128
    fleets = {}
129
    alwaysVisible = {}
130
    # all systems are part of the map
131
    for systemID in galaxy.systems:
132
        system = tran.db[systemID]
133
        # black holes are always visible, for easier orientation on the galaxy map
134
        if system.starClass[0] == 'b':
135
            alwaysVisible[systemID] = system
136
        _map[systemID] = system
137
        # get mobile objects (fleet, ...)
138
        for objID in cmdObj.cmd(system).getObjectsInSpace(tran, system):
139
            obj = tran.db[objID]
140
            _map[objID] = obj
141
            fleets[objID] = obj
142
    return _map, fleets, alwaysVisible
143