Esempio n. 1
0
 def goal_test(self, state):
     """Return True if the state is a goal. The default method compares the
     state to self.goal, as specified in the constructor. Override this
     method if checking against a single self.goal is not enough."""
     new_wh1 = sokoban.Warehouse()
     new_wh1.extract_locations(state.split(sep="\n"))
     new_wh2 = sokoban.Warehouse()
     new_wh2.extract_locations(self.goal.split(sep="\n"))
     return set(new_wh1.boxes) == set(new_wh2.targets)
 def h(n):
     # Perform a manhattan distance heuristic
     state = n.state[1]
     wh = sokoban.Warehouse()
     wh.extract_locations(state.split('\n'))
     num_targets = len(wh.targets)
     heuristic = 0
     test = 1
     for box in wh.boxes:
         # dist = 0
         # for target in wh.targets:
         #     dist+= manhattan_distance(box, target)
         # heuristic += (dist/num_targets)
         if test == 1:
             dist = 0
             for target in wh.targets:
                 dist += manhattan_distance(box, target)
             heuristic += 0.8 * (dist /
                                 num_targets) + 0.5 * manhattan_distance(
                                     warehouse.worker, box)
         else:
             dist1 = []
             for target in wh.targets:
                 dist1.append(manhattan_distance(box, target))
             heuristic += 0.8 * min(dist1) + 0.5 * manhattan_distance(
                 warehouse.worker, box)
     return heuristic
Esempio n. 3
0
    def heuristic(node):
        # Using Manhattan Distance for heuristics
        nodeState = node.state

        warehouseFromNode = sokoban.Warehouse()
        warehouseFromNode.extract_locations(nodeState)

        warehouseTargets = warehouseFromNode.targets
        warehouseTargetsCount = len(warehouseTargets)
        warehouseBoxes = warehouseFromNode.boxes
        warehouseWorker = warehouseFromNode.worker
        heuristicValue = 0

        for warehouseBox in warehouseBoxes:
            totalBoxDistance = 0

            aSquared = abs(warehouseBox[0] - warehouseWorker[0])
            bSquared = abs(warehouseBox[1] - warehouseWorker[1])
            workerDistanceToBox = (aSquared + bSquared)**0.5

            for warehouseTarget in warehouseTargets:
                aSquared = abs(warehouseBox[0] - warehouseTarget[0])
                bSquared = abs(warehouseBox[1] - warehouseTarget[1])

                manhattanDistanceSingleBox = (aSquared + bSquared)**0.5
                totalBoxDistance += manhattanDistanceSingleBox

            heuristicValue += (totalBoxDistance /
                               warehouseTargetsCount) * workerDistanceToBox

        return heuristicValue
    def result(self, state, action):

        warehouse = sokoban.Warehouse()
        warehouse.extract_locations(state.splitlines())

        box_position = action[0]
        action = action[1]

        box_id = warehouse.boxes.index(box_position)
        warehouse.boxes.remove(box_position)
        if action == 'Right':
            move = movement[0]
            new_box_position = (box_position[0] + move[0],
                                box_position[1] + move[1])

        if action == "Left":
            move = movement[1]
            new_box_position = (box_position[0] + move[0],
                                box_position[1] + move[1])

        if action == 'Down':
            move = movement[2]
            new_box_position = (box_position[0] + move[0],
                                box_position[1] + move[1])

        if action == 'Up':
            move = movement[3]
            new_box_position = (box_position[0] + move[0],
                                box_position[1] + move[1])

        warehouse.worker = box_position

        warehouse.boxes.insert(box_id, new_box_position)
        # print(str(warehouse))
        return str(warehouse)
 def actions(self, state):
     """
     Return the list of actions that can be executed in the given state.
     
     As specified in the header comment of this class, the attributes
     'self.allow_taboo_push' and 'self.macro' should be tested to determine
     what type of list of actions is to be returned.
     """
     warehouse = sokoban.Warehouse()
     warehouse.extract_locations(state.splitlines())
     # print(warehouse)
     # print(state)
     taboo = set(
         sokoban.find_2D_iterator(
             taboo_cells(str(warehouse)).splitlines(), "X"))
     for box in warehouse.boxes:
         for move in movement:
             worker_position = (box[0] - move[0], box[1] - move[1])
             box_after_pushed = (box[0] + move[0], box[1] + move[1])
             # print(taboo)
             if (can_go_there(warehouse, worker_position)
                     and box_after_pushed not in taboo
                     and box_after_pushed not in warehouse.walls
                     and box_after_pushed not in warehouse.boxes):
                 yield (box, direction(move))
Esempio n. 6
0
    def result(self, state, action):
        # NO TESTING - YOU ALREADY KNOW THAT THIS IS A VALID MOVE!!!
        stateArray = state.split('\n')
        warehouseObject = sokoban.Warehouse()
        warehouseObject.extract_locations(stateArray)
        workerPos = warehouseObject.worker

        # These are in (y, x) format
        moveLeft = ((-1, 0), 'Left')
        moveRight = ((1, 0), 'Right')
        moveUp = ((0, -1), 'Up')
        moveDown = ((0, 1), 'Down')
        possibleMoves = [moveLeft, moveRight, moveUp, moveDown]
        if type(action) == tuple:
            actionString = action[1]
            moveFrom = action[0][1], action[0][0]
        else:
            actionString = action
        for movePair in possibleMoves:
            if movePair[1] == actionString:
                move = movePair[0]
                break

        # if marco true - action = [ ((3,4), 'Left'), ((5,2), 'Right')]
        if self.macro:
            boxArrayPosition = warehouseObject.boxes.index(moveFrom)
            newBoxPosition = moveFrom[0] + move[0], moveFrom[1] + move[1]
            warehouseObject.boxes[boxArrayPosition] = newBoxPosition
            warehouseObject.worker = moveFrom
            return str(warehouseObject)

        # if marco false - action = [ 'Left', 'Right' ]
        else:
            newWorkerPosition = workerPos[0] + move[0], workerPos[1] + move[1]
            testPos = stateArray[newWorkerPosition[1]][newWorkerPosition[0]]
            if testPos == ' ' or testPos == '.':
                # nothing more to do, just update state with worker = testPos
                warehouseObject.worker = newWorkerPosition
                return str(warehouseObject)
            elif testPos == '$' or testPos == '*':
                # need to shift box before moving worker to this location
                assert newWorkerPosition in warehouseObject.boxes
                boxArrayPosition = warehouseObject.boxes.index(
                    newWorkerPosition)
                newBoxPosition = newWorkerPosition[0] + move[
                    0], newWorkerPosition[1] + move[1]
                warehouseObject.boxes[boxArrayPosition] = newBoxPosition
                warehouseObject.worker = newWorkerPosition[
                    0], newWorkerPosition[1]
                return str(warehouseObject)

        # The code should never EVER get here!
        print("STOP!!!!!!, you should never see this...")
        print(
            "The possible actions failed to correctly find the actions available"
        )
        assert False
Esempio n. 7
0
def warehouse_deepcopy(warehouse):
    result = sokoban.Warehouse()
    result.worker = (warehouse.worker[0], warehouse.worker[1])

    boxesInternal = []
    for i in warehouse.boxes:
        boxesInternal.append((i[0], i[1]))

    result.boxes = boxesInternal
    result.targets = warehouse.targets
    result.walls = warehouse.walls
    return result
Esempio n. 8
0
    def h(self, n):
        heur = 0
        new_wh = sokoban.Warehouse()
        new_wh.extract_locations(n.state.split(sep="\n"))
        for box in new_wh.boxes:
            temp_target = new_wh.targets[0]
            for target in new_wh.targets:
                if (manhattan_distance(target, box) < manhattan_distance(
                        temp_target, box)):
                    temp_target = target
            heur = heur + manhattan_distance(temp_target, box)

        return heur
    def h(self, n):

        h = 0
        wh = sokoban.Warehouse()
        self.initial_box

        # print(wh.boxes)
        for target in self.targets:
            for box in self.initial_box:
                # print(box)
                ith_box = self.initial_box.index(box)
                h = (manhattan_distance(box, target) * push_cost[ith_box]) + h
        return h
    def actions(self, state):

        warehouse = sokoban.Warehouse()
        warehouse.extract_locations(state.splitlines())
        taboo = set(sokoban.find_2D_iterator(taboo_cells(str(warehouse)), "X"))
        for box in warehouse.boxes:
            for move in movement:
                worker_position = (box[0] - move[0], box[1] - move[1])
                box_after_pushed = (box[0] + move[0], box[1] + move[1])

                if (can_go_there(warehouse, worker_position)
                        and box_after_pushed not in taboo
                        and box_after_pushed not in warehouse.walls
                        and box_after_pushed not in warehouse.boxes):
                    yield (box, direction(move))
    def h(self, n):
        # print(node)
        # print(' ')
        # print(self.initial)
        h = 0

        wh = sokoban.Warehouse()
        wh.extract_locations(n.state.splitlines())
        # print(wh.boxes)
        # print(wh.boxes)
        # print(n.state)
        for target in wh.targets:
            for box in wh.boxes:
                # print(box)
                h = manhattan_distance(box, target) + h
        return h
    def __init__(self, initial, goal, push_cost):

        self.initial = initial
        self.goal = goal.replace('@', ' ')
        self.push_cost = push_cost
        wh = sokoban.Warehouse()
        wh.extract_locations(initial.splitlines())
        self.initial_box = wh.boxes
        self.targets = wh.targets
        self.coll = {
            'Left': (-1, 0),
            'Right': (1, 0),
            'Up': (0, -1),
            'Down': (0, 1)
        }
        self.box_push_cost = 0
 def result(self, state, action):
     # Extract the warehouse from the current state.
     current_warehouse = sokoban.Warehouse()
     current_warehouse.extract_locations(state[1].split(sep="\n"))
     box = action[0]
     if box in current_warehouse.boxes:
         # Remove the old box, set the worker to the position, and add the
         # new box position. This moves the box with the worker.
         offset = direction_to_offset(action[1])
         current_warehouse.worker = box
         current_warehouse.boxes.remove(box)
         current_warehouse.boxes.append(add_tuples(box, offset))
         return action, str(current_warehouse)
     else:
         # If the box isn't in the warehouse, something went very wrong.
         print(str(current_warehouse))
         print(box)
         print(current_warehouse.boxes)
         raise ValueError("Box not in warehouse!")
Esempio n. 14
0
 def path_cost(self, c, state1, action, state2):
     """Return the cost of a solution path that arrives at state2 from
     state1 via action, assuming cost c to get up to state1. If the problem
     is such that the path doesn't matter, this function will only look at
     state2.  If the path does matter, it will consider c and maybe state1
     and action. The default method costs 1 for every step in the path."""
     new_wh2 = sokoban.Warehouse()
     new_wh2.extract_locations(state2.split(sep="\n"))
     if self.push_costs == None:
         return c + 1
     else:
         for i in range(len(self.ListofLocation)):
             if self.ListofLocation[i] not in new_wh2.boxes:
                 push_cost = self.push_costs[i]
                 for box in new_wh2.boxes:
                     if box not in self.ListofLocation:
                         self.ListofLocation[i] = box
                         return c + push_cost
         return c + 1
    def actions(self, state):
        """
        Returns the list of actions that can be executed in the given state.
        """

        #Warehouse current state
        the_warehouse = sokoban.Warehouse()
        #Positional information of boxes, worker, targets and walls extracted
        the_warehouse.extract_locations(state[1].split(sep="\n"))
        #If allow_taboo_push is True, return all legal moves including the box on a taboo cell
        if self.allow_taboo_push:
            #Find bad cell spots
            is_cell_taboo = set(
                find_2D_iterator(taboo_cells(the_warehouse), "X"))
            #find directions for the box
            for box in the_warehouse.boxes:
                for offset in worker_offsets:
                    offset = offset_of_direction(offset)
                    b_position = add_coordinates(box, offset)
                    ppos1 = (box[0] + offset[0] * -1)
                    ppos0 = (box[1] + offset[1] * -1)
                    p_position = (ppos1, ppos0)
                    p_position = flip_coordinates(p_position)
                    if can_go_there(the_warehouse, p_position):
                        if b_position not in is_cell_taboo:
                            if b_position not in the_warehouse.boxes:
                                if b_position not in the_warehouse.walls:
                                    yield (box, direction_of_offset(offset))

        #if allow_taboo_push is False, taboo and shouldn't be included in list of moves.
        elif not self.allow_taboo_push:
            #find directions for the box
            for box in the_warehouse.boxes:
                for offset in worker_offsets:
                    b_position = add_coordinates(box, offset)
                    p_position = flip_coordinates((box[0] + offset[0] * -1),
                                                  (box[1] + offset[1] * -1))
                    if can_go_there(the_warehouse, p_position):
                        if b_position not in the_warehouse.boxes:
                            if b_position not in the_warehouse.walls:
                                yield (box, direction_of_offset(offset))
    def result(self, state, move):
        '''
        Move is the direction of the object moved by the worker
        '''
        #Warehouse current state
        the_warehouse = sokoban.Warehouse()
        #Positional information of boxes, worker, targets and walls extracted
        the_warehouse.extract_locations(state[1].split(sep="\n"))
        #remove the box from its old position, set it to the character's offset direction
        #set the boxes' old position to the worker
        position = move[0]

        if position in the_warehouse.boxes:

            the_warehouse.worker = position
            the_warehouse.boxes.remove(position)
            offset_position = offset_of_direction(move[1])
            the_warehouse.boxes.append(
                add_coordinates(position, offset_position))
            return move, str(the_warehouse)
        else:
            raise ValueError("Box is outside the Warehouse")
    def actions(self, state):
        # Extract the warehouse from the current state.
        current_warehouse = sokoban.Warehouse()
        current_warehouse.extract_locations(state[1].split(sep="\n"))
        global bad_cells

        if bad_cells is None:
            # If taboo cells haven't been computed, compute them.
            # This is done once for optimisation purposes.
            bad_cells = set(
                find_2D_iterator(
                    taboo_cells(current_warehouse).split("\n"), "X"))

        # Find every box, and every direction it can be pushed.
        for box in current_warehouse.boxes:
            for offset in offset_states:
                player_position = flip_tuple(
                    (box[0] + (offset[0] * -1), box[1] + (offset[1] * -1)))
                new_box_position = add_tuples(box, offset)
                if can_go_there(current_warehouse, player_position) \
                        and new_box_position not in bad_cells \
                        and new_box_position not in current_warehouse.walls \
                        and new_box_position not in current_warehouse.boxes:
                    yield (box, offset_to_direction(offset))
Esempio n. 18
0
def main():
    wh = sokoban.Warehouse()
    wh.load_warehouse("./warehouses/warehouse_57.txt")
    solve_sokoban_elem(wh)
    solve_sokoban_macro(wh)
Esempio n. 19
0
    def actions(self, state):
        """
        Return the list of actions that can be executed in the given state.
        
        As specified in the header comment of this class, the attributes
        'self.allow_taboo_push' and 'self.macro' should be tested to determine
        what type of list of actions is to be returned.
        """
        # These are in (y, x) format
        moveLeft = (-1, 0)
        moveRight = (1, 0)
        moveUp = (0, -1)
        moveDown = (0, 1)
        possibleMoves = [moveLeft, moveRight, moveUp, moveDown]

        nodeAsString = state.split('\n')
        warehouseObject = sokoban.Warehouse()
        warehouseObject.extract_locations(nodeAsString)
        justTabooCells = taboo_cells(warehouseObject)
        tabooCells = list(sokoban.find_2D_iterator(justTabooCells.split('\n'), 'X')) \
            if not self.allow_taboo_push else []

        currentWalls = warehouseObject.walls
        currentBoxes = warehouseObject.boxes
        currentWorker = warehouseObject.worker

        if self.macro:
            for box in currentBoxes:
                for move in possibleMoves:
                    testNewBoxPosition = box[0] + move[0], box[1] + move[1]
                    # Need to reverse the tuple to be in a (x,y) format
                    testNewPlayerPosition = box[1] + (move[1] * -1), box[0] + (
                        move[0] * -1)
                    canIGetThere = can_go_there(warehouseObject,
                                                testNewPlayerPosition)

                    if canIGetThere and testNewBoxPosition not in currentWalls \
                            and testNewBoxPosition not in currentBoxes \
                            and testNewBoxPosition not in tabooCells:
                        revBox = box[1], box[0]
                        if move == moveLeft:
                            yield (revBox, "Left")
                        elif move == moveRight:
                            yield (revBox, "Right")
                        elif move == moveUp:
                            yield (revBox, "Up")
                        elif move == moveDown:
                            yield (revBox, "Down")
        else:
            for move in possibleMoves:
                # Need to reverse the tuple to be in a (x,y) format
                testNewPlayerPosition = currentWorker[0] + move[
                    0], currentWorker[1] + move[1]
                if testNewPlayerPosition not in currentWalls:
                    if testNewPlayerPosition not in currentBoxes:
                        if move == moveLeft:
                            yield ("Left")
                        elif move == moveRight:
                            yield ("Right")
                        elif move == moveUp:
                            yield ("Up")
                        elif move == moveDown:
                            yield ("Down")
                    else:
                        # If there is a box in the way, make sure the box can legally be moved
                        newBoxPosition = testNewPlayerPosition[0] + move[
                            0], testNewPlayerPosition[1] + move[1]
                        if newBoxPosition not in currentWalls and \
                                newBoxPosition not in currentBoxes and \
                                newBoxPosition not in tabooCells:
                            if move == moveLeft:
                                yield ("Left")
                            elif move == moveRight:
                                yield ("Right")
                            elif move == moveUp:
                                yield ("Up")
                            elif move == moveDown:
                                yield ("Down")
        wh = sokoban.Warehouse()
        self.initial_box

        # print(wh.boxes)
        for target in self.targets:
            for box in self.initial_box:
                # print(box)
                ith_box = self.initial_box.index(box)
                h = (manhattan_distance(box, target) * push_cost[ith_box]) + h
        return h

    def value(self, state):
        return 1


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

if __name__ == '__main__':
    puzzle_t3 = '''
    #######
    #@ $ .#
    #. $  #
    #######'''
    problem_file = "./warehouses/warehouse_03_impossible.txt"
    wh = sokoban.Warehouse()
    wh.load_warehouse(problem_file)
    push_cost = [1, 10]
    # wh.extract_locations(puzzle_t1.split(sep='\n'))
    print('\nElementary solution')
    answer = solve_sokoban_elem(wh)
    print(answer)