def get_defined_playfield(alpaca): assert alpaca.type == 'Alpaca' playast = alpaca.playfield assert playast.type == 'Playfield' if playast.value is None: return None repr_map = construct_representation_map(alpaca) pf = Playfield(get_default_state(alpaca), repr_map) for (x, y, ch) in playast.value: pf.set(x, y, repr_map[ch]) pf.recalculate_limits() return pf
def main(argv): argparser = ArgumentParser() argparser.add_argument( 'source', metavar='SOURCE', type=str, help='Name of the file containing the ALPACA description to process, ' 'or "test" to run internal tests only and exit') argparser.add_argument("-a", "--show-ast", action="store_true", help="show parsed AST instead of evaluating") argparser.add_argument( "-c", "--compile-to", metavar='BACKEND', default=None, help="compile to given backend code instead " "of evaluating directly (available backends: javascript)") argparser.add_argument("-d", "--divider", metavar='STRING', default="-----", help="set the string shown between generations " "(default: '-----')") argparser.add_argument("-f", "--halt-at-fixpoint", action="store_true", help="stop evolving CA when it comes to a trivial " "fixed point (playfield = previous playfield)") argparser.add_argument("-g", "--generations", metavar='COUNT', dest="generations", default=None, type=int, help="evolve CA for only the given number of " "generations") argparser.add_argument("-i", "--initial-configuration", metavar='FILENAME', type=str, default=None, help="initial configuration to load into playfield " "(when evolving a playfield only)") argparser.add_argument("-I", "--hide-initial", action="store_false", dest="show_initial", help="don't show initial configuration") argparser.add_argument("-J", "--hide-intermediate", action="store_false", dest="show_intermediate", default=True, help="don't show intermediate configurations " "(only show final configuration)") argparser.add_argument("-p", "--parse-only", action="store_true", help="parse the ALPACA description only and exit") argparser.add_argument("-v", "--verbose", action="store_true", help="run verbosely") argparser.add_argument( "--display-window", metavar='RANGE', default=None, help= "A string in the form '(x1,y1)-(x2-y2)'; if given, every generation " "displayed will only display the cells within this fixed window") argparser.add_argument("--display-svg", action="store_true", help="Display each generation as SVG") argparser.add_argument("--stylesheet", metavar='FILENAME', default=None, help="Use the given file as the ALPACA stylesheet " "(only supported in SVG output currently)") argparser.add_argument( "--write-discrete-files-to", metavar='DIRNAME', default=None, help= "If given, instead of displaying each generation on standard output, " "write it to a new numbered file in this directory") options = argparser.parse_args(argv[1:]) if options.source == 'test': import doctest (fails, something) = doctest.testmod(analysis) if fails == 0: print "All tests passed." sys.exit(0) else: sys.exit(1) with open(options.source, 'r') as f: text = f.read() ast = Parser(text).alpaca() if options.parse_only: sys.exit(0) if options.show_ast: from pprint import pprint pprint(ast) sys.exit(0) default_state = get_default_state(ast) repr_map = construct_representation_map(ast) if options.compile_to is not None: # XXX generalize if options.compile_to == 'javascript': from alpaca.backends.javascript import Compiler compiler = Compiler(ast, sys.stdout, options=options) success = compiler.compile() if success: sys.exit(0) else: print "unsupported backend '%s'" % options.compile_to sys.exit(1) display_x1, display_y1, display_x2, display_y2 = None, None, None, None if options.display_window: match = re.match(r'^\((-?\d+)\,(-?\d+)\)\-\((-?\d+)\,(-?\d+)\)$', options.display_window) try: (display_x1, display_y1, display_x2, display_y2) = (int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4))) except Exception as e: print "Could not parse '{}'".format(options.display_window) raise pf = get_defined_playfield(ast) if pf is None: if not options.initial_configuration: print "source file does not define an initial configuration," print "and no cellular automaton configuration file given" sys.exit(1) with open(options.initial_configuration) as f: pf = Playfield(default_state, repr_map) pf.load(f) count = 0 def print_divider(): # TODO: allow formatting string in the divider, esp. # to show the # of this generation if options.divider != '': print options.divider def begin_output(): if not options.write_discrete_files_to: print_divider() if options.stylesheet: stylesheet = open(options.stylesheet).read() else: stylesheet = None def output_frame(count, pf): if options.display_window: if options.display_svg: rendered = pf.to_svg(display_x1, display_y1, display_x2, display_y2, stylesheet=stylesheet) else: rendered = pf.to_str(display_x1, display_y1, display_x2, display_y2) else: if options.display_svg: rendered = pf.to_svg(pf.min_x, pf.min_y, pf.max_x, pf.max_y, stylesheet=stylesheet) else: rendered = str(pf) if options.write_discrete_files_to: with open( os.path.join(options.write_discrete_files_to, "%08d.txt" % count), 'w') as f: f.write(rendered) else: sys.stdout.write(rendered) print_divider() begin_output() if options.show_initial: output_frame(count, pf) while True: new_pf = Playfield(default_state, repr_map) evolve_playfield(pf, new_pf, ast, verbose=options.verbose) new_pf.recalculate_limits() if options.halt_at_fixpoint: if pf.equals(new_pf): break pf = new_pf count += 1 if (options.show_intermediate or (options.generations is not None and count == options.generations - 1)): output_frame(count, pf) if (options.generations is not None and count >= options.generations): break sys.exit(0)