Exemplo n.º 1
0
 def test_scan_tokens_domain(self):
     parser = PDDL_Parser()
     self.assertEqual(parser.scan_tokens('examples/dinner/dinner.pddl'), [
         'define', ['domain', 'dinner'], [':requirements', ':strips'],
         [
             ':predicates', ['clean'], ['dinner'], ['quiet'], ['present'],
             ['garbage']
         ],
         [
             ':action', 'cook', ':precondition', ['clean'], ':effect',
             ['dinner']
         ],
         [
             ':action', 'wrap', ':precondition', ['quiet'], ':effect',
             ['present']
         ],
         [
             ':action', 'carry', ':precondition', ['garbage'], ':effect',
             ['and', ['not', ['garbage']], ['not', ['clean']]]
         ],
         [
             ':action', 'dolly', ':precondition', ['garbage'], ':effect',
             ['and', ['not', ['garbage']], ['not', ['quiet']]]
         ]
     ])
Exemplo n.º 2
0
 def test_parse_predicates(self):
     parser = PDDL_Parser()
     parser.predicates = {}
     parser.parse_predicates(
         [['untyped_pred', '?v1', '?v2', '?v3'],
          [
              'typed_pred', '?v1', '-', 'type1', '?v2', '-', 'type1', '?v3',
              '-', 'object'
          ], ['shared_type_pred', '?v1', '?v2', '-', 'type1', '?v3']])
     self.assertEqual(
         parser.predicates, {
             'untyped_pred': {
                 '?v1': 'object',
                 '?v2': 'object',
                 '?v3': 'object'
             },
             'typed_pred': {
                 '?v1': 'type1',
                 '?v2': 'type1',
                 '?v3': 'object'
             },
             'shared_type_pred': {
                 '?v1': 'type1',
                 '?v2': 'type1',
                 '?v3': 'object'
             }
         })
Exemplo n.º 3
0
 def test_parse_undefined_types(self):
     parser = PDDL_Parser()
     parser.types = {}
     parser.parse_types(['location', 'pile', 'robot', 'crane', 'container'])
     self.assertEqual(
         parser.types,
         {'object': ['location', 'pile', 'robot', 'crane', 'container']})
Exemplo n.º 4
0
 def __init__(self, filename, domainName='reconstructed'):
     self.domainName = domainName
     self.parser = PDDL_Parser()
     self.tokens = self.parser.scan_tokens(filename)
     pprint.pprint(self.tokens)
     print('=== Objects ===')
     self.parseObjects(self.tokens[1])
     pprint.pprint(self.types2objs)
     print('=== States ===')
     self.parseStates(self.tokens)
     pprint.pprint(self.states)
     print('=== Predicates ===')
     pprint.pprint(self.predicates)
     print('=== Actions ===')
     self.parseActions(self.tokens)
     # print(self.tokens[3])
     # p, n = self.actions[0].assignPrecons(self.tokens[3][1][1:])
     # print('Grounded Positive preconditions')
     # print(p)
     # print('Grounded Negative preconditions')
     # print(n)
     # print('Before State')
     # print(self.states[0])
     # self.actions[0].prunePrecons(self.states[0], self.tokens[3][1][1:])
     # print(self.actions[0])
     self.refineActions(self.tokens)
     pprint.pprint(self.actions)
     self.genTypeclasses()
 def solve(self, domain, problem):
     # Parser
     parser = PDDL_Parser()
     parser.parse_domain(domain)
     parser.parse_problem(problem)
     # Parsed data
     actions = parser.actions
     state = parser.state
     goal_pos = parser.positive_goals
     goal_not = parser.negative_goals
     # Do nothing
     if self.applicable(state, goal_pos, goal_not):
         return []
     # Search
     visited = [state]
     fringe = [state, None]
     while fringe:
         state = fringe.pop(0)
         plan = fringe.pop(0)
         for act in actions:
             if self.applicable(state, act.positive_preconditions, act.negative_preconditions):
                 new_state = self.apply(state, act.add_effects, act.del_effects)
                 if new_state not in visited:
                     if self.applicable(new_state, goal_pos, goal_not):
                         full_plan = [act]
                         while plan:
                             act, plan = plan
                             full_plan.insert(0, act)
                         return full_plan
                     visited.append(new_state)
                     fringe.append(new_state)
                     fringe.append((act, plan))
     return None
Exemplo n.º 6
0
 def test_scan_tokens_problem(self):
     parser = PDDL_Parser()
     self.assertEqual(parser.scan_tokens('examples/dinner/pb1.pddl'), [
         'define', ['problem', 'pb1'], [':domain', 'dinner'],
         [':init', ['garbage'], ['clean'], ['quiet']],
         [':goal', ['and', ['dinner'], ['present'], ['not', ['garbage']]]]
     ])
 def test_scan_tokens_problem(self):
     parser = PDDL_Parser()
     self.assertEqual(parser.scan_tokens('dinner/pb1.pddl'),
         ['define', ['problem', 'pb1'],
         [':domain', 'dinner'],
         [':init', ['garbage'], ['clean'], ['quiet']],
         [':goal', ['and', ['dinner'], ['present'], ['not', ['garbage']]]]]
     )
 def test_parse_problem(self):
     parser = PDDL_Parser()
     parser.parse_domain('dinner/dinner.pddl')
     parser.parse_problem('dinner/pb1.pddl')
     self.assertEqual(parser.problem_name, 'pb1')
     self.assertEqual(parser.objects, [])
     self.assertEqual(parser.state, [['garbage'],['clean'],['quiet']])
     self.assertEqual(parser.positive_goals, [['dinner'], ['present']])
     self.assertEqual(parser.negative_goals, [['garbage']])
 def test_parse_domain(self):
     parser = PDDL_Parser()
     parser.parse_domain('dinner/dinner.pddl')
     self.assertEqual(parser.domain_name, 'dinner')
     self.assertEqual(parser.actions,
         [
             Action('cook', [], [['clean']], [], [['dinner']], []),
             Action('wrap', [], [['quiet']], [], [['present']], []),
             Action('carry', [], [['garbage']], [], [], [['garbage'], ['clean']]),
             Action('dolly', [], [['garbage']], [], [], [['garbage'], ['quiet']])
         ]
     )
Exemplo n.º 10
0
 def __init__(self, domainfile, problemfile):
     self.parser_help = PDDL_Parser()
     self.parser_help.parse_domain(domainfile)
     self.parser_help.parse_problem(problemfile)
     self.domprob = DomainProblem(domainfile, problemfile)
     self.current_state = None  # State object
     self.pos_goal = None  # tuple of literals that need to be true at goal
     self.neg_goal = None  # tuple of literals that need to be false at goal
     self.action_dic = None  # list of actions
     self.objects = None  # list of world objects
     self.reversed_objects = None  # for type of object, list of instances
     self.parser()
Exemplo n.º 11
0
 def test_parse_defined_types(self):
     parser = PDDL_Parser()
     parser.types = {}
     parser.parse_types([
         'place', 'locatable', 'level', '-', 'object', 'depot', 'market',
         '-', 'place', 'truck', 'goods', '-', 'locatable'
     ])
     self.assertEqual(
         parser.types, {
             'object': ['place', 'locatable', 'level'],
             'place': ['depot', 'market'],
             'locatable': ['truck', 'goods']
         })
Exemplo n.º 12
0
 def test_parse_domain(self):
     parser = PDDL_Parser()
     parser.parse_domain('dinner/dinner.pddl')
     self.assertEqual(parser.domain_name, 'dinner')
     self.assertEqual(parser.requirements, [':strips'])
     self.assertEqual(parser.types, [])
     self.assertEqual(parser.actions, [
         Action('cook', [], [['clean']], [], [['dinner']], []),
         Action('wrap', [], [['quiet']], [], [['present']], []),
         Action('carry', [], [['garbage']], [], [],
                [['garbage'], ['clean']]),
         Action('dolly', [], [['garbage']], [], [],
                [['garbage'], ['quiet']])
     ])
Exemplo n.º 13
0
    def __init__(self, domain, problem, logfile='/dev/null'):
        # Parser
        self.parser = PDDL_Parser()
        self.parser.parse_domain(domain)
        self.parser.parse_problem(problem)
        # Parsed data
        self.state = self.parser.state
        self.goal_pos = self.parser.positive_goals
        self.goal_not = self.parser.negative_goals

        self.history = []
        self.movelog = []

        self.logfile = logfile

        self.planner = Planner()
        # Do nothing
        if self.planner.applicable(self.state, self.goal_pos, self.goal_not):
            print('Puzzle is already solved! Double-check your problem file!')
Exemplo n.º 14
0
 def solve(self, domain, problem):
     # Parser
     parser = PDDL_Parser()
     parser.parse_domain(domain)
     parser.parse_problem(problem)
     # Parsed data
     actions = parser.actions
     state = parser.state
     goal_pos = parser.positive_goals
     goal_not = parser.negative_goals
     # Do nothing
     if self.applicable(state, goal_pos, goal_not):
         return []
     # Search
     visited = [state]
     fringe = [state, None]
     while fringe:
         state = fringe.pop(0)
         plan = fringe.pop(0)
         for act in actions:
             if self.applicable(state, act.positive_preconditions,
                                act.negative_preconditions):
                 new_state = self.apply(state, act.add_effects,
                                        act.del_effects)
                 if new_state not in visited:
                     if self.applicable(new_state, goal_pos, goal_not):
                         full_plan = [act]
                         while plan:
                             act, plan = plan
                             full_plan.insert(0, act)
                         return full_plan
                     visited.append(new_state)
                     fringe.append(new_state)
                     fringe.append((act, plan))
     return None
Exemplo n.º 15
0
def constraints(domain, problem):
    clause_list = []
    # Parser
    parser = PDDL_Parser()
    parser.parse_domain(domain)
    parser.parse_problem(problem)

    state = parser.state
    # Initial state clauses:
    initial_clauses = list(state)
    #print(initial_clauses)

    goal_pos = parser.positive_goals
    goal_not = parser.negative_goals
    goal_clauses = [goal_pos, goal_not]

    action_list = []
    # Grounding process
    ground_actions = []
    for action in parser.actions:
        for act in action.groundify(parser.objects):
            ground_actions.append(act)
    # Appending grounded actions:
    for act in ground_actions:
        action_list.append(act)
        #print(act)
    action_list.append(Action('noop', (), [], [], [], []))
    # Appending to one list:
    clause_list.append(initial_clauses)
    clause_list.append(goal_clauses)
    clause_list.extend(action_list)
    return clause_list
 def test_scan_tokens_domain(self):
     parser = PDDL_Parser()
     self.assertEqual(parser.scan_tokens('dinner/dinner.pddl'),
         ['define', ['domain', 'dinner'],
         [':requirements', ':strips'],
         [':predicates', ['clean'], ['dinner'], ['quiet'], ['present'], ['garbage']],
         [':action', 'cook',
             ':parameters', [],
             ':precondition', ['and', ['clean']],
             ':effect', ['and', ['dinner']]],
         [':action', 'wrap',
             ':parameters', [],
             ':precondition', ['and', ['quiet']],
             ':effect', ['and', ['present']]],
         [':action', 'carry',
             ':parameters', [],
             ':precondition', ['and', ['garbage']],
             ':effect', ['and', ['not', ['garbage']], ['not', ['clean']]]],
         [':action', 'dolly',
             ':parameters', [],
             ':precondition', ['and', ['garbage']],
             ':effect', ['and', ['not', ['garbage']], ['not', ['quiet']]]]]
     )
Exemplo n.º 17
0
 def test_parse_problem(self):
     parser = PDDL_Parser()
     parser.parse_domain('examples/dinner/dinner.pddl')
     parser.parse_problem('examples/dinner/pb1.pddl')
     self.assertEqual(parser.problem_name, 'pb1')
     self.assertEqual(parser.objects, {})
     self.assertEqual(parser.state, [['garbage'],['clean'],['quiet']])
     self.assertEqual(parser.positive_goals, [['dinner'], ['present']])
     self.assertEqual(parser.negative_goals, [['garbage']])
Exemplo n.º 18
0
 def test_parse_objects(self):
     parser = PDDL_Parser()
     parser.types = {}
     parser.objects = {}
     parser.parse_types(
         ['airplane', 'segment', 'direction', 'airplanetype', 'a'])
     parser.parse_objects([
         'b', '-', 'a', 'a', '-', 'a', 'north', 'south', '-', 'direction',
         'light', 'medium', 'heavy', '-', 'airplanetype', 'element1', '-',
         'object', 'seg_pp_0_60', 'seg_ppdoor_0_40', '-', 'segment',
         'airplane_CFBEG', '-', 'airplane', 'element2'
     ], 'test')
     self.assertEqual(
         parser.objects, {
             'a': ['b', 'a'],
             'object': ['element1', 'element2'],
             'direction': ['north', 'south'],
             'airplanetype': ['light', 'medium', 'heavy'],
             'segment': ['seg_pp_0_60', 'seg_ppdoor_0_40'],
             'airplane': ['airplane_CFBEG']
         })
Exemplo n.º 19
0
    def test_parse_problem(self):
        def frozenset_of_tuples(data):
            return frozenset([tuple(t) for t in data])

        parser = PDDL_Parser()
        parser.parse_domain('examples/dinner/dinner.pddl')
        parser.parse_problem('examples/dinner/pb1.pddl')
        self.assertEqual(parser.problem_name, 'pb1')
        self.assertEqual(parser.objects, {})
        self.assertEqual(
            parser.state,
            frozenset_of_tuples([['garbage'], ['clean'], ['quiet']]))
        self.assertEqual(parser.positive_goals,
                         frozenset_of_tuples([['dinner'], ['present']]))
        self.assertEqual(parser.negative_goals,
                         frozenset_of_tuples([['garbage']]))
Exemplo n.º 20
0
def constraints(domain, problem):
    gate_list = []
    # Parser
    parser = PDDL_Parser()
    parser.parse_domain(domain)
    parser.parse_problem(problem)

    state = parser.state
    # Initial state gate:
    initial_gate = list(state)
    #initial_gate = refine_gate(initial_gate)
    #print(initial_gate)

    goal_pos = parser.positive_goals
    goal_not = parser.negative_goals
    goal_gate = [goal_pos, goal_not]
    #goal_gate = [refine_gate(goal_pos), refine_gate(goal_not)]
    #print(goal_gate)

    #for act in parser.actions:
    #  #print(act)
    #  act.positive_preconditions = refine_gate(act.positive_preconditions)
    #  act.negative_preconditions = refine_gate(act.negative_preconditions)
    #  act.add_effects = refine_gate(act.add_effects)
    #  act.del_effects = refine_gate(act.del_effects)
    #  #print(act)

    action_list = []
    # Grounding process
    ground_actions = []
    for action in parser.actions:
        for act in action.groundify(parser.objects):
            ground_actions.append(act)
    # Appending grounded actions:
    for act in ground_actions:
        action_list.append(act)
        #print(act)

    # Appending to one list:
    gate_list.append(initial_gate)
    gate_list.append(goal_gate)
    gate_list.extend(action_list)
    return gate_list
Exemplo n.º 21
0
 def construct(self, domain, problem):
     # Parser
     parser = PDDL_Parser()
     parser.parse_domain(domain)
     parser.parse_problem(problem)
     # Parsed data
     state = parser.state
     initial_state = convert(state)
     goal_pos = parser.positive_goals
     goal_not = parser.negative_goals
     # Do nothing
     if self.applicable(state, goal_pos, goal_not):
         return []
     # Grounding process
     ground_actions = []
     for action in parser.actions:
         for act in action.groundify(parser.objects):
             ground_actions.append(act)
     # Search
     visited = [state]
     need_visit = [state]
     transitions = dict()
     while need_visit:
         state = need_visit.pop(0)
         transitions[convert(state)] = dict()
         for act in ground_actions:
             if self.applicable(state, act.positive_preconditions,
                                act.negative_preconditions):
                 new_state = self.apply(state, act.add_effects,
                                        act.del_effects)
                 if new_state not in visited:
                     visited.append(new_state)
                     need_visit.append(new_state)
                     transitions[convert(state)][act.name] = convert(
                         new_state)
     return [transitions, initial_state]
Exemplo n.º 22
0
class Engine:
    def __init__(self, domain, problem, logfile='/dev/null'):
        # Parser
        self.parser = PDDL_Parser()
        self.parser.parse_domain(domain)
        self.parser.parse_problem(problem)
        # Parsed data
        self.state = self.parser.state
        self.goal_pos = self.parser.positive_goals
        self.goal_not = self.parser.negative_goals

        self.history = []
        self.movelog = []

        self.logfile = logfile

        self.planner = Planner()
        # Do nothing
        if self.planner.applicable(self.state, self.goal_pos, self.goal_not):
            print('Puzzle is already solved! Double-check your problem file!')

    def parseCellName(self, cellName):
        x, y = cellName[4:].split('_')
        # print(cellName)
        # print(out)
        return int(x), int(y)

    def findPlayer(self):
        for pred in self.state:
            if pred[0] == 'player':
                return self.parseCellName(pred[1])
        raise ValueError('Player not found!')

    def formatPos(self, coords):
        return 'cell{}_{}'.format(coords[0], coords[1])

    def groundAction(self, act, assignment):
        variables = []
        for v, _ in act.parameters:
            variables.append(v)
        pps = act.replace(act.positive_preconditions, variables, assignment)
        nps = act.replace(act.negative_preconditions, variables, assignment)
        aes = act.replace(act.add_effects, variables, assignment)
        des = act.replace(act.del_effects, variables, assignment)
        return Action(act.name, assignment, pps, nps, aes, des)

    def addVec(self, *vecs):
        x = 0
        y = 0
        for u, v in vecs:
            x += u
            y += v
        return (x, y)

    # act must already be grounded (e.g. by self.groundAction)
    def tryAction(self, act, log):
        # print(self.state)
        # print(act.positive_preconditions)
        # print(act.negative_preconditions)
        # print(self.planner.applicable(self.state, act.positive_preconditions, act.negative_preconditions))
        if self.planner.applicable(self.state, act.positive_preconditions,
                                   act.negative_preconditions):
            # log.write(str(self.state) + '\n')
            # log.write(str(act))
            act_str = '(:action ({}))'.format(' '.join(
                [act.name, *act.parameters]))
            self.history.append(self.state)
            self.state = self.planner.apply(self.state, act.add_effects,
                                            act.del_effects)
            # log.write(self.lispState() + '\n\n')
            self.movelog.append('{}\n\n{}\n\n'.format(act_str,
                                                      self.lispState()))
            return True
        else:
            return False

    def lookupAction(self, actName):
        for act in self.parser.actions:
            if act.name == actName:
                return act
        return None

    def doMove(self, key, log):
        delta = None
        actions = []
        if key == 'w':
            delta = (0, -1)
            actions = ['movenorth', 'pushnorth']
        elif key == 'a':
            delta = (-1, 0)
            actions = ['movewest', 'pushwest']
        elif key == 's':
            delta = (0, 1)
            actions = ['movesouth', 'pushsouth']
        elif key == 'd':
            delta = (1, 0)
            actions = ['moveeast', 'pusheast']
        elif key == 'u':
            if len(self.history) >= 1:
                self.state = self.history.pop()
                self.movelog.pop()
            return True
        elif key == 'r':
            self.state = self.parser.state
            # self.history.append(self.state)
            self.history = [self.state]
            self.movelog = []
            return True
        else:
            # log.write('Unparseable input: {}\n\n'.format(key))
            return False
        # print(key, delta, actions)
        playerPos = self.findPlayer()
        playerCell = self.formatPos(playerPos)
        nextCell = self.formatPos(self.addVec(playerPos, delta))
        afterCell = self.formatPos(self.addVec(playerPos, delta, delta))
        # print(playerPos, playerCell, nextCell, afterCell)
        act = self.lookupAction(actions[0])
        gact = self.groundAction(act, [playerCell, nextCell])
        # print(gact)
        if self.tryAction(gact, log):
            return True
        else:
            act = self.lookupAction(actions[1])
            gact = self.groundAction(act, [playerCell, nextCell, afterCell])
            # print(gact)
            if self.tryAction(gact, log):
                return True
        # log.write('Blocked move: {}\n\n'.format(actions))
        return False

    tiles = {
        -1: '[]',  # Wall
        1: '  ',  # Floor
        3: '()',  # Boulder on floor
        5: '//',  # Goal on floor
        7: '{}',  # Goal and boulder on floor
        9: ':)',  # Player on floor
        13: '%)'
    }  # Goal and player on floor

    def render(self):
        w, h = 0, 0
        for cell in self.parser.objects['object']:
            x, y = self.parseCellName(cell)
            w = max(w, x + 1)
            h = max(h, y + 1)
        for y in range(h):
            for x in range(w):
                cell = self.formatPos((x, y))
                code = 0
                # print(cell)
                # print(self.state)
                if self.planner.applicable(self.state, [['wall', cell]], []):
                    code = -1
                else:
                    if self.planner.applicable(self.state, [['floor', cell]],
                                               []):
                        code = 1
                    if self.planner.applicable(self.state, [['ball', cell]],
                                               []):
                        code += 2
                    if self.planner.applicable(self.goal_pos, [['ball', cell]],
                                               []):
                        code += 4
                    if self.planner.applicable(self.state, [['player', cell]],
                                               []):
                        code += 8
                print(self.tiles[code], end='')
            print()

    def lispState(self, word=':state'):
        out = []
        out.append('({}'.format(word))
        for pred in self.state:
            out.append(' (')
            out.append(' '.join(pred))
            out.append(')')
        out.append(')')
        return ''.join(out)

    def gameloop(self):
        with open(self.logfile, 'w') as log:
            # log.write('{}\n\n'.format(datetime.datetime.now()))
            log.write('(trajectory\n\n')
            log.write('(:objects ')
            for t, os in self.parser.objects.items():
                for o in os:
                    log.write('{} -  {} '.format(o, t))
            log.write(')\n\n')
            log.write(self.lispState(':init'))
            log.write('\n\n')
            while True:
                self.render()
                if self.planner.applicable(self.state, self.goal_pos,
                                           self.goal_not):
                    print('Winningness!')
                    log.write(''.join(self.movelog))
                    log.write(')')
                    return
                prevTime = time.time()
                key = input('Choose direction (wasdur, followed by Enter): ')
                # log.write('{}\n\n'.format(time.time() - prevTime))
                self.doMove(key, log)
Exemplo n.º 23
0
class Domain():
    def __init__(self, domainfile, problemfile):
        self.parser_help = PDDL_Parser()
        self.parser_help.parse_domain(domainfile)
        self.parser_help.parse_problem(problemfile)
        self.domprob = DomainProblem(domainfile, problemfile)
        self.current_state = None  # State object
        self.pos_goal = None  # tuple of literals that need to be true at goal
        self.neg_goal = None  # tuple of literals that need to be false at goal
        self.action_dic = None  # list of actions
        self.objects = None  # list of world objects
        self.reversed_objects = None  # for type of object, list of instances
        self.parser()

    def parser(self):
        world_dic = self.domprob.worldobjects()
        # object list
        obj_dic = dict()
        for obj in world_dic.keys():
            wo = WorldObject(name=obj)
            wo.family = world_dic[obj]
            obj_dic[obj] = wo

        # reversed objects
        self.reversed_objects = defaultdict(list)
        for obj, typ in self.domprob.problem.objects.items():
            self.reversed_objects[typ].append(obj)
        for type, subtypes in self.parser_help.types.items(
        ):  # add reference to subtypes
            for sub in subtypes:
                self.reversed_objects[type] += self.reversed_objects[sub]

        # action list
        action_dic = dict()
        for op in self.domprob.operators():
            my_op = Action(name=op)
            action_dic[op] = my_op
        for op in action_dic.keys():
            operator = self.domprob.domain.operators[op]
            var_names = operator.variable_list.keys()
            var_types = operator.variable_list.values()
            var_combinations = itertools.product(
                *[self.reversed_objects[typ] for typ in var_types])
            for var_list in var_combinations:
                value = dict()
                # ground preconditions and effects
                value["preconditions_pos"] = {
                    prec.ground({
                        name: inst
                        for (name, inst) in zip(var_names, var_list)
                    })
                    for prec in operator.precondition_pos
                }
                value["preconditions_neg"] = {
                    prec.ground({
                        name: inst
                        for (name, inst) in zip(var_names, var_list)
                    })
                    for prec in operator.precondition_neg
                }
                value["effets_pos"] = {
                    prec.ground({
                        name: inst
                        for (name, inst) in zip(var_names, var_list)
                    })
                    for prec in operator.effect_pos
                }
                value["effets_neg"] = {
                    prec.ground({
                        name: inst
                        for (name, inst) in zip(var_names, var_list)
                    })
                    for prec in operator.effect_neg
                }
                action_dic[op].action_dic[tuple(var_list)] = value

                init_state_set = set()

        init_state = self.domprob.initialstate()
        init_state_set = set()
        for state in init_state:
            init_state_set.add(tuple(state.predicate))

        # goal
        self.pos_goal = set(self.parser_help.positive_goals)
        self.neg_goal = set(self.parser_help.negative_goals)

        ## Update ##
        self.current_state = State(true_predicates=init_state_set,
                                   pos_goal_state=self.pos_goal,
                                   neg_goal_state=self.neg_goal)
        self.action_dic = action_dic
        self.objects = obj_dic
Exemplo n.º 24
0
class Engine:

    # Params:
    #   domain: Name of domain file; should be 'soko3/soko3/pddl'
    #   problem: Name of problem file encoding the level to be played, e.g. soko3/levelp3.pddl
    #   logfile: Name of file the trajectory should be written to; defaults to /dev/null
    #   verbose: If true, will write restarts, undoes, and failed moves to the trajectory file
    def __init__(self, domain, problem, logfile='/dev/null', verbose=False):
        # Parser
        self.parser = PDDL_Parser()
        self.parser.parse_domain(domain)
        self.parser.parse_problem(problem)
        # Parsed data
        self.state = self.parser.state
        self.goal_pos = self.parser.positive_goals
        self.goal_not = self.parser.negative_goals

        self.history = []
        self.movelog = []

        self.logfile = logfile
        self.verbose = verbose

        self.planner = Planner()
        # Do nothing
        if self.planner.applicable(self.state, self.goal_pos, self.goal_not):
            print('Puzzle is already solved! Double-check your problem file!')

    def parseCellName(self, cellName):
        _, x, y = cellName.split('-')
        # print(cellName)
        # print(out)
        return int(x), int(y)

    def findPlayer(self):
        for pred in self.state:
            if pred[0] == 'at' and pred[1] == 'player-01':
                return self.parseCellName(pred[2])
        raise ValueError('Player not found!')

    def formatPos(self, coords):
        return 'pos-{:02}-{:02}'.format(coords[0], coords[1])

    def groundAction(self, act, assignment):
        variables = []
        for v, _ in act.parameters:
            variables.append(v)
        pps = act.replace(act.positive_preconditions, variables, assignment)
        nps = act.replace(act.negative_preconditions, variables, assignment)
        aes = act.replace(act.add_effects, variables, assignment)
        des = act.replace(act.del_effects, variables, assignment)
        return Action(act.name, assignment, pps, nps, aes, des)

    def addVec(self, *vecs):
        x = 0
        y = 0
        for u, v in vecs:
            x += u
            y += v
        return (x, y)

    # act must already be grounded (e.g. by self.groundAction)
    def tryAction(self, act, log):
        # print(self.state)
        # print(act.positive_preconditions)
        # print(act.negative_preconditions)
        # print(self.planner.applicable(self.state, act.positive_preconditions, act.negative_preconditions))
        if self.planner.applicable(self.state, act.positive_preconditions,
                                   act.negative_preconditions):
            success = True
            suffix = ''
        else:
            success = False
            suffix = '-failed'
        if success or self.verbose:
            # log.write(str(self.state) + '\n')
            # log.write(str(act))
            print('Action: {} {}'.format(act.name, act.parameters))
            try:
                act_str = '(:action{} ({}))'.format(
                    suffix, ' '.join([act.name, *act.parameters]))
                if success:
                    self.history.append(self.state)
                    self.state = self.planner.apply(self.state,
                                                    act.add_effects,
                                                    act.del_effects)
                # log.write(self.lispState() + '\n\n')
                self.movelog.append('{}\n\n{}\n\n'.format(
                    act_str, self.lispState()))
            except TypeError:
                # Tried to move or push a boulder off the grid or into a wall (in sokoban-sequential, those are the same thing).
                # This can only be a failed action, but trying to log it crashes this script (hence this try-except block), and would cause problems for trajectory.py down the line.
                # So, don't attempt to log this action.
                # This might come back to bite me later, but I'll cross that bridge when I get there.
                pass
        return success

    def lookupAction(self, actName):
        for act in self.parser.actions:
            if act.name == actName:
                return act
        return None

    # Finds the next cell adjacent to curCell in direction direc
    def findNextCell(self, curCell, direc):
        for cell in self.parser.objects['location']:
            if self.planner.applicable(self.state,
                                       [['move-dir', curCell, cell, direc]],
                                       []):
                return cell
        return None

    def getStone(self, cell):
        for stone in self.parser.objects['stone']:
            if self.planner.applicable(self.state, [['at', stone, cell]], []):
                return stone
        return None

    def doMove(self, key, log):
        direc = None
        if key == 'u':
            if len(self.history) >= 1:
                self.state = self.history.pop()
                if self.verbose:
                    self.movelog.append('(:undo)\n\n{}\n\n'.format(
                        self.lispState()))
                else:
                    self.movelog.pop()
            return True
        elif key == 'r':
            self.state = self.parser.state
            # self.history.append(self.state)
            self.history = [self.state]
            if self.verbose:
                self.movelog.append('(:restart)\n\n{}\n\n'.format(
                    self.lispState()))
            else:
                self.movelog = []
            return True
        elif key == 'w':
            direc = 'dir-up'
        elif key == 's':
            direc = 'dir-down'
        elif key == 'a':
            direc = 'dir-left'
        elif key == 'd':
            direc = 'dir-right'
        else:
            # log.write('Unparseable input: {}\n\n'.format(key))
            return False
        # print(key, delta, actions)
        playerPos = self.findPlayer()
        # print(key, currentCell)

        # Put player's cell, next cell, and cell after in a list
        cells = [self.formatPos(playerPos)]
        cells.append(self.findNextCell(cells[0], direc))
        cells.append(self.findNextCell(cells[1], direc))

        # Try move action
        assignment = ['player-01']
        assignment.extend(cells[0:2])
        assignment.append(direc)
        gact = self.groundAction(self.lookupAction('move'), assignment)
        if self.tryAction(gact, log):
            return True
        # If that failed, try push-to-nongoal
        assignment.insert(1, self.getStone(cells[1]))
        assignment.insert(4, cells[2])
        gact = self.groundAction(self.lookupAction('push-to-goal'), assignment)
        if self.tryAction(gact, log):
            return True
        # And if that failed, try push-to-goal
        gact = self.groundAction(self.lookupAction('push-to-nongoal'),
                                 assignment)
        if self.tryAction(gact, log):
            return True
        return False

        # for act in self.parser.actions:
        #     currentCell = self.formatPos(playerPos)
        #     assignment = [key]
        #     while len(assignment) < len(act.parameters):
        #         assignment.append(currentCell)
        #         currentCell = self.findNextCell(currentCell, key)    # Having to do this for every cell parameter in every action is inefficient; maybe improve later?
        #     gact = self.groundAction(act, assignment)
        #     # print(gact)
        #     if self.tryAction(gact, log):
        #         return True
        # return False

        # nextCell = self.formatPos(self.addVec(playerPos, delta))
        # afterCell = self.formatPos(self.addVec(playerPos, delta, delta))
        # # print(playerPos, playerCell, nextCell, afterCell)
        # act = self.lookupAction(actions[0])
        # gact = self.groundAction(act, [playerCell, nextCell])
        # # print(gact)
        # if self.tryAction(gact, log):
        #     return True
        # else:
        #     act = self.lookupAction(actions[1])
        #     gact = self.groundAction(act, [playerCell, nextCell, afterCell])
        #     # print(gact)
        #     if self.tryAction(gact, log):
        #         return True
        # # log.write('Blocked move: {}\n\n'.format(actions))
        # return False

    predIDs = {'wall': 1, 'player': 2, 'ball': 4, 'pit': 8, 'goal': 16}

    tiles = {
        0: '  ',  # Floor
        1: '[]',  # Wall
        2: ':)',  # Player
        4: '()',  # Boulder
        8: '\/',  # Pit
        16: '//',  # Goal
        18: '%)',  # Goal and player
        20: '{}'
    }  # Goal and boulder

    nonwalls = set()

    def findNonWalls(self):
        for pred in self.state:
            # print('Checking {}'.format(pred))
            if pred[0] == 'move-dir':
                self.nonwalls.add(pred[1])
                self.nonwalls.add(pred[2])

    def renderCell(self, cell):
        if cell not in self.nonwalls:
            return '[]'
        elif self.formatPos(self.findPlayer()) == cell:
            if self.planner.applicable(self.state, [['is-goal', cell]], []):
                return '%)'
            else:
                return ':)'
        elif self.getStone(cell) is not None:
            if self.planner.applicable(self.state, [['is-goal', cell]], []):
                return '{}'
            else:
                return '()'
        else:
            if self.planner.applicable(self.state, [['is-goal', cell]], []):
                return '//'
            else:
                return '  '

    def render(self):
        w, h = 0, 0
        for cell in self.parser.objects['location']:
            x, y = self.parseCellName(cell)
            w = max(w, x + 1)
            h = max(h, y + 1)
        for y in range(1, h):
            for x in range(1, w):
                cell = self.formatPos((x, y))
                # code = 0
                # # print(cell)
                # # print(self.state)
                # for pred, pid in self.predIDs.items():
                #     if self.planner.applicable(self.state, [[pred, cell]], []):
                #         code += pid
                # if self.planner.applicable(self.goal_pos, [['ball', cell]], []):
                #     code += self.predIDs['goal']
                print(self.renderCell(cell), end='')
                # if self.planner.applicable(self.state, [['wall', cell]], []):
                #     code = -1
                # else:
                #     if self.planner.applicable(self.state, [['floor', cell]], []):
                #         code = 1
                #     if self.planner.applicable(self.state, [['ball', cell]], []):
                #         code += 2
                #     if self.planner.applicable(self.goal_pos, [['ball', cell]], []):
                #         code += 4
                #     if self.planner.applicable(self.state, [['player', cell]], []):
                #         code += 8
            print()

    def lispState(self, word=':state'):
        out = []
        out.append('({}'.format(word))
        for pred in self.state:
            out.append(' (')
            out.append(' '.join(pred))
            out.append(')')
        out.append(')')
        return ''.join(out)

    def gameloop(self):
        with open(self.logfile, 'w') as log:
            # log.write('{}\n\n'.format(datetime.datetime.now()))
            log.write('(trajectory\n\n')
            log.write('(:objects ')
            for t, os in self.parser.objects.items():
                for o in os:
                    log.write('{} -  {} '.format(o, t))
            log.write(')\n\n')
            log.write(self.lispState(':init'))
            log.write('\n\n')
            self.findNonWalls()
            while True:
                self.render()
                if self.planner.applicable(self.state, self.goal_pos,
                                           self.goal_not):
                    print('Winningness!')
                    log.write(''.join(self.movelog))
                    log.write(')')
                    return
                prevTime = time.time()
                key = input('Choose direction (wasdur, followed by Enter): ')
                # log.write('{}\n\n'.format(time.time() - prevTime))
                self.doMove(key, log)
Exemplo n.º 25
0
class Engine:
    def __init__(self, domain, problem, logfile='/dev/null'):
        # Parser
        self.parser = PDDL_Parser()
        self.parser.parse_domain(domain)
        self.parser.parse_problem(problem)
        # Parsed data
        self.state = self.parser.state
        self.goal_pos = self.parser.positive_goals
        self.goal_not = self.parser.negative_goals

        self.history = []
        self.movelog = []

        self.logfile = logfile

        self.planner = Planner()
        # Do nothing
        if self.planner.applicable(self.state, self.goal_pos, self.goal_not):
            print('Puzzle is already solved! Double-check your problem file!')

    def parseCellName(self, cellName):
        x, y = cellName[4:].split('_')
        # print(cellName)
        # print(out)
        return int(x), int(y)

    def findPlayer(self):
        for pred in self.state:
            if pred[0] == 'player':
                return self.parseCellName(pred[1])
        raise ValueError('Player not found!')

    def formatPos(self, coords):
        return 'cell{}_{}'.format(coords[0], coords[1])

    def groundAction(self, act, assignment):
        variables = []
        for v, _ in act.parameters:
            variables.append(v)
        pps = act.replace(act.positive_preconditions, variables, assignment)
        nps = act.replace(act.negative_preconditions, variables, assignment)
        aes = act.replace(act.add_effects, variables, assignment)
        des = act.replace(act.del_effects, variables, assignment)
        return Action(act.name, assignment, pps, nps, aes, des)

    def addVec(self, *vecs):
        x = 0
        y = 0
        for u, v in vecs:
            x += u
            y += v
        return (x, y)

    # act must already be grounded (e.g. by self.groundAction)
    def tryAction(self, act, log):
        # print(self.state)
        # print(act.positive_preconditions)
        # print(act.negative_preconditions)
        # print(self.planner.applicable(self.state, act.positive_preconditions, act.negative_preconditions))
        if self.planner.applicable(self.state, act.positive_preconditions,
                                   act.negative_preconditions):
            # log.write(str(self.state) + '\n')
            # log.write(str(act))
            act_str = '(:action ({}))'.format(' '.join(
                [act.name, *act.parameters]))
            self.history.append(self.state)
            self.state = self.planner.apply(self.state, act.add_effects,
                                            act.del_effects)
            # log.write(self.lispState() + '\n\n')
            self.movelog.append('{}\n\n{}\n\n'.format(act_str,
                                                      self.lispState()))
            return True
        else:
            return False

    def lookupAction(self, actName):
        for act in self.parser.actions:
            if act.name == actName:
                return act
        return None

    # Finds the next cell adjacent to curCell in direction direc
    def findNextCell(self, curCell, direc):
        for cell in self.parser.objects['cell']:
            if self.planner.applicable(self.state,
                                       [['in-dir', direc, curCell, cell]], []):
                return cell
        return None

    def doMove(self, key, log):
        if key == 'u':
            if len(self.history) >= 1:
                self.state = self.history.pop()
                self.movelog.pop()
            return True
        elif key == 'r':
            self.state = self.parser.state
            # self.history.append(self.state)
            self.history = [self.state]
            self.movelog = []
            return True
        # else:
        #     # log.write('Unparseable input: {}\n\n'.format(key))
        #     return False
        # print(key, delta, actions)
        playerPos = self.findPlayer()
        # print(key, currentCell)
        for act in self.parser.actions:
            currentCell = self.formatPos(playerPos)
            assignment = [key]
            while len(assignment) < len(act.parameters):
                assignment.append(currentCell)
                currentCell = self.findNextCell(
                    currentCell, key
                )  # Having to do this for every cell parameter in every action is inefficient; maybe improve later?
            gact = self.groundAction(act, assignment)
            # print(gact)
            if self.tryAction(gact, log):
                return True
        return False

        # nextCell = self.formatPos(self.addVec(playerPos, delta))
        # afterCell = self.formatPos(self.addVec(playerPos, delta, delta))
        # # print(playerPos, playerCell, nextCell, afterCell)
        # act = self.lookupAction(actions[0])
        # gact = self.groundAction(act, [playerCell, nextCell])
        # # print(gact)
        # if self.tryAction(gact, log):
        #     return True
        # else:
        #     act = self.lookupAction(actions[1])
        #     gact = self.groundAction(act, [playerCell, nextCell, afterCell])
        #     # print(gact)
        #     if self.tryAction(gact, log):
        #         return True
        # # log.write('Blocked move: {}\n\n'.format(actions))
        # return False

    predIDs = {'wall': 1, 'player': 2, 'ball': 4, 'pit': 8, 'goal': 16}

    tiles = {
        0: '  ',  # Floor
        1: '[]',  # Wall
        2: ':)',  # Player
        4: '()',  # Boulder
        8: '\/',  # Pit
        16: '//',  # Goal
        18: '%)',  # Goal and player
        20: '{}'
    }  # Goal and boulder

    def render(self):
        w, h = 0, 0
        for cell in self.parser.objects['cell']:
            x, y = self.parseCellName(cell)
            w = max(w, x + 1)
            h = max(h, y + 1)
        for y in range(h):
            for x in range(w):
                cell = self.formatPos((x, y))
                code = 0
                # print(cell)
                # print(self.state)
                for pred, pid in self.predIDs.items():
                    if self.planner.applicable(self.state, [[pred, cell]], []):
                        code += pid
                if self.planner.applicable(self.goal_pos, [['ball', cell]],
                                           []):
                    code += self.predIDs['goal']
                print(self.tiles[code], end='')
                # if self.planner.applicable(self.state, [['wall', cell]], []):
                #     code = -1
                # else:
                #     if self.planner.applicable(self.state, [['floor', cell]], []):
                #         code = 1
                #     if self.planner.applicable(self.state, [['ball', cell]], []):
                #         code += 2
                #     if self.planner.applicable(self.goal_pos, [['ball', cell]], []):
                #         code += 4
                #     if self.planner.applicable(self.state, [['player', cell]], []):
                #         code += 8
            print()

    def lispState(self, word=':state'):
        out = []
        out.append('({}'.format(word))
        for pred in self.state:
            out.append(' (')
            out.append(' '.join(pred))
            out.append(')')
        out.append(')')
        return ''.join(out)

    def gameloop(self):
        with open(self.logfile, 'w') as log:
            # log.write('{}\n\n'.format(datetime.datetime.now()))
            log.write('(trajectory\n\n')
            log.write('(:objects ')
            for t, os in self.parser.objects.items():
                for o in os:
                    log.write('{} -  {} '.format(o, t))
            log.write(')\n\n')
            log.write(self.lispState(':init'))
            log.write('\n\n')
            while True:
                self.render()
                if self.planner.applicable(self.state, self.goal_pos,
                                           self.goal_not):
                    print('Winningness!')
                    log.write(''.join(self.movelog))
                    log.write(')')
                    return
                prevTime = time.time()
                key = input(
                    'Choose direction ({}ur, followed by Enter): '.format(
                        ''.join(self.parser.objects['dir'])))
                # log.write('{}\n\n'.format(time.time() - prevTime))
                self.doMove(key, log)
Exemplo n.º 26
0
class trajectory:
    def parseObjects(self, objTokens):
        self.types2objs = {
        }  # Map of types -> objects; useful when you need to know what objects have a specified type
        self.objs2types = {
        }  # Map of objects -> types; useful when you want to know what the type of a specific object is
        objs = []
        isType = False
        for token in objTokens[
                1:]:  # Throw out objTokens[0], which will be the string ':objects'
            if isType:
                if token not in self.types2objs:
                    self.types2objs[token] = []
                self.types2objs[token].extend(objs)
                for obj in objs:
                    self.objs2types[obj] = token
                objs = []
                isType = False
            elif token == '-':
                isType = True
            else:
                objs.append(token)

    # Parses the :init and :state blocks in the trajectory file, and also makes a dictionary of all the predicates that appear in the states, along with the types of their peremeters
    def parseStates(self, tokens):
        self.states = []
        self.predicates = {}
        for block in tokens:
            if block[0] == ':state' or block[0] == ':init':
                self.states.append(block[1:])
                for pred in block[1:]:
                    pName = pred[0]
                    pTypes = []
                    for arg in pred[1:]:
                        pTypes.append(
                            [self.objs2types[arg]]
                        )  # Predicate type lists are now lists of lists of strings- each inner list representing the types observed for one parameter
                    if pName in self.predicates:
                        for oldParamTypes, newType in zip(
                                self.predicates[pName], pTypes):
                            if newType[0] not in oldParamTypes:
                                oldParamTypes.append(newType[0])
                        # if self.predicates[pName] != pTypes:
                        # raise TypeError('Predicate {} believed to have parameter types {}; inconsistent with observed parameters {}'.format(pName, self.predicates[pName], pTypes))
                    else:
                        self.predicates[pName] = pTypes

    def parseActions(self, tokens):
        self.actions = {}
        for block in tokens:
            if block[0] == ':action':
                act_in = block[1]
                # print('Parsing action {}'.format(act_in))
                parTypes = []
                for param in act_in[1:]:
                    parTypes.append(
                        self.objs2types[param]
                    )  # Not doing list-of-lists here- that'll be handled in actionCandidate constructor
                if act_in[0] in self.actions:
                    # print ('Found action with same name: {}'.format(act_in[0]))
                    for oldTypes, newType in zip(
                            self.actions[act_in[0]].parameterTypes, parTypes):
                        if newType not in oldTypes:
                            oldTypes.append(newType)
                    self.actions[act_in[0]].updateParameterTypes(parTypes)
                    # if act.parameterTypes != parTypes:
                    #     raise TypeError('Action {} found using parameters {}; inconsistent with earlier {}. Are you using type inheritance?'.format(act_in[0], parTypes, act.parameterTypes))
                else:
                    newAct = actionCandidate(act_in[0], parTypes, self)
                    self.actions[newAct.name] = newAct

    def refineActions(self, tokens):
        assignments = [((n - 1) // 2 - 1, block[1])
                       for (n, block) in enumerate(tokens)
                       if block[0] == ':action']
        # pprint.pprint(assignments)
        for i, agmt in assignments:
            assignedTypes = [self.objs2types[par] for par in agmt[1:]]
            self.actions[agmt[0]].updateParameterTypes(assignedTypes)
        for act in self.actions.values():
            act.createPrecons(self)
        needsDoubleChecking = False
        for i, agmt in assignments:
            # print('State {}: {}'.format(i, self.states[i]))
            # print('Action {}: {}'.format(i, agmt))
            # print('State {}: {}'.format(i+1, self.states[i+1]))
            # print()
            act = self.actions[agmt[0]]
            assignment = agmt[1:]
            # assignedTypes = [self.objs2types[par] for par in assignment]
            act.prunePrecons(self.states[i], assignment)
            needsDoubleChecking |= act.updateEffects(self.states[i],
                                                     assignment,
                                                     self.states[i + 1])
        if needsDoubleChecking:
            # print('Double-checking action effects\n')
            needsDoubleChecking = False
            for i, agmt in assignments:
                act = self.actions[agmt[0]]
                assignment = agmt[1:]
                # assignedTypes = [self.objs2types[par] for par in assignment]
                needsDoubleChecking |= act.updateEffects(
                    self.states[i], assignment, self.states[i + 1])
            if needsDoubleChecking:
                raise ValueError(
                    "Some actions still had unexpected effects during the second pass. This shouldn't be possible. If you see this message, please let me know. --SE"
                )

    def genTypeclasses(self):  #TODO Add code to deal with deeper hierarchies
        classList = []
        for typesOuter in self.predicates.values():
            for types in typesOuter:
                # print(types)
                sorTypes = list(sorted(types))
                if sorTypes not in classList:
                    classList.append(sorTypes)
        for act in self.actions:
            for types in self.actions[act].parameterTypes:
                sorTypes = list(sorted(types))
                if sorTypes not in classList:
                    classList.append(sorTypes)
        # print(classList)
        self.typeclasses = {}
        for tclass in classList:
            self.typeclasses['_'.join(tclass)] = 'object'
        for typ in self.types2objs.keys():
            container = 'object'
            for tclass in classList:
                if typ in tclass and typ != '_'.join(tclass):
                    container = '_'.join(tclass)
            self.typeclasses[typ] = container

    def __init__(self, filename, domainName='reconstructed'):
        self.domainName = domainName
        self.parser = PDDL_Parser()
        self.tokens = self.parser.scan_tokens(filename)
        pprint.pprint(self.tokens)
        print('=== Objects ===')
        self.parseObjects(self.tokens[1])
        pprint.pprint(self.types2objs)
        print('=== States ===')
        self.parseStates(self.tokens)
        pprint.pprint(self.states)
        print('=== Predicates ===')
        pprint.pprint(self.predicates)
        print('=== Actions ===')
        self.parseActions(self.tokens)
        # print(self.tokens[3])
        # p, n = self.actions[0].assignPrecons(self.tokens[3][1][1:])
        # print('Grounded Positive preconditions')
        # print(p)
        # print('Grounded Negative preconditions')
        # print(n)
        # print('Before State')
        # print(self.states[0])
        # self.actions[0].prunePrecons(self.states[0], self.tokens[3][1][1:])
        # print(self.actions[0])
        self.refineActions(self.tokens)
        pprint.pprint(self.actions)
        self.genTypeclasses()

    def __repr__(self):
        fmtTypeclasses = [
            '{} - {}'.format(k, v) for k, v in self.typeclasses.items()
        ]
        fmtPredicates = []
        for name, types in self.predicates.items():
            fmtParams = [name]
            for i, typ in enumerate(types):
                fmtParams.append('?{} - {}'.format(i, '_'.join(typ)))
            fmtPredicates.append('({})'.format(' '.join(fmtParams)))
        fmtActions = [str(act) for act in self.actions.values()]
        return '''(define (domain {})
(:requirements :typing :negative-preconditions)
(:types {})
(:predicates {})
{})
'''.format(self.domainName, ' '.join(fmtTypeclasses), ' '.join(fmtPredicates),
           ''.join(fmtActions))