Inprove -m mapping.
[open-adventure.git] / make_graph.py
1 #!/usr/bin/env python3
2 """\
3 usage: make-graph.py [-a] [-m] [-s]
4
5 Make a DOT graph of Colossal Cave
6
7 -a = emit graph of entire dungeon
8 -m = emit graph of maze all alike
9 -s = emit graph of surface locations
10 """
11 # Copyright (c) 2017 by Eric S. Raymond
12 # SPDX-License-Identifier: BSD-2-clause
13
14 import sys, yaml, getopt
15
16 def allalike(loc):
17     "Select out loci related to the Maze All Alike"
18     return ("ALIKE" in loc) or (loc == "LOC_PITBRINK") or ("MAZEEND" in loc) or ("STALACTITE" in loc)
19
20 def surface(attrs):
21     "Select out surface locations"
22     if ("ABOVE" in attrs["conditions"]) and attrs["conditions"]["ABOVE"]:
23         return True
24     if ("FOREST" in attrs["conditions"]) and attrs["conditions"]["FOREST"]:
25         return True
26     return False
27
28 def abbreviate(d):
29     m = {"NORTH":"N", "EAST":"E", "SOUTH":"S", "WEST":"W", "UPWAR":"U", "DOWN":"D"}
30     return m.get(d, d)
31
32 if __name__ == "__main__":
33     with open("adventure.yaml", "r") as f:
34         db = yaml.safe_load(f)
35
36     try:
37         (options, arguments) = getopt.getopt(sys.argv[1:], "ams")
38     except getopt.GetoptError as e:
39         print(e)
40         sys.exit(1)
41
42     subset = "maze"
43     for (switch, val) in options:
44         if switch == '-a':
45             subset = "all"
46         elif switch == '-m':
47             subset = "maze"
48         elif switch == '-s':
49             subset = "surface"
50         else:
51             sys.stderr.write(__doc__)
52             raise SystemExit(1)        
53
54     startlocs = {}
55     for obj in db["objects"]:
56         objname = obj[0]
57         location = obj[1].get("locations")
58         if "OBJ" not in objname and location != "LOC_NOWHERE" and ("immovable" not in obj[1] or not obj[1]["immovable"]):
59             if location in startlocs:
60                 startlocs[location].append(objname)
61             else:
62                 startlocs[location] = [objname]
63
64     startlocs = {}
65     for obj in db["objects"]:
66         objname = obj[0]
67         location = obj[1].get("locations")
68         if "OBJ" not in objname and location != "LOC_NOWHERE" and ("immovable" not in obj[1] or not obj[1]["immovable"]):
69             if location in startlocs:
70                 startlocs[location].append(objname)
71             else:
72                 startlocs[location] = [objname]
73
74     print("digraph G {")
75     
76     for (loc, attrs) in db["locations"]:        
77         if subset == "surface" and not surface(attrs):
78             continue
79         if subset == "maze" and not allalike(loc):
80             continue;
81         node_label = loc[4:]
82         if loc in startlocs:
83             node_label += "\\n" + ",".join(startlocs[loc]).lower()
84         print('    %s [shape=box,label="%s"]' % (loc[4:], node_label))
85         
86     for (loc, attrs) in db["locations"]:        
87         if subset == "surface" and not surface(attrs):
88             continue
89         travel = attrs["travel"]
90         if len(travel) > 0:
91             for dest in travel:
92                 verbs = [abbreviate(x) for x in dest["verbs"]]
93                 if len(verbs) == 0:
94                     continue
95                 action = dest["action"]
96                 if action[0] == "goto":
97                     dest = action[1]
98                     if subset == "maze" and not (allalike(loc) or allalike(dest)):
99                         continue;
100                     arc = "%s -> %s" % (loc[4:], dest[4:])
101                     label=",".join(verbs).lower()
102                     if len(label) > 0:
103                         arc += ' [label="%s"]' % label
104                     print("    " + arc)
105     print("}")