git @ Cat's Eye Technologies Samovar / master src / samovar / generators / depthfirst.py
master

Tree @master (Download .tar.gz)

depthfirst.py @masterraw · history · blame

# encoding: UTF-8

# FIXME: just a sketch for now

import sys
import time

from samovar.ast import Assert, Retract
from samovar.database import Database

from .base import Event, BaseGenerator


class DepthFirstGenerator(BaseGenerator):
    def __init__(self, world, scenario, verbosity=0, sorted_search=True, randomness=None):
        self.world = world
        self.scenario = scenario
        self.verbosity = verbosity
        self.sorted_search = sorted_search
        self.random = randomness
        self.seen_states = set()

    def generate_events(self, **kwargs):
        self.seen_states = set()

        # Create initial stacks.
        state = Database(self.scenario.propositions, sorted_search=self.sorted_search)
        candidate_rules = list(self.candidate_rules(state, require_change=True))
        stack = [
            [None, state, candidate_rules, 0]
        ]

        # Loop, doing work at the top of the stack.
        done = False
        counter = 0
        while not done:
            counter += 1
            [last_event, state, candidate_rules, cr_index] = stack[-1]
            if self.verbosity >= 1 and counter % 1000 == 0:
                sys.stderr.write("Stack depth {}, candidate count {}, index {}\n".format(
                    len(stack), len(candidate_rules), cr_index
                ))
            if cr_index > (len(candidate_rules) - 1):
                # we've exhausted all the candidates on this level.  backtrack.
                if self.verbosity >= 1:
                    sys.stderr.write("*** Backtracking\n")
                stack.pop()
                continue

            # otherwise, try to make a match.
            rule, unifier = candidate_rules[cr_index]

            new_event = Event(rule, unifier)
            new_state = state.clone()
            self.update_state(new_state, unifier, rule)
            if self.verbosity >= 2:
                self.debug_state(new_state, "Intermediate")
            if self.goal_is_met(new_state):
                return [e[0] for e in stack if e[0] is not None] + [new_event]

            froz = frozenset(new_state.contents)
            if froz in self.seen_states:
                stack[-1][3] += 1   # inc cr_index. TODO this is so ugly
                continue
            self.seen_states.add(froz)

            # otherwise, descend to try to extend the sequence of events we've got.
            new_candidate_rules = list(self.candidate_rules(new_state, require_change=True))
            stack.append(
                [new_event, new_state, new_candidate_rules, 0]
            )

        return None