Esempio n. 1
0
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
Esempio n. 2
0
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)