1import math 2import random 3import sys 4import itertools 5from hashlib import md5 6from typing import Iterable, Iterator, Tuple 7 8error_list = [] 9 10 11def int_hash(s): 12 h = md5() 13 h.update(s) 14 return int(h.hexdigest(), 16) 15 16 17def seed_rng(seed): 18 """ 19 Seeds the default RNG with the specified seed 20 """ 21 random.seed(seed) 22 # The following jumpahead call can be uncommented to work around this issue of the Mersenne Twister PRNG 23 # (quoted from wikipedia http://en.wikipedia.org/wiki/Mersenne_twister): 24 # "It can take a long time to start generating output that passes randomness tests, if the initial state is highly 25 # non-random-- particularly if the initial state has many zeros. A consequence of this is that two instances of the 26 # generator, started with initial states that are almost the same, will usually output nearly the same sequence 27 # for many iterations, before eventually diverging." 28 # random.jumpahead(999999) 29 30 31def distance(start, end): 32 """ 33 Calculates linear distance between two coordinates. 34 """ 35 x1, y1 = start 36 x2, y2 = end 37 return math.hypot(float(x1) - float(x2), float(y1) - float(y2)) 38 39 40def report_error(msg): 41 """ 42 Handles error messages. 43 """ 44 error_list.append(msg) 45 print(msg, file=sys.stderr) 46 47 48def unique_product(first: Iterable[int], second: Iterable[int]) -> Iterator[Tuple[int, int]]: 49 """ 50 Create all possible unique pairs for two iterables. 51 Both iterables should consist of comparable objects. 52 Pair is sorted in ascending order. 53 """ 54 return filter(lambda x: x[0] < x[1], itertools.product(first, second)) 55 56 57class MapGenerationError(RuntimeError): 58 """Map generation runtime error.""" 59