~widelands-dev/widelands-website/trunk

« back to all changes in this revision

Viewing changes to widelandslib/make_flow_diagram.py

  • Committer: kaputtnik
  • Date: 2019-05-30 18:20:02 UTC
  • mto: This revision was merged to the branch mainline in revision 540.
  • Revision ID: kaputtnik-20190530182002-g7l91m1xo28clghv
adjusted README; first commit on the new server

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 
4
4
import pydot as d
5
5
 
 
6
from django.conf import settings
6
7
from widelandslib.tribe import *
7
 
#from pudb import set_trace; set_trace()
8
8
 
9
9
from os import makedirs, path
10
10
import subprocess
11
11
from tempfile import mkdtemp
12
12
 
13
 
tdir = ""
 
13
tdir = ''
14
14
 
15
15
##############################
16
16
# To Do Make_Flow_Diagram.py #
17
17
##############################
18
 
# i'd like to add things like: forester resores trunk or: gamekeeper restores meat
 
18
# i'd like to add things like: forester resores log or: gamekeeper restores meat
19
19
#
20
20
# also, a building called construction site where alle the building material can point at would be nice
21
21
#
22
22
# how to tell the viewer, how many and wich ressources turn to others via buildings,
23
 
# e.g. 6 trunks to 1 coal with the atlanteans, maybe on the edges?
 
23
# e.g. 6 logs to 1 coal with the atlanteans, maybe on the edges?
24
24
 
25
25
#############################
26
26
# Work around bugs in pydot #
27
27
#############################
28
 
## Pydot can't handle names with - in it. We replace them.
 
28
# Pydot can't handle names with - in it. We replace them.
 
29
 
29
30
 
30
31
def _cleanup_str(s):
31
32
    return s.replace('-', '')
32
33
 
 
34
 
33
35
class Subgraph(d.Subgraph):
 
36
 
34
37
    def __init__(self, name, *args, **kwargs):
35
38
        name = _cleanup_str(name)
36
39
        d.Subgraph.__init__(self, name, *args, **kwargs)
37
40
 
 
41
 
38
42
class Node(d.Node):
 
43
 
39
44
    def __init__(self, name, *args, **kwargs):
40
45
        name = _cleanup_str(name)
41
46
        d.Node.__init__(self, name, *args, **kwargs)
42
47
 
 
48
 
43
49
class Edge(d.Edge):
 
50
 
44
51
    def __init__(self, first, second, *args, **kwargs):
45
52
        first = _cleanup_str(first)
46
53
        second = _cleanup_str(second)
47
54
        d.Edge.__init__(self, first, second, *args, **kwargs)
48
55
 
 
56
 
49
57
class CleanedDot(d.Dot):
 
58
 
50
59
    def get_node(self, name, *args, **kwargs):
51
60
        name = _cleanup_str(name)
52
61
        return d.Dot.get_node(self, name, *args, **kwargs)
55
64
# Begin of drawing #
56
65
####################
57
66
 
 
67
 
58
68
def add_building(g, b, limit_inputs=None, limit_outputs=None, limit_buildings=None, link_workers=True, limit_recruits=None):
59
69
    # Add the nice node
60
 
    workers = ""
61
 
    if isinstance(b, (ProductionSite,)):
 
70
    workers = ''
 
71
    if isinstance(b, ProductionSite):
62
72
        workers = r"""<table border="0px" cellspacing="0">"""
63
73
        for worker in b.workers:
64
74
            wo = b.tribe.workers[worker]
67
77
            ))
68
78
            if link_workers:
69
79
                add_worker(g, wo)
70
 
                g.add_edge(Edge(b.name, wo.name, color="orange", arrowhead="none"))
 
80
                g.add_edge(
 
81
                    Edge(b.name, wo.name, color='orange', arrowhead='none'))
71
82
        for worker in b.recruits:
72
83
            if limit_recruits is None or worker in limit_recruits:
73
84
                wo = b.tribe.workers[worker]
74
85
                add_worker(g, wo, as_recruit=True)
75
 
                g.add_edge(Edge(b.name, wo.name, color="darkgreen"))
 
86
                g.add_edge(Edge(b.name, wo.name, color='darkgreen'))
76
87
        workers += r"""</table>"""
77
88
 
78
 
    if isinstance(b, (MilitarySite,)):
 
89
    if isinstance(b, MilitarySite):
79
90
        workers = r"""<table border="0px" cellspacing="0">"""
80
91
        workers += (r"""<tr><td border="0px">Keeps %s Soldiers</td></tr>"""
81
92
                    r"""<tr><td border="0px">Conquers %s fields</td></tr>"""
83
94
        workers += r"""</table>"""
84
95
 
85
96
    costs = r"""<tr><td colspan="2"><table border="0px" cellspacing="0">"""
86
 
    for ware, count in b.buildcost.items():
 
97
    for ware, count in list(b.buildcost.items()):
87
98
        w = b.tribe.wares[ware]
88
 
        costs += ('<tr><td border="0px">%s x </td><td border="0px"><img src="%s"/></td><td border="0px">%s</td></tr>' % (count, w.image, w.descname))
 
99
        costs += ('<tr><td border="0px">%s x </td><td border="0px"><img src="%s"/></td><td border="0px">%s</td></tr>' %
 
100
                  (count, w.image, w.descname))
89
101
    costs += r"""</table></td></tr>"""
90
102
    if not b.buildcost:
91
 
        costs = ""
 
103
        costs = ''
92
104
 
93
105
    n = Node(b.name,
94
 
        shape = "none",
95
 
        label = (r"""<<TABLE border="1px" cellborder="0px" cellspacing="0px" cellpadding="0px">
 
106
             shape='none',
 
107
             label=(r"""<<TABLE border="1px" cellborder="0px" cellspacing="0px" cellpadding="0px">
96
108
<TR><TD><IMG SRC="%s"/></TD>
97
109
<TD valign="bottom">%s</TD>
98
110
</TR>
99
111
<TR><TD align="left" colspan="2">%s</TD></TR>
100
112
%s
101
 
</TABLE>>""" % (b.image, workers, b.descname, costs)).replace('\n',''),
102
 
        URL = "../../buildings/%s/" % b.name,
103
 
        fillcolor = "orange",
104
 
        style = "filled",
105
 
    )
 
113
</TABLE>>""" % (b.image, workers, b.descname, costs)).replace('\n', ''),
 
114
             URL='../../buildings/%s/' % b.name,
 
115
             fillcolor='orange',
 
116
             style='filled',
 
117
             )
106
118
 
107
 
    sg = Subgraph("%s_enhancements" % b.name,
108
 
        ordering = "out", rankdir="TB", rank="same")
 
119
    sg = Subgraph('%s_enhancements' % b.name,
 
120
                  ordering='out', rankdir='TB', rank='same')
109
121
    if b.enhancement and not b.enhanced_building:
110
122
        cb = b
111
123
        while cb.enhancement:
112
124
            if limit_buildings == None or (cb.name in limit_buildings):
113
125
                sg.add_node(Node(_cleanup_str(cb.name)))
114
126
                if limit_buildings == None or (cb.enhancement in limit_buildings):
115
 
                    g.add_edge(Edge(cb.name, cb.enhancement, color="blue"))
 
127
                    g.add_edge(Edge(cb.name, cb.enhancement, color='blue'))
116
128
            cb = b.tribe.buildings[cb.enhancement]
117
129
        if limit_buildings == None or (cb.name in limit_buildings):
118
130
            sg.add_node(Node(_cleanup_str(cb.name)))
121
133
    else:
122
134
        g.add_node(n)
123
135
 
124
 
 
125
 
    if isinstance(b, (ProductionSite,)):
126
 
        # for worker,c in b.workers: 
 
136
    if isinstance(b, ProductionSite):
 
137
        # for worker,c in b.workers:
127
138
        #     g.add_edge(Edge(worker, name, color="orange"))
128
139
 
129
140
        for output in b.outputs:
130
141
            if limit_outputs is None or output in limit_outputs:
131
 
                g.add_edge(Edge(b.name, output, color="darkgreen"))
 
142
                g.add_edge(Edge(b.name, output, color='darkgreen'))
132
143
 
133
144
        for input_ in b.inputs:
134
145
            if limit_inputs is None or input_ in limit_inputs:
135
 
                g.add_edge(Edge(input_, b.name, color="#cd0000"))
 
146
                g.add_edge(Edge(input_, b.name, color='#cd0000'))
136
147
    return n
137
148
 
138
149
 
139
150
def add_ware(g, w):
140
151
    # Add the nice node
141
152
    n = Node(w.name,
142
 
             shape = "ellipse",
143
 
             label = (r"""<<TABLE border="0px">
 
153
             shape='ellipse',
 
154
             label=(r"""<<TABLE border="0px">
144
155
<TR><TD><IMG SRC="%s"/></TD></TR>
145
156
<TR><TD>%s</TD></TR>
146
157
</TABLE>>""") % (w.image, w.descname),
147
 
             URL = "../../wares/%s/" % (w.name),
148
 
             fillcolor = "#dddddd",
149
 
             style="filled",
150
 
)
 
158
             URL='../../wares/%s/' % (w.name),
 
159
             fillcolor='#dddddd',
 
160
             style='filled',
 
161
             )
151
162
 
152
163
    g.add_node(n)
153
164
 
 
165
 
154
166
def add_worker(g, w, as_recruit=False):
155
167
    # Add the nice node
156
168
    n = Node(w.name,
157
 
            shape = "octagon" if not as_recruit else "ellipse",
158
 
            label = (r"""<<TABLE border="0px">
 
169
             shape='octagon' if not as_recruit else 'ellipse',
 
170
             label=(r"""<<TABLE border="0px">
159
171
<TR><TD><IMG SRC="%s"/></TD>
160
172
<TD>%s</TD></TR>
161
173
</TABLE>>""") % (w.image, w.descname),
162
 
            URL="../../workers/%s/" % w.name,
163
 
            style="filled",
164
 
        )
 
174
             URL='../../workers/%s/' % w.name,
 
175
             style='filled',
 
176
             )
165
177
 
166
178
    g.add_node(n)
167
179
 
168
180
 
169
181
def make_graph(tribe_name):
170
182
    global tdir
171
 
    tdir = mkdtemp(prefix="widelands-help")
172
 
    t = Tribe(tribe_name)
173
 
 
174
 
    g = CleanedDot(concentrate="false", style="filled", bgcolor="white",
175
 
                overlap="false", splines="true", rankdir="LR")
176
 
 
177
 
    for name,w in t.wares.items():
 
183
    tdir = mkdtemp(prefix='widelands-help')
 
184
    json_directory = path.normpath(settings.MEDIA_ROOT + '/map_object_info')
 
185
    with open(path.normpath(
 
186
            json_directory + '/tribe_' + tribe_name + '.json'), 'r') as tribeinfo_file:
 
187
        tribeinfo = json.load(tribeinfo_file)
 
188
 
 
189
    t = Tribe(tribeinfo, json_directory)
 
190
 
 
191
    g = CleanedDot(concentrate='false', style='filled', bgcolor='white',
 
192
                   overlap='false', splines='true', rankdir='LR')
 
193
 
 
194
    for name, w in list(t.wares.items()):
178
195
        add_ware(g, w)
179
196
    #
180
197
    # for name,w in t.workers.items():
181
198
    #     add_worker(g, w)
182
199
 
183
 
    for name,b in t.buildings.items():
 
200
    for name, b in list(t.buildings.items()):
184
201
        add_building(g, b, link_workers=False)
185
202
 
186
 
 
187
 
    g.write_pdf(path.join(tdir, "%s.pdf" % tribe_name))
188
 
 
189
 
    g.set_size("6")
190
 
    g.write_gif(path.join(tdir, "%s.gif" % tribe_name))
191
 
 
192
 
    rtdir, tdir = tdir, ""
 
203
    g.write_pdf(path.join(tdir, '%s.pdf' % tribe_name))
 
204
 
 
205
    g.set_size('32')
 
206
    g.write_gif(path.join(tdir, '%s.gif' % tribe_name))
 
207
 
 
208
    rtdir, tdir = tdir, ''
193
209
    return rtdir
194
210
 
 
211
 
195
212
def make_building_graph(t, building_name):
196
 
    if isinstance(t, basestring):
 
213
    if isinstance(t, str):
197
214
        t = Tribe(t)
198
215
 
199
216
    b = t.buildings[building_name]
200
217
 
201
 
    g = CleanedDot(concentrate="false", bgcolor="transparent",
202
 
                overlap="false", splines="true", rankdir="LR")
 
218
    g = CleanedDot(concentrate='false', bgcolor='transparent',
 
219
                   overlap='false', splines='true', rankdir='LR')
203
220
 
204
 
    if not isinstance(b, (ProductionSite,)):
 
221
    if not isinstance(b, ProductionSite):
205
222
        inputs, outputs = [], []
206
223
    else:
207
 
        # TODO: prepare for tribes having buildings with a ware as both input and output.
208
 
        inputs, outputs = [[t.wares[name] for name in lst] for lst in [b.inputs, b.outputs]]
 
224
        # TODO: prepare for tribes having buildings with a ware as both input
 
225
        # and output.
 
226
        inputs, outputs = [[t.wares[name] for name in lst]
 
227
                           for lst in [b.inputs, b.outputs]]
209
228
 
210
229
    # find the uppermost building in the enhancement hierarchy
211
230
    bb = b
212
231
    while bb.base_building:
213
232
        bb = bb.base_building
214
 
        add_building(g, bb, limit_inputs=[], limit_outputs=[], link_workers=False)
 
233
        add_building(g, bb, limit_inputs=[],
 
234
                     limit_outputs=[], link_workers=False)
215
235
 
216
236
    add_building(g, b)
217
237
 
218
238
    bb = b
219
239
    while bb.enhancement:
220
240
        bb = t.buildings[bb.enhancement]
221
 
        add_building(g, bb, limit_inputs=[], limit_outputs=[], link_workers=False)
 
241
        add_building(g, bb, limit_inputs=[],
 
242
                     limit_outputs=[], link_workers=False)
222
243
 
223
244
    [add_ware(g, w) for w in inputs + outputs]
224
245
 
225
 
    try: makedirs(path.join(tdir, "help/%s/buildings/%s/" % (t.name, building_name)))
226
 
    except: pass
227
 
    g.write(path.join(tdir, "help/%s/buildings/%s/source.dot" % (t.name, building_name)))
 
246
    try:
 
247
        makedirs(path.join(tdir, 'help/%s/buildings/%s/' %
 
248
                           (t.name, building_name)))
 
249
    except:
 
250
        pass
 
251
    g.write(path.join(tdir, 'help/%s/buildings/%s/source.dot' %
 
252
                      (t.name, building_name)))
 
253
 
228
254
 
229
255
def make_worker_graph(t, worker_name):
230
 
    if isinstance(t, basestring):
 
256
    if isinstance(t, str):
231
257
        t = Tribe(t)
232
258
 
233
259
    w = t.workers[worker_name]
234
260
 
235
 
    g = CleanedDot(concentrate="false", bgcolor="transparent",
236
 
                overlap="false", splines="true", rankdir="LR")
 
261
    g = CleanedDot(concentrate='false', bgcolor='transparent',
 
262
                   overlap='false', splines='true', rankdir='LR')
237
263
 
238
 
    buildings = [bld for bld in t.buildings.values() if 
239
 
            isinstance(bld, ProductionSite) and 
240
 
              (w.name in bld.workers or w.name in bld.recruits)]
 
264
    buildings = [bld for bld in list(t.buildings.values()) if
 
265
                 isinstance(bld, ProductionSite) and
 
266
                 (w.name in bld.workers or w.name in bld.recruits)]
241
267
 
242
268
    for bld in buildings:
243
 
        add_building(g, bld, limit_inputs=[], limit_outputs=[], limit_buildings=[buildings], link_workers=False, limit_recruits=[w.name])
 
269
        add_building(g, bld, limit_inputs=[], limit_outputs=[], limit_buildings=[
 
270
                     buildings], link_workers=False, limit_recruits=[w.name])
244
271
        if w.name in bld.workers:
245
 
            g.add_edge(Edge(bld.name, w.name, color="orange", arrowhead="none"))
 
272
            g.add_edge(Edge(bld.name, w.name, color='orange', arrowhead='none'))
246
273
 
247
 
    sg = Subgraph("%s_enhancements" % w.name,
248
 
        ordering = "out", rankdir="TB", rank="same")
 
274
    sg = Subgraph('%s_enhancements' % w.name,
 
275
                  ordering='out', rankdir='TB', rank='same')
249
276
    # find exactly one level of enhancement
250
 
    for other in t.workers.values():
 
277
    for other in list(t.workers.values()):
251
278
        if other.becomes == w.name:
252
279
            add_worker(sg, other)
253
 
            g.add_edge(Edge(other.name, w.name, color="blue"))
 
280
            g.add_edge(Edge(other.name, w.name, color='blue'))
254
281
        elif w.becomes == other.name:
255
282
            add_worker(sg, other)
256
 
            g.add_edge(Edge(w.name, other.name, color="blue"))
 
283
            g.add_edge(Edge(w.name, other.name, color='blue'))
257
284
 
258
285
    add_worker(sg, w)
259
286
    g.add_subgraph(sg)
260
287
 
261
 
    try: makedirs(path.join(tdir, "help/%s/workers/%s/" % (t.name, w.name)))
262
 
    except OSError: pass
263
 
    g.write(path.join(tdir, "help/%s/workers/%s/source.dot" % (t.name, w.name)))
 
288
    try:
 
289
        makedirs(path.join(tdir, 'help/%s/workers/%s/' % (t.name, w.name)))
 
290
    except OSError:
 
291
        pass
 
292
    g.write(path.join(tdir, 'help/%s/workers/%s/source.dot' % (t.name, w.name)))
 
293
 
264
294
 
265
295
def make_ware_graph(t, ware_name):
266
 
    if isinstance(t, basestring):
 
296
    if isinstance(t, str):
267
297
        t = Tribe(t)
268
298
    w = t.wares[ware_name]
269
299
 
270
 
    g = CleanedDot(concentrate="false", bgcolor="transparent",
271
 
                overlap="false", splines="true", rankdir="LR")
 
300
    g = CleanedDot(concentrate='false', bgcolor='transparent',
 
301
                   overlap='false', splines='true', rankdir='LR')
272
302
 
273
 
    buildings = [bld for bld in t.buildings.values() if isinstance(bld, (ProductionSite, )) and (w.name in bld.inputs or w.name in bld.outputs)]
274
 
    [add_building(g, bld, limit_inputs=[w.name], limit_outputs=[w.name], limit_buildings=[b.name for b in buildings], link_workers=False) for bld in buildings]
 
303
    buildings = [bld for bld in list(t.buildings.values()) if isinstance(
 
304
        bld, ProductionSite) and (w.name in bld.inputs or w.name in bld.outputs)]
 
305
    [add_building(g, bld, limit_inputs=[w.name], limit_outputs=[w.name], limit_buildings=[
 
306
                  b.name for b in buildings], link_workers=False) for bld in buildings]
275
307
 
276
308
    add_ware(g, w)
277
309
 
278
 
    try: makedirs(path.join(tdir, "help/%s/wares/%s/" % (t.name, ware_name)))
279
 
    except OSError: pass
280
 
    g.write(path.join(tdir, "help/%s/wares/%s/source.dot" % (t.name, ware_name)))
 
310
    try:
 
311
        makedirs(path.join(tdir, 'help/%s/wares/%s/' % (t.name, ware_name)))
 
312
    except OSError:
 
313
        pass
 
314
    g.write(path.join(tdir, 'help/%s/wares/%s/source.dot' % (t.name, ware_name)))
 
315
 
281
316
 
282
317
def process_dotfile(directory):
283
 
    subprocess.Popen(("dot -Tpng -o %s/image.png -Tcmapx -o %s/map.map %s/source.dot" % (directory, directory, directory)).split(" ")).wait()
284
 
    #with open(directory,"w") as html:
285
 
    #    html.write(r"""<IMG SRC="image.png" border="0px" usemap="#G"/>""" + open(path.join(directory, "map.map")).read())
 
318
    subprocess.Popen(('dot -Tpng -o %s/menu.png -Tcmapx -o %s/map.map %s/source.dot' %
 
319
                      (directory, directory, directory)).split(' ')).wait()
 
320
    # with open(directory,"w") as html:
 
321
    # html.write(r"""<IMG SRC="menu.png" border="0px" usemap="#G"/>""" +
 
322
    # open(path.join(directory, "map.map")).read())
 
323
 
286
324
 
287
325
def make_all_subgraphs(t):
288
326
    global tdir
289
 
    tdir = mkdtemp(prefix="widelands-help")
290
 
    if isinstance(t, basestring):
 
327
    tdir = mkdtemp(prefix='widelands-help')
 
328
    if isinstance(t, str):
291
329
        t = Tribe(t)
292
 
    print "making all subgraphs for tribe", t.name, "in", tdir
293
 
 
294
 
    print "  making workers"
 
330
    print('making all subgraphs for tribe', t.name, 'in', tdir)
 
331
 
 
332
    print('  making wares')
 
333
 
 
334
    for w in t.wares:
 
335
        print('    ' + w)
 
336
        make_ware_graph(t, w)
 
337
        process_dotfile(path.join(tdir, 'help/%s/wares/%s/' % (t.name, w)))
 
338
 
 
339
    print('  making workers')
295
340
 
296
341
    for w in t.workers:
297
 
        print "    " + w
 
342
        print('    ' + w)
298
343
        make_worker_graph(t, w)
299
 
        process_dotfile(path.join(tdir, "help/%s/workers/%s/" % (t.name, w)))
300
 
 
301
 
    print "  making wares"
302
 
 
303
 
    for w in t.wares:
304
 
        print "    " + w
305
 
        make_ware_graph(t, w)
306
 
        process_dotfile(path.join(tdir, "help/%s/wares/%s/" % (t.name, w)))
307
 
 
308
 
    print "  making buildings"
 
344
        process_dotfile(path.join(tdir, 'help/%s/workers/%s/' % (t.name, w)))
 
345
 
 
346
    print('  making buildings')
309
347
 
310
348
    for b in t.buildings:
311
 
        print "    " + b
 
349
        print('    ' + b)
312
350
        make_building_graph(t, b)
313
 
        process_dotfile(path.join(tdir, "help/%s/buildings/%s/" % (t.name, b)))
 
351
        process_dotfile(path.join(tdir, 'help/%s/buildings/%s/' % (t.name, b)))
314
352
 
315
 
    rtdir, tdir = tdir, ""
 
353
    rtdir, tdir = tdir, ''
316
354
    return rtdir
317
355
 
 
356
 
318
357
def add_bases(tribe, building, g):
319
358
    if b.enhanced_building:
320
359
        add_building()
321
360
 
322
 
if __name__ == "__main__":
 
361
 
 
362
if __name__ == '__main__':
323
363
    make_all_subgraphs()