|
| 1 | +import re |
| 2 | +import os |
| 3 | +import numpy as np |
| 4 | + |
| 5 | +import terrain |
| 6 | +from grammar import parser |
| 7 | + |
| 8 | +grammar = open("description.grammar").read() |
| 9 | +desc = parser(grammar) |
| 10 | + |
| 11 | +@desc.function("word", str) |
| 12 | +def word(director, key): |
| 13 | + m = director.kwargs["mapgrid"] |
| 14 | + return "*" + m.lang.word(key) + "*" |
| 15 | + |
| 16 | +@desc.function("name", str) |
| 17 | +def name(director, key): |
| 18 | + m = director.kwargs["mapgrid"] |
| 19 | + return m.lang.name(key) |
| 20 | + |
| 21 | + |
| 22 | +def direction(m, p1, p2): |
| 23 | + x, y = m.vxs[p2,:] - m.vxs[p1,:] |
| 24 | + angle = int(4 * np.arctan2(y, x) / np.pi + 4.5) % 8 |
| 25 | + return ["west", "south-west", "south", "south-east", |
| 26 | + "east", "north-east", "north", "north-west"][angle] |
| 27 | + |
| 28 | +def describe(m, city, last_city=None): |
| 29 | + paras = [] |
| 30 | + direc = "" |
| 31 | + far = False |
| 32 | + near = False |
| 33 | + land = True |
| 34 | + sea = False |
| 35 | + if last_city is not None: |
| 36 | + direc = direction(m, city, last_city) |
| 37 | + path,_ = m.shortest_path(last_city, city) |
| 38 | + dist = terrain.distance(m.vxs[city,:], m.vxs[last_city,:]) |
| 39 | + far = bool(dist > 0.3) |
| 40 | + near = bool(dist < 0.15) |
| 41 | + land = bool(np.mean(m.elevation[path] > 0) > 0.4) |
| 42 | + sea = bool(np.mean(m.elevation[path] <= 0) > 0.4) |
| 43 | + kwargs = {"lastcity": m.city_names.get(last_city, ""), |
| 44 | + "city": m.city_names[city], |
| 45 | + "region": m.region_names[city], |
| 46 | + "direction": direc, |
| 47 | + "far": far, |
| 48 | + "near": near, |
| 49 | + "islandjourney": land, |
| 50 | + "isseajourney": sea, |
| 51 | + "mapgrid": m} |
| 52 | + paras.extend(desc("description", **kwargs).split("\n")) |
| 53 | + return paras |
| 54 | + |
| 55 | +def mdize(name): |
| 56 | + name = re.sub('`', u'\u02bb', name) |
| 57 | + return name |
| 58 | + |
| 59 | +def get_map(directory, mode): |
| 60 | + try: |
| 61 | + m = terrain.load(directory + "/map.pickle") |
| 62 | + except: |
| 63 | + m = terrain.MapGrid(mode=mode) |
| 64 | + m.save(directory + "/map.pickle") |
| 65 | + return m |
| 66 | + |
| 67 | +def draw_map(directory, m): |
| 68 | + m.plot(directory + "/map.png", dpi=200) |
| 69 | + |
| 70 | +def write_description(directory, m): |
| 71 | + with open(directory + "/map.md", "w") as f: |
| 72 | + last_city = None |
| 73 | + cities = m.ordered_cities() |
| 74 | + reg1 = m.region_names[cities[0]] |
| 75 | + reg2 = m.region_names[cities[-1]] |
| 76 | + title = "%s to %s" % (reg1, reg2) |
| 77 | + f.write("# %s\n\n" % mdize(title).encode("utf8")) |
| 78 | + for city in cities: |
| 79 | + name = mdize(m.city_names[city]) |
| 80 | + f.write("## %s\n" % name.encode("utf8")) |
| 81 | + for para in describe(m, city, last_city=last_city): |
| 82 | + f.write("%s\n\n" % mdize(para).encode("utf8")) |
| 83 | + last_city = city |
| 84 | + |
| 85 | +def process_directory(directory, mode="shore"): |
| 86 | + print "PROCESSING", directory, mode |
| 87 | + m = get_map(directory, mode) |
| 88 | + draw_map(directory, m) |
| 89 | + write_description(directory, m) |
| 90 | + |
| 91 | +def choose(lst, p): |
| 92 | + n = len(lst) - 1 |
| 93 | + return lst[sum(np.random.random() < p for _ in xrange(n))] |
| 94 | + |
| 95 | +def do_novel(directory='tests/full', n=100): |
| 96 | + modes = ["shore", "island", "mountain", "desert"] |
| 97 | + last_mode = "shore" |
| 98 | + for i in xrange(n): |
| 99 | + mode = choose(modes, i/(n-1.)) |
| 100 | + if mode == last_mode: |
| 101 | + mapmode = mode |
| 102 | + else: |
| 103 | + mapmode = last_mode + "/" + mode |
| 104 | + direc = "%s/%02d" % (directory, i) |
| 105 | + try: |
| 106 | + os.makedirs(direc) |
| 107 | + except: |
| 108 | + pass |
| 109 | + process_directory(direc, mode=mapmode) |
| 110 | + last_mode = mode |
| 111 | + |
0 commit comments