#!python3 import random """generates a musical instrument by choosing at random a hornbostel-sachs category. this version is uniformly distributed between the options at each level, but does not include suffxes.""" strip_dashes_and_dots = lambda x: x.replace("-", "").replace(".", "").replace(" ", "") def generate_instrument(listing): """ listing contains a hornbostel-sachs dictionary; this steps through index-by-index picking numbers at random one by one until it's gotta stop, so this has even chances of every category, rather than an even chance to every listing.""" nice_from_stripped = {strip_dashes_and_dots(x): x for x in listing.keys()} stripped_keys = [strip_dashes_and_dots(x) for x in listing.keys()] prefix = random.choice([x for x in stripped_keys if len(x) == 1]) final_code = pick_code(prefix, [x for x in stripped_keys if x.startswith(prefix)]) return nice_from_stripped[final_code] # this defines a threshhold for quitting early dependent on the length of the code so far. # so there's a 0% chance of stopping with a zero-length code, 0% with a 1-length code, 1% with 2-length... chance_of_stopping = [0, 0, 0.01, 0.01, 0.01, 0.05, 0.05, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2] def pick_code(prefix, keys): if random.random() < chance_of_stopping[len(prefix)]: return prefix # only look at keys that are one longer than the current key next_keys = [x for x in keys if len(x) == len(prefix) + 1] if len(next_keys) == 0: return prefix # if we can't find any successors then stop next_prefix = random.choice(next_keys) return pick_code(next_prefix, [x for x in keys if x.startswith(next_prefix)]) if __name__ == "__main__": with open("Hornbostel-Sachs") as f: hornbostelsachs = {line.split(" ")[0]: " ".join(line.split(" ")[1:]) for line in f.readlines()} val = generate_instrument(hornbostelsachs) parents = [val[0:x+1] for x in range(len(val)) if val[x].isdigit()] for x in parents: print(x, " : ", hornbostelsachs[x].strip())