From 63041a5e62573a442e8a43b43e4c2a9c3c522e8e Mon Sep 17 00:00:00 2001 From: Pelle Nilsson Date: Tue, 23 Sep 2014 23:15:00 +0200 Subject: [PATCH] checkgamebook.py now can find unreachable sections in books. --- checkgamebook.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ readme.org | 10 ++++---- todo.org | 8 ++++--- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/checkgamebook.py b/checkgamebook.py index 3a517e3..f046478 100755 --- a/checkgamebook.py +++ b/checkgamebook.py @@ -35,8 +35,63 @@ import json USAGE = "usage: %prog [options] inputfile(s)... outputfile" +def find_section_nr_names(sections): + section_nr_to_name = {} + for section_name,section_contents in sections.iteritems(): + section_nr_to_name[section_contents["nr"]] = section_name + return section_nr_to_name + +def find_references(sections): + section_nr_to_name = find_section_nr_names(sections) + references = {} + for section_name,section_contents in sections.iteritems(): + references_from_section = [] + for t in section_contents["text"]: + if isinstance(t, dict) and "reference" in t: + ref = section_nr_to_name[int(t["reference"])] + references_from_section.append(ref) + references[section_name] = references_from_section + return references + +def traverse(sections, references, function, data): + stack = ["start"] + visited = set() + while len(stack) > 0: + section = stack.pop() + function(section, data) + visited.add(section) + for reference in references[section]: + if reference not in visited: + stack.append(reference) + +def traverse_add(section, data): + data.add(section) + +found_errors = False # yay, global state +def check_error(msg): + print "%s: %s" % (sys.argv[1], msg) + global found_errors + found_errors = True + +def check_all_sections_can_be_reached_in_theory(sections, references): + reached = set() + traverse(sections, references, traverse_add, reached) + for section in sections: + if section not in reached: + check_error("Could not reach section '%s' from start." % section) + def check_gamebook(inputfilename): book = json.load(open(inputfilename)) + sections = book["sections"] + if not "start" in sections: + check_error("No start section found. Cancelling checks.") + sys.exit(1) + del sections["IGNORE-debug-json-padding-IGNORE"] + for section in sections.keys(): + if section.startswith("empty-"): + del sections[section] + references = find_references(sections) + check_all_sections_can_be_reached_in_theory(sections, references) if __name__ == '__main__': import argparse @@ -46,3 +101,7 @@ if __name__ == '__main__': help='input gamebook debug file (eg test.debug)') args = ap.parse_args() check_gamebook(args.inputfile) + if found_errors: + sys.exit(1) + else: + sys.exit(0) diff --git a/readme.org b/readme.org index 0bd514a..2fc8fc0 100644 --- a/readme.org +++ b/readme.org @@ -90,10 +90,12 @@ on a book and warn about things that do not look right. To use it first generate a *debug* output file version of the book, using the same flags (eg include-tags) as when formatting the real book. Then run *checkgamebook.py bookname.debug*. -(TODO: Currently does not really test anything. The idea -is that it should do things like trying to tell you about -sections that can not be reached, or items that are required -before they can possibly have been found.) +Currently only tests that all sections can be reached, in theory, +from the *start* section. It only looks for existing references, +and has no idea for instance if a locked door can never be +unlocked because it is impossible to find enough money to +pay for a key. Future versions will hopefully catch more +problems, but never all of them in complex books. ** Number Map Files Whenever formatgamebook.py runs it looks for a file with the same diff --git a/todo.org b/todo.org index a7680ba..47af07b 100644 --- a/todo.org +++ b/todo.org @@ -1,4 +1,4 @@ -* TODO [62/92] [67%] +* TODO [64/92] [69%] ** DONE Debug output ** DONE DOT output ** DONE LaTeX output @@ -79,8 +79,10 @@ Will be taken care of when implementing JSON output. ** DONE checkgamebook.py script, parse debug file JSON CLOSED: [2014-09-23 Tue 21:52] -** TODO checkgamebook.py build internal section graph -** TODO checkgamebook.py find unreachable sections +** DONE checkgamebook.py build internal section graph + CLOSED: [2014-09-23 Tue 23:10] +** DONE checkgamebook.py find unreachable sections + CLOSED: [2014-09-23 Tue 23:10] ** TODO JavaScript improved design/code for what links to enable Many strange things can happen when clicking one link changes something that should now enable or disable some link. Instead of the current