def next_id(story, type): """ Scans through the given story and returns the next ID number for the given object type. """ highest = -1 for (schema, binding) in ans.bindings({"id": ID_PATTERN}, story): id_type = dequote(str(binding["id.Type"].name)) id_int = int(binding["id.ID"].name) if id_type == type and id_int > highest: highest = id_int return highest + 1
def glean_nouns(story): result = {} for sc, binding in ans.bindings(NOUN_SCHEMAS, story): n = binding["st.property.inst.Key"].unquoted() t = binding["st.property.inst.Type"].unquoted() if n not in result: result[n] = nouns.Noun(n, TR_TYPE[t] if t in TR_TYPE else "thing") if sc == "name": result[n].name = binding["st.property.Name"].unquoted() elif sc == "number": result[n].number = binding["st.property.Number"].unquoted() elif sc == "gender": result[n].gender = binding["st.property.Gender"].unquoted() elif sc == "person": result[n].person = binding["st.property.Person"].unquoted() elif sc == "determined": d = binding["st.property.Determination"].unquoted() result[n].determined = d == "true" return result
def filter_keep(story): result = [] for sch, bnd in ans.bindings(KEEP, story): result.append(bnd[sch]) # Unique key handling: max_unique_key = None for pr in story: b = ans.bind(SC["unique_key_used"], pr) if b: k = int(str(b["unique_key_used.Key"])) if max_unique_key == None or k > max_unique_key: max_unique_key = k b = ans.bind(SC["max_unique"], pr) if b: k = int(str(b["max_unique.Key"])) if max_unique_key == None or k > max_unique_key: max_unique_key = k if max_unique_key == None: result.append(Pr("max_unique", Pr(0))) else: result.append(Pr("max_unique", Pr(max_unique_key))) return result
def gen(t): nonlocal name, code, source if not t.mem.code: raise ASPTaskError( "Task '{}' has no code (missing t.mem.code)!".format(name)) if type(t.net.mem.code.story) == obj.EmptyObj: raise ASPTaskError( "No story found (missing t.net.mem.code.story)!") if type(t.net.mem.code.universal) == obj.EmptyObj: raise ASPTaskError( "No universal constraints object (missing t.net.mem.code.universal)!" ) problem = assemble_problem(t) predicates = asp.solve(problem) # print("Predicates:") # for p in predicates: # print(p) errors = [] status = None story_predicates = set() to_run = [] to_spawn = {} lmemlist = [] gmemlist = [] for (schema, binding) in ans.bindings(story_schemas, predicates): story_predicates.add(binding[schema]) for (schema, binding) in ans.bindings(active_schemas, predicates): if schema == "error": print("Error in Clingo output!") errors.append(dequote(str(binding["error.Message"]))) elif schema == "status": s = dequote(str(binding["status.String"])) if status == None: status = s else: status = status + " and " + s elif schema == "local_mem": lmemlist.append( (dequote(str(binding["local_mem.Address"].name)), binding["local_mem.Value"])) elif schema == "global_mem": gmemlist.append((dequote(str(binding["global_mem.Address"])), binding["global_mem.Value"])) elif schema == "spawn_task": tid = str(binding["spawn_task.Id"]) tname = dequote(str(binding["spawn_task.TaskName"])) if tid not in to_spawn: to_spawn[tid] = { "name": "<unknown>", "args": {}, } to_spawn[tid]["name"] = tname elif schema == "task_arg": tid = str(binding["task_arg.Id"]) tkey = dequote(str(binding["task_arg.Key"])) tval = dequote(str(binding["task_arg.Value"])) if tid not in to_spawn: to_spawn[tid] = { "name": "<unknown>", "args": {}, } to_spawn[tid]["args"][tkey] = tval elif schema == "run_code": to_run.append(unquote(binding["run_code.QuotedCode"])) if errors: raise ASPTaskError("Error(s) while resolving answer set task:\n" + '\n'.join(errors)) if status in tn.TaskStatus.aliases: status = tn.TaskStatus.aliases[status] elif status == None: status = tn.TaskStatus.Final.Completed else: raise ASPTaskError( "Error: answer set produced invalid status '{}'.".format( status)) # Run code blocks before additions and removals are processed: for code in to_run: code_locals = { "status": status, "task": t, "story_predicates": story_predicates, "lmemlist": lmemlist, "gmemlist": gmemlist, } compiled = compile( code, "<snippet from ASP task '{}' in {}>".format(name, source), 'exec') exec(compiled, {}, code_locals) status = code_locals["status"] story_predicates = code_locals["story_predicates"] lmemlist = code_locals["lmemlist"] gmemlist = code_locals["gmemlist"] # Process the new story and memory elements: t.set_story(story_predicates) for (addr, val) in lmemlist: t.mem[addr] = val for (addr, val) in gmemlist: t.net.mem[addr] = val # Spawn tasks: for id in to_spawn: spawn_task(t.net, to_spawn[id]["name"], **to_spawn[id]["args"]) # We're finally done, so yield the indicated status: yield status
def filter_keep(story): result = [] for sch, bnd in ans.bindings(KEEP, story): result.append(bnd[sch]) return result
def build_story_text(story, root=None): node_templates = {} # First, build all of the templates for the entire story: for sc, bnd in ans.bindings(TEXT_SCHEMAS, story): node = bnd["txt.Node"].unquoted() print("Adding {} template for node '{}'.".format(sc, node)) if node not in node_templates: node_templates[node] = { "name": node, "intro": "", "situation": "", "options": {}, "outcomes": {}, # TODO: state-change text } txt = bnd["txt.Text"].unquoted() if sc == "intro_text": node_templates[node]["intro"] = txt elif sc == "potential_text": if node_templates[node]["situation"]: node_templates[node]["situation"] += " and " node_templates[node]["situation"] += txt elif sc == "option_text": opt = bnd["txt.option.Opt"].unquoted() node_templates[node]["options"][opt] = txt elif sc == "action_text": opt = bnd["txt.option.Opt"].unquoted() node_templates[node]["outcomes"][opt] = txt # Next, use the node structure to recursively render the story text in # ChoiceScript: nouns = glean_nouns(story) node_structure = find_node_structure(story) base_pnslots = { "I": [0, set()], "we": [0, set()], "you": [0, { "the_party" }], "he": [0, set()], "she": [0, set()], "it": [0, set()], "they": [0, set()], } base_introduced = { "the_party" } # Start with all root nodes on our open list: olist = [ (n, base_pnslots, base_introduced) for n in node_templates.keys() if len(node_structure[n]["predecessors"]) == 0 ] print("Root nodes: {}".format([n for (n, bp, bi) in olist])) # The ready dictionary keeps track of introduction and pronoun information # propagating between non-root nodes and has enough information to know when # a node is ready to be rendered: ready = { n: { pr: None for pr in node_structure[n]["predecessors"]} for n in node_templates.keys() if len(node_structure[n]["predecessors"]) > 0 } results = [] while olist: target, pnslots, introduced = olist.pop(0) print("Processing node: '{}'.".format(target)) # build node text: txt, outgoing = build_node_text( node_templates[target], node_structure, nouns, pnslots, introduced ) results.append(txt) # update our readiness information and propagate nodes to the open list as # they're fully ready: for n in [x for x in outgoing if x in ready]: # DEBUG: if None not in ready[n].values(): raise RuntimeError(""" Updating readiness of already-ready node '{}' from node '{}'. Readiness is: {}\ """.format(n, target, ready[n]) ) ready[n][target] = outgoing[n] if None not in ready[n].values(): pns, intr = merge_txt_states(list(ready[n].values())) # TODO: Get rid of pnslots merging altogether? #olist.append((n, pns, intr)) olist.append((n, base_pnslots, intr)) return ("\n\n*comment " + '-'*72 + "\n\n").join(results)
def gen(t): nonlocal name, code, source if not t.mem.code: raise ASPTaskError( "Task '{}' has no code (missing t.mem.code)!".format(name) ) if type(t.net.mem.code.story) == obj.EmptyObj: raise ASPTaskError("No story found (missing t.net.mem.code.story)!") if type(t.net.mem.code.universal) == obj.EmptyObj: raise ASPTaskError( "No universal constraints object (missing t.net.mem.code.universal)!" ) problem = assemble_problem(t) predicates = asp.solve(problem) # print("Predicates:") # for p in predicates: # print(p) errors = [] status = None story_predicates = set() to_run = [] to_spawn = {} lmemlist = [] gmemlist = [] for (schema, binding) in ans.bindings(story_schemas, predicates): story_predicates.add(binding[schema]) for (schema, binding) in ans.bindings(active_schemas, predicates): if schema == "error": print("Error in Clingo output!") errors.append(dequote(str(binding["error.Message"]))) elif schema == "status": s = dequote(str(binding["status.String"])) if status == None: status = s else: status = status + " and " + s elif schema == "local_mem": lmemlist.append( ( dequote(str(binding["local_mem.Address"].name)), binding["local_mem.Value"] ) ) elif schema == "global_mem": gmemlist.append( ( dequote(str(binding["global_mem.Address"])), binding["global_mem.Value"] ) ) elif schema == "spawn_task": tid = str(binding["spawn_task.Id"]) tname = dequote(str(binding["spawn_task.TaskName"])) if tid not in to_spawn: to_spawn[tid] = { "name": "<unknown>", "args": {}, } to_spawn[tid]["name"] = tname elif schema == "task_arg": tid = str(binding["task_arg.Id"]) tkey = dequote(str(binding["task_arg.Key"])) tval = dequote(str(binding["task_arg.Value"])) if tid not in to_spawn: to_spawn[tid] = { "name": "<unknown>", "args": {}, } to_spawn[tid]["args"][tkey] = tval elif schema == "run_code": to_run.append(unquote(binding["run_code.QuotedCode"])) if errors: raise ASPTaskError( "Error(s) while resolving answer set task:\n" + '\n'.join(errors) ) if status in tn.TaskStatus.aliases: status = tn.TaskStatus.aliases[status] elif status == None: status = tn.TaskStatus.Final.Completed else: raise ASPTaskError( "Error: answer set produced invalid status '{}'.".format(status) ) # Run code blocks before additions and removals are processed: for code in to_run: code_locals={ "status": status, "task": t, "story_predicates": story_predicates, "lmemlist": lmemlist, "gmemlist": gmemlist, } compiled = compile( code, "<snippet from ASP task '{}' in {}>".format(name, source), 'exec' ) exec( compiled, {}, code_locals ) status = code_locals["status"] story_predicates = code_locals["story_predicates"] lmemlist = code_locals["lmemlist"] gmemlist = code_locals["gmemlist"] # Process the new story and memory elements: t.set_story(story_predicates) for (addr, val) in lmemlist: t.mem[addr] = val for (addr, val) in gmemlist: t.net.mem[addr] = val # Spawn tasks: for id in to_spawn: spawn_task( t.net, to_spawn[id]["name"], **to_spawn[id]["args"] ) # We're finally done, so yield the indicated status: yield status
def viz(story, error=False, lasttarget=None): """ Visualize the given set of predicates (writes out to a file). """ nodes = set() node_properties = {} links = {} for sch, bnd in ans.bindings(SCHEMAS, story): if sch == "story_node": node = bnd["story_node.Node"].unquoted() nodes.add(node) if node not in node_properties: node_properties[node] = {} elif sch == "node_type": node = bnd["node_type.Node"].unquoted() typ = bnd["node_type.Type"].unquoted() nodes.add(node) if node not in node_properties: node_properties[node] = {} node_properties[node]["type"] = typ elif sch == "node_status_reached": node = bnd["node_status_reached.Node"].unquoted() status = bnd["node_status_reached.Status"].unquoted() nodes.add(node) if node not in node_properties: node_properties[node] = {} if ("status" not in node_properties[node]) or ( NODE_STATUSES.index(node_properties[node]["status"]) < NODE_STATUSES.index(status)): node_properties[node]["status"] = status elif sch == "successor": src = bnd["successor.From"].unquoted() opt = bnd["successor.option.Opt"].unquoted() dst = bnd["successor.To"].unquoted() if src not in links: links[src] = {} links[src][opt] = dst elif sch == "action": src = bnd["at.Node"].unquoted() opt = bnd["at.action.option.Opt"].unquoted() act = bnd["at.action.Action"].unquoted() if src not in links: links[src] = {} if "actions" not in links[src]: links[src]["actions"] = {} links[src]["actions"][opt] = act elif sch == "vignette": node = bnd["vignette.Node"].unquoted() root = bnd["vignette.Root"].unquoted() nodes.add(node) if node not in node_properties: node_properties[node] = {} node_properties[node]["vignette"] = root elif sch == "setup": node = bnd["setup.Node"].unquoted() setup = bnd["setup.Which"].unquoted() nodes.add(node) if node not in node_properties: node_properties[node] = {} node_properties[node]["setup"] = setup # Write out the graphviz graph: gv = """\ digraph "story" { graph [ fontname = "TeXGyre-Pagella", fontsize = 12 ]; """ for node in nodes: if "status" not in node_properties[node]: color = "gray" elif node_properties[node]["status"] == "uninitialized": color = "red" elif node_properties[node]["status"] == "polished": color = "green" else: color = "yellow" gvattrs = [ 'color = {}'.format(color), ] if error and node == lasttarget: shape = "diamond" elif "type" not in node_properties[node]: shape = "polygon" elif node_properties[node]["type"] == "event": shape = "box" elif node_properties[node]["type"] == "choice": shape = "oval" elif node_properties[node]["type"] == "ending": shape = "invtriangle" gvattrs.append('shape = {}'.format(shape)) if "setup" in node_properties[node]: gvattrs.append('label = "s:{}"'.format( node_properties[node]["setup"])) gv += ' "{}" [{}];\n'.format(node, ', '.join(gvattrs)) for src in links: if src not in nodes: continue for opt in [o for o in links[src] if o != "actions"]: dst = links[src][opt] if dst not in nodes: continue if "actions" in links[src] and opt in links[src]["actions"]: act = links[src]["actions"][opt] else: act = "unknown" linkattrs = ['label = "{}"'.format(act)] if (node_properties[src].get("vignette") and (node_properties[src].get("vignette") == node_properties[dst].get("vignette"))): linkattrs.append('style = bold') gvattrs = '' if linkattrs: gvattrs = ' [{}]'.format(', '.join(linkattrs)) gv += ' "{}" -> "{}"{};\n'.format(src, dst, gvattrs) gv += "}" with open(VIZ_GV, 'w') as fout: fout.write(gv) subprocess.call(VIZ_EXE + [VIZ_GV, "-Tsvg", "-o", VIZ_SVG])