Beispiel #1
0
def plan(domain, problem, useheuristic=True):
    """
    Find a solution to a planning problem in the given domain 
    
    The parameters domain and problem are exactly what is returned from pddl.parse_domain and pddl.parse_problem. If useheuristic is true,
    a planning heuristic (developed in task 4) should be used, otherwise use pathfinding.default_heuristic. This allows you to compare 
    the effect of your heuristic vs. the default one easily.
    
    The return value of this function should be a 4-tuple, with the exact same elements as returned by pathfinding.astar:
       - A plan, which is a sequence of graph.Edge objects that have to be traversed to reach a goal state from the start. Each Edge object represents an action, 
         and the edge's name should be the name of the action, consisting of the name of the operator the action was derived from, followed by the parenthesized 
         and comma-separated parameter values e.g. "move(agent-1,sq-1-1,sq-2-1)"
       - distance is the number of actions in the plan (i.e. each action has cost 1)
       - visited is the total number of nodes that were added to the frontier during the execution of the algorithm 
       - expanded is the total number of nodes that were expanded (i.e. whose neighbors were added to the frontier)
    """
    def heuristic(state, action):
        return pathfinding.default_heuristic

    def isgoal(state):
        return True

    start = graph.Node()
    return pathfinding.astar(
        start, heuristic if useheuristic else pathfinding.default_heuristic,
        isgoal)
Beispiel #2
0
def plan(domain, problem, useheuristic=True):
    """
    Find a solution to a planning problem in the given domain 
    
    The parameters domain and problem are exactly what is returned from pddl.parse_domain and pddl.parse_problem. If useheuristic is true,
    a planning heuristic (developed in task 4) should be used, otherwise use pathfinding.default_heuristic. This allows you to compare 
    the effect of your heuristic vs. the default one easily.
    
    The return value of this function should be a 4-tuple, with the exact same elements as returned by pathfinding.astar:
       - A plan, which is a sequence of graph.Edge objects that have to be traversed to reach a goal state from the start. Each Edge object represents an action, 
         and the edge's name should be the name of the action, consisting of the name of the operator the action was derived from, followed by the parenthesized 
         and comma-separated parameter values e.g. "move(agent-1,sq-1-1,sq-2-1)"
       - distance is the number of actions in the plan (i.e. each action has cost 1)
       - visited is the total number of nodes that were added to the frontier during the execution of the algorithm 
       - expanded is the total number of nodes that were expanded (i.e. whose neighbors were added to the frontier)
    """

    goal = expressions.make_expression(problem[2][0])

    def heuristic(state, action):
        num = 1
        num = expressions.goalsAchieved(action.target.world, goal.getRoot(),
                                        num)
        num = 1 / num
        #print(num)
        neighNum = len(state.neighbors)
        #print(neighNum)
        return num

    def isgoal(state):
        return True

    #Problem = [typesDictionary, initialStates, rawGoals, ExpressionGoal]
    #Domain = [actionsDictionary, typesDictionary]
    #print(problem[1])

    #expressions.printNAryTree(goal.getRoot())
    allPossibleActions = []

    #expressions.printNAryTree(goal.getRoot())

    start = graph.PlanNode(problem[1], domain[1], problem[0], [], 'Root')
    allPossibleActions = start.set_possibleActions(domain[0])
    start.set_initialStates()
    start.get_neighbors(allPossibleActions, domain[0], useheuristic)
    #for n in start.neighbors:
    #    print(n.name)
    #print(allPossibleActions)
    #astar(start, heuristic, goal, allActions, actionsDictionary)
    #input("Press Enter to continue...")
    #print(useheuristic)
    edgesPassed, totalPathCost, numFront, numExpandedNodes = pathfinding.astar(
        start, heuristic if useheuristic else pathfinding.default_heuristic,
        goal, allPossibleActions, domain[0], useheuristic)
    #returns priorityNode.edgesPassed, priorityNode.currentPathCost, numFrontier, expandedNodes

    return edgesPassed, len(edgesPassed), numFront, numExpandedNodes
Beispiel #3
0
def GetResponseTime(grid, startTile, endTile, travelSpeed):
    path = pathfinding.astar(grid, startTile, endTile)
    distance = 0
    #The height and width of each tile is 1m
    for i in range(len(path) - 1):
        if path[i][0] == path[i + 1][0] or path[i][1] == path[i + 1][1]:
            distance += 1
        else:
            distance += math.sqrt(2)
    return (distance / travelSpeed) * 60.0  #convert hours to minutes
Beispiel #4
0
    def find_path(self, start, end, avoid_blocking_entities=False):
        if avoid_blocking_entities == True:
            motionmap = deepcopy(self.terrain.motionmap)
            for x, y in [
                    e.loc() for e in self.entities
                    if e.block.motion == True and e.loc() not in [start, end]
            ]:
                motionmap[x][y] = False
        else:
            motionmap = self.terrain.motionmap

        path = pf.astar(motionmap, start, end)
        return path
 def get_path(self, x, y):
     """
     Get a path to the target x,y - which will be looked up to row, column for A* purposes
     :return:
     """
     end_row, end_column = Entity.grid.get_column_row_for_pixels(x, y)
     start_row, start_column = Entity.grid.get_column_row_for_pixels(self.x, self.y)
     
     # TODO this will fail if any of thses are 0
     if start_row and start_column and end_row and end_column:
         path = astar(Entity.grid.grid_for_pathing(), (start_row, start_column), (end_row, end_column))
         
         if path:
             # convert from row,col to pixels
             return [Entity.grid.get_pixel_center(p[0], p[1]) for p in path]
     
     return None
Beispiel #6
0
    def generate_rivers(self, river_nb=1, waypoint_nb=2):
        def random_tile_at_range(grid, start, radius, forbidden):
            vis = []
            for x in range(start.x - radius, start.x + radius):
                for y in range(start.y - radius, start.y + radius):
                    if not grid.out_of_bound(x, y):
                        t = grid.grid[x][y]
                        if t != start and abs(
                                utils.distance2p((start.x, start.y),
                                                 (t.x, t.y)) -
                                radius) < 1 and t.get_type() not in forbidden:
                            vis.append(t)
            if vis == []:
                return None
            return np.random.choice(vis)

        for i in range(river_nb):
            start = self.get_random_border()
            while start.get_type() in ["HILL", "MOUNTAIN"]:
                start = self.get_random_border()

            waypoints = [start]

            for j in range(1, waypoint_nb + 1):
                curr = waypoints[j - 1]
                t = random_tile_at_range(
                    self, curr,
                    int(((self.width + self.height) / 2) / waypoint_nb),
                    ["MOUNTAIN"])
                if t == None:
                    break
                waypoints.append(t)

            waypoints.append(self.get_opposite_border(start))

            river = []

            for j in range(len(waypoints) - 1):
                _start = waypoints[j]
                _goal = waypoints[j + 1]
                way = pf.astar(_start, _goal, self)
                for w in way:
                    river.append(w)

            for r in river:
                r.set_type("SHALLOW_WATER")
Beispiel #7
0
def plan(domain, problem, useheuristic=True):
    # get all objects applying the typinh hierarchy
    allobjs = mergeObjs(domain, problem)

    # get all grounded actions
    groundActions(domain.actions, allobjs)
    goalExp = expressions.make_expression(problem.goal)

    def isgoal(state):
        return expressions.models(state.state, goalExp)

    def heuristic(state, action):
        return SuperHeuristic(state, action, problem.init, problem.goal,
                              allobjs, isgoal)  # pathfinding.default_heuristic

    start = PlanNode("init", expressions.make_world(problem.init, allobjs),
                     allobjs)
    return pathfinding.astar(
        start, heuristic if useheuristic else pathfinding.default_heuristic,
        isgoal)
Beispiel #8
0
    def generateregion(self, adjtiles):
        if (self.biome in ['water', 'ice cap']):
            # maybe small islands?
            # icy shit on ice caps (but then how to handle poles?)
            # otherwise, all water
            for tile in self.tiles:
                tile.allwater = True
            return
        else:
            terrainnoise = self.noisegrids[0].add(self.tnoisegrids[0])
            terrainnoise = terrainnoise.sizedown(2)

            # first, do coasts and general dist2coast
            '''
			if (self.biome == 'volcano'):
				# special case for volcanos
				self.genvolcanoregion()
				return
			'''

            if (self.dist2coast < 2):
                # coastal, adjacent
                waterdirections = [direction \
                 for direction in adjtiles \
                 if (adjtiles[direction].biome == 'water')]
                for waterdir in waterdirections:
                    start, stop = self.coaststartstop(waterdir,
                                                      TILES2COAST_CONN)
                    if (not 0 in waterdir):
                        self.setneighbors(False)
                    else:
                        self.setneighbors(True)
                    path = astar(start, stop, self, terrainnoise)
                    for pos in path:
                        self.regiontile(*pos).allwater = True
                        dist = 1
                        newpos = (pos[0] + waterdir[0] * dist,
                                  pos[1] + waterdir[1] * dist)
                        while (self.inbounds(*newpos)):
                            self.regiontile(*newpos).allwater = True
                            dist += 1
                            newpos = (pos[0] + waterdir[0] * dist,
                                      pos[1] + waterdir[1] * dist)

            # do general elevation lines
            # only interested in cardinal direction adjacent tiles
            downslopedirections = [direction \
             for direction in adjtiles \
             if (adjtiles[direction].dist2coast < self.dist2coast) and
             0 in direction]
            self.setneighbors(True)
            for downslopedir in downslopedirections:
                start, stop = self.coaststartstop(downslopedir,
                                                  TILES2ELEV_CONN)
                path = astar(start, stop, self, terrainnoise)
                for pos in path:
                    if (self.regiontile(*pos).allwater):
                        continue
                    self.regiontile(*pos).elevationdir = downslopedir
                    dist = 1
                    newpos = (pos[0] + downslopedir[0] * dist,
                              pos[1] + downslopedir[1] * dist)
                    while (self.inbounds(*newpos)):
                        if (terrainnoise.get(*newpos) > 0.25):
                            self.regiontile(*newpos).elevationdir = None
                        else:
                            self.regiontile(*newpos).elevationdir = \
                             downslopedir
                        dist += 1
                        newpos = (pos[0] + downslopedir[0] * dist,
                                  pos[1] + downslopedir[1] * dist)

            # second, do hills and mountains
            if (self.biome in ['mountain', 'polar', 'volcano']):
                nummounts = MIN_MOUNTS + int(
                 (MAX_MOUNTS-MIN_MOUNTS) * \
                 terrainnoise.tiles[0])
                buffer = 6
                if (self.biome == 'volcano'):
                    nummounts = 1
                    buffer = 11
                peaks = terrainnoise.extremes(mindist=5,
                                              buffer=buffer,
                                              num=nummounts)

                mountlayers = []
                for i in range(nummounts):
                    x, y = peaks[i]
                    numlayers = MIN_MOUNTLAYERS + int(
                     (MAX_MOUNTLAYERS-MIN_MOUNTLAYERS) * \
                     self.tnoisegrids[0].tiles[i * \
                      self.tnoisegrids[0].size // 2])
                    if (self.biome == 'volcano'):
                        numlayers = VOLCANO_LAYERS
                    radius = MOUNTLAYER_WIDTH + 0.2
                    for j in range(numlayers):
                        mountlayers.append([x, y, radius])
                        radius += 1

                if (self.biome == 'volcano'):
                    self.regiontile(mountlayers[0][0],
                                    mountlayers[0][1]).islava = True
                for y in range(self.height):
                    for x in range(self.width):
                        for layer in mountlayers:
                            xysq = (x - layer[0])**2 + (y - layer[1])**2
                            if (xysq <= layer[2]**2):
                                if (self.regiontile(x, y).allwater):
                                    self.regiontile(x, y).allwater = False
                                if (abs(xysq - layer[2]**2) <= \
                                 MOUNTLAYER_WIDTH**2):
                                    diff = (x - layer[0], y - layer[1])
                                    vec = vectorsbyclosestangle(
                                        diff,
                                        [(1, 0), (-1, 0), (0, 1), (0, -1),
                                         (1, 1), (-1, 1), (1, -1), (-1, -1)])
                                    if (self.regiontile(
                                            x, y).elevationdir is None or dot(
                                                self.regiontile(
                                                    x, y).elevationdir, vec) >
                                            0):

                                        self.regiontile(x,
                                                        y).elevationdir = vec
                                elif (xysq == 0):
                                    self.regiontile(x, y).elevationdir = None

            else:
                # hills only have 1 layer
                numhills = int(self.numhills * terrainnoise.tiles[0])
                if (numhills > 0):
                    peaks = terrainnoise.extremes(mindist=5,
                                                  buffer=6,
                                                  num=numhills)

                    hilllayers = []
                    hill = 0
                    peak = 0
                    while (hill < numhills and peak < len(peaks)):
                        x, y = peaks[peak]
                        radius = 1
                        if (not self.regiontile(x, y).allwater):
                            hilllayers.append([x, y, radius])
                            hill += 1
                        peak += 1

                    for y in range(self.height):
                        for x in range(self.width):
                            for layer in hilllayers:
                                xysq = (x - layer[0])**2 + (y - layer[1])**2
                                if (xysq <= layer[2]**2):
                                    if (self.regiontile(x, y).allwater):
                                        self.regiontile(x, y).allwater = False
                                    if (abs(xysq - layer[2]**2) <= 2
                                            and xysq != 0):
                                        diff = (x - layer[0], y - layer[1])
                                        vec = vectorsbyclosestangle(
                                            diff, [(1, 0), (-1, 0), (0, 1),
                                                   (0, -1), (1, 1), (-1, 1),
                                                   (1, -1), (-1, -1)])
                                        self.regiontile(x,
                                                        y).elevationdir = vec
                                    elif (xysq == 0):
                                        self.regiontile(x,
                                                        y).elevationdir = None

            # third, do rivers
            if (not self.biome in ['ice cap', 'volcano', 'polar', 'mountain']):
                upslopedirections = [direction \
                 for direction in adjtiles \
                 if (adjtiles[direction].dist2coast > self.dist2coast) and
                 0 in direction]
                # 1) find center
                cx, cy = (self.width // 2, self.height // 2)  # (16, 16)
                # 2) path from center to one output, and from inputs to center
                riveroutput = None
                if (len(downslopedirections) > 0):
                    riveroutput = (
                        min(cx + downslopedirections[0][0] * self.width // 2,
                            self.width - 1),
                        min(cy + downslopedirections[0][1] * self.height // 2,
                            self.height - 1))

                riverinputs = []
                riverinputs.extend(self.newriverinputs(upslopedirections))
                for updir in upslopedirections:
                    x, y = (min(cx + updir[0] * self.width // 2,
                                self.width - 1),
                            min(cy + updir[1] * self.height // 2,
                                self.height - 1))
                    riverinputs.append((x, y))

                self.setneighbors(True)
                riverpathtoout = None
                if (not riveroutput is None):
                    riverpathtoout = astar((cx, cy), riveroutput, self,
                                           terrainnoise)
                riverpathsfromin = []
                for riverin in riverinputs:
                    path = astar(riverin, (cx, cy), self, terrainnoise)
                    riverpathsfromin.append(path)

                # 3) draw paths, stop when hitting another river
                # first draw from center to output, if any
                if (not riverpathtoout is None):
                    prevtile = riverpathtoout[0]
                    for i in range(len(riverpathtoout)):
                        x, y = riverpathtoout[i]
                        riverdir = None
                        if (i - 1 >= 0):
                            prevx, prevy = riverpathtoout[i - 1]
                            riverdir = (x - prevx, y - prevy)
                        else:
                            riverdir = downslopedirections[0]
                        regtile = self.regiontile(x, y)
                        if (not regtile.allwater):
                            if (regtile.riverout is None):
                                regtile.riverout = riverdir
                            if (i - 1 >= 0):
                                self.regiontile(
                                    *prevtile).riverin.append(riverdir)
                        else:
                            break

                for path in riverpathsfromin:
                    previousriverdir = None
                    for i in range(len(path)):
                        x, y = path[i]
                        riverdir = None
                        # if not at the last node
                        if (i + 1 < len(path)):
                            # get the next node
                            x2, y2 = path[i + 1]
                            previousriverdir = riverdir
                            riverdir = (x2 - x, y2 - y)
                        regtile = self.regiontile(x, y)
                        # if it doesn't already have a river, or is a lake/ocean
                        if (not regtile.allwater):
                            if (regtile.riverout is None):
                                regtile.riverout = riverdir
                                regtile.riverin.append(previousriverdir)
                        else:
                            break

                # 4) if hit a river going opposite directions, form a lake
                valleys = terrainnoise.extremes(mindist=5,
                                                minmax='min',
                                                buffer=6,
                                                num=self.numlakes)
                if (riverpathtoout is None):
                    self.regiontile(cx, cy).allwater = True
                for v in valleys:
                    self.regiontile(*v).allwater = True

            # last, do forests
            cx, cy = (self.width // 2, self.height // 2)
            for y in range(self.height):
                for x in range(self.width):
                    p = 1.0 - terrainnoise.get(x, y)
                    adjregtiles = self.adjacenttiles(x, y, True)
                    adjregtiles.append((x, y))
                    for tile in adjregtiles:
                        if (not self.regiontile(*tile).riverout is None
                                or self.regiontile(*tile).allwater):
                            p /= RIVERFORESTMOD
                    if (not self.regiontile(x, y).riverout is None):
                        p /= RIVERFORESTMOD
                    if (self.biome == 'mountain' and
                            not self.regiontile(x, y).elevationdir is None):
                        p *= MOUNTSLOPEFORESTMOD
                    if (p < self.forestdensity):
                        self.regiontile(x, y).forest = True
                    elif (x < FORESTBORDERBLEED
                          or x >= self.width - FORESTBORDERBLEED
                          or y < FORESTBORDERBLEED
                          or y >= self.height - FORESTBORDERBLEED):
                        diff = (x - cx, y - cy)
                        vec = vectorsbyclosestangle(diff, [(1, 0), (-1, 0),
                                                           (0, 1), (0, -1)])
                        adjbiome = adjtiles[vec].biome
                        if (adjbiome in biomedata and adjbiome != self.biome):
                            adjforestdensity = \
                             biomedata[adjbiome]['forestdensity']
                            dist = min(x, y, self.width - x, self.height - y)
                            borderforestdensity = lerp(
                                self.forestdensity, adjforestdensity,
                                float(dist) / FORESTBORDERBLEED)
                            if (p < adjforestdensity):
                                self.regiontile(x, y).forest = True

            ##### END OF TERRAIN, BEGIN POIs AND METADATA ###########

            # first, do towns (no towns on ice caps for now)
            # also, remove forests immediately around towns
            p1 = self.tnoisegrids[0].tiles[0]
            p2 = self.tnoisegrids[1].tiles[0]
            numtowns = int(((p1 + p2) / 2.0 * float(self.maxtowns)) + 0.5)

            towngrid = self.tnoisegrids[2]
            towngrid = towngrid.sizedown(2)
            for y in range(self.height):
                for x in range(self.width):
                    if (self.regiontile(x, y).riverout):
                        towngrid.tiles[x + towngrid.size * y] *= \
                         TOWNRIVERMOD
                    if (self.regiontile(x, y).allwater):
                        adjwatertiles = self.adjacenttiles(x, y, True)
                        for tile in adjwatertiles:
                            if (not self.regiontile(*tile).allwater):
                                towngrid.tiles[
                                 tile[0] + towngrid.size * tile[1]] *= \
                                  TOWNRIVERMOD

            townlocs = towngrid.extremes(mindist=3,
                                         buffer=2,
                                         minmax='max',
                                         num=numtowns)
            for x, y in townlocs:
                if (not self.regiontile(x, y).allwater):
                    self.regiontile(x, y).poi = 'town'
                    self.towns[(x, y)] = 1  #Town()
                # cut down nearby trees
                adjtiles = self.adjacenttiles(x, y, True)
                self.regiontile(x, y).forest = False
                for tile in adjtiles:
                    self.regiontile(*tile).forest = False

            # second, do roads
            if (len(townlocs) > 1):

                # find average point of all town positions
                avgpos = self.avgtuples(townlocs)
                firsttown, dist = self.nextmindistnode(avgpos, townlocs)

                # calculate endpoints
                points = self.roadpaths(firsttown, townlocs)

                # calculate paths
                roadlist = [
                ]  # may want to turn this into a 2-dim dict, faster
                costmap = [4] * self.size**2
                for y in range(self.height):
                    for x in range(self.width):
                        # avoid allwater completely
                        if (self.regiontile(x, y).allwater
                                or self.regiontile(x, y).islava):
                            costmap[x + self.width * y] = self.size**2
                        # avoid rivers if possible
                        elif (self.regiontile(x, y).riverout):
                            costmap[x + self.width * y] = 40
                        # avoid changes in elevation somewhat
                        elif (self.regiontile(x, y).elevationdir):
                            costmap[x + self.width * y] = 40
                        # prefer non-forest to forest
                        elif (self.regiontile(x, y).forest):
                            costmap[x + self.width * y] = 20

                # draw paths
                # diagonal paths?
                DIAGONAL_ROADS = False
                self.setneighbors(DIAGONAL_ROADS)
                for start, stop in points:
                    path = basicastar(start, stop, self, costmap)
                    for x, y in path:
                        if not (x, y) in roadlist:
                            roadlist.append((x, y))
                            costmap[x + self.width * y] = \
                             costmap[x + self.width * y] // 4

                for x, y in roadlist:
                    regtile = self.regiontile(x, y)
                    if (regtile.forest and
                            self.tnoisegrids[0].get(x, y) >= FORESTROADPROB):
                        continue

                    if x + 1 < self.width and (x + 1, y) in roadlist:
                        regtile.roaddirs.append((1, 0))
                    if x - 1 >= 0 and (x - 1, y) in roadlist:
                        regtile.roaddirs.append((-1, 0))

                    if y + 1 < self.height and (0, 1) in roadlist:
                        regtile.roaddirs.append((0, 1))
                    if y - 1 >= 0 and (x, y - 1) in roadlist:
                        regtile.roaddirs.append((0, -1))

                    if (DIAGONAL_ROADS):
                        if (x + 1 < self.width and y + 1 < self.height
                                and (x + 1, y + 1) in roadlist):
                            regtile.roaddirs.append((1, 1))
                        if (x + 1 < self.width and y - 1 >= 0
                                and (x + 1, y - 1) in roadlist):
                            regtile.roaddirs.append((1, -1))
                        if (x - 1 >= 0 and y + 1 < self.height
                                and (x - 1, y + 1) in roadlist):
                            regtile.roaddirs.append((-1, 1))
                        if (x - 1 >= 0 and y - 1 >= 0
                                and (x - 1, y - 1) in roadlist):
                            regtile.roaddirs.append((-1, -1))

            # third, do POIs

            # last, do dungeons
Beispiel #9
0
    def generate_river_simple(self,
                              nb_river=1,
                              waypoints_nb=3,
                              _start=None,
                              _end=None):
        if (_start == None or _end == None) and (len([
                t for t in self.get_tiles_1D() if t.get_type() in ["MOUNTAIN"]
        ]) <= 0 or len([
                t for t in self.get_tiles_1D()
                if t.get_type() in ["SHALLOW_WATER", "DEEP_WATER"]
        ]) <= 0):
            return
        for i in range(nb_river):
            if _start == None:
                start = np.random.choice([
                    t for t in self.get_tiles_1D()
                    if t.get_type() in ["MOUNTAIN"]
                ])
            else:
                start = _start

            if _end == None:
                end = np.random.choice([
                    t for t in self.get_tiles_1D()
                    if t.get_type() in ["SHALLOW_WATER", "DEEP_WATER"]
                ])
            else:
                end = _end

            # river_path_length = pf.getPathLength(start, end, self, cost_dict=p.type2cost_river, dn=True)
            # print(river_path_length)

            # waypoints = []

            # start_to_end_dir  = utils.angle_from_points((start.x, start.y), (end.x, end.y))
            # start_to_end_dist = utils.distance2p((start.x, start.y), (end.x, end.y))

            # waypoints.append(utils.point_from_direction((start.x, start.y), 5, utils.random_angle_in_direction(start_to_end_dir, 45), as_int=True))

            # _pass = 0
            # while utils.distance2p(waypoints[-1], (end.x, end.y)) > start_to_end_dist*0.1 and _pass<10:
            #     _pass += 1
            #     start_to_end_dir = utils.angle_from_points(waypoints[-1], (end.x, end.y))
            #     print(utils.distance2p(waypoints[-1], (end.x, end.y)), start_to_end_dir)
            #     waypoints.append(utils.point_from_direction(waypoints[-1], start_to_end_dist*0.1, utils.random_angle_in_direction(start_to_end_dir, 45), as_int=True))

            # print(waypoints, (end.x, end.y))

            river_path = pf.astar(start,
                                  end,
                                  self,
                                  cost_dict=p.type2cost_river,
                                  dn=True)

            for i, r in enumerate(river_path):
                if r.get_type() in ["SHALLOW_WATER", "DEEP_WATER"
                                    ] or r.is_river:
                    break
                r.is_river = True
            self.rivers_path.append(river_path[:i + 1])

        self.river_tiles = utils.flatten(self.rivers_path)
Beispiel #10
0
                     [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 9],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [9, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 9],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
                    dtype=np.int32)

    # Testing top left to bottom right
    spawn1_correct = (40, 30)
    spawn2_correct = (150, 140)

    # amount = 100
    solution, cost, closed_set = astar(spawn1_correct,
                                       spawn2_correct,
                                       pathing_grid,
                                       diagonal=1,
                                       debug=True)
    t0 = time.time()
    # for i in range(amount):
    #     # solution, cost, closed_set = astar((0, 0), (10, 13), nmap, diagonal=True)
    #     solution, cost, closed_set = astar(spawn1_correct, spawn2_correct, pathing_grid, diagonal=True)
    solution, cost, closed_set = astar(spawn1_correct,
                                       spawn2_correct,
                                       pathing_grid,
                                       diagonal=1,
                                       debug=True)
    t1 = time.time()
    np.save("path.npy", solution)  # list(closed_set))
    print(f"Time: {t1-t0}\nTotal path length: {cost}\nPath: {solution}")
    print(len(closed_set), closed_set)
Beispiel #11
0
def main():
    tick_time = 10
    size = (
        500, 500
    )  # can't change this yet without creating an issue with the board scale
    cell_size = 10
    Cube.rows = size[0] // cell_size
    background_colour = (20, 20, 20)

    # instantiate the rendering object (surface), BG colour, and title
    screen = pygame.display.set_mode(size)
    screen.fill(background_colour)
    pygame.display.set_caption("Maze Game")
    clock = pygame.time.Clock()

    # Create Maze
    maze = Maze(size, cell_size)

    distance = manhattan_distance(maze.goal)

    maze.zombies.append(Zombie(maze.start, Colour.ZOMBIE))

    solution = pathfinding.astar(maze.start, maze.goal_test, maze.successors,
                                 distance)
    cached_path = pathfinding.node_to_path(
        solution) if solution is not None else []

    # Game Loop
    running = True  # len(cached_path) > 0
    current = None

    while running:
        screen.fill(background_colour)
        maze.draw_grid(screen)
        maze.draw_cells(screen)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break

        # Check for a left mouse click down
        mouse_pressed = pygame.mouse.get_pressed()
        if mouse_pressed == (1, 0, 0):
            (x, y) = pygame.mouse.get_pos()
            maze.click_create_tower(x, y)

        clock.tick(tick_time)  # 30 would be real time - slower < 30 > faster

        _temp = current
        if _temp is not None and maze.cells[_temp.row][
                _temp.col].color != Colour.BLOCKED:
            maze.cells[_temp.row][_temp.col].color = Colour.EMPTY

        current = cached_path.pop(0)

        if maze.cells[current.row][current.col].color == Colour.EMPTY:
            maze.cells[current.row][current.col].color = Colour.ZOMBIE

        elif maze.cells[current.row][current.col].color != Colour.EMPTY:
            # need to invalidate the cache and start again
            if _temp is not None:
                # maze.cells[_temp.row][_temp.col].color = Colour.PATH
                maze.cells[current.row][current.col].color = Colour.BLOCKED
                solution = pathfinding.astar(_temp, maze.goal_test,
                                             maze.successors, distance)
            else:
                solution = pathfinding.astar(current, maze.goal_test,
                                             maze.successors, distance)

            if solution is None:
                print("No solution found using A*!")
                break
            else:
                # print("Problem: Recalculating!")
                cached_path = pathfinding.node_to_path(solution)

        maze.draw_cells(screen)
        pygame.display.update()
Beispiel #12
0
def plan(domain, problem, useheuristic=True):
    """
    Find a solution to a planning problem in the given domain 
    
    The parameters domain and problem are exactly what is returned from pddl.parse_domain and pddl.parse_problem. If useheuristic is true,
    a planning heuristic (developed in task 4) should be used, otherwise use pathfinding.default_heuristic. This allows you to compare 
    the effect of your heuristic vs. the default one easily.
    
    The return value of this function should be a 4-tuple, with the exact same elements as returned by pathfinding.astar:
       - A plan, which is a sequence of graph.Edge objects that have to be traversed to reach a goal state from the start. Each Edge object represents an action, 
         and the edge's name should be the name of the action, consisting of the name of the operator the action was derived from, followed by the parenthesized 
         and comma-separated parameter values e.g. "move(agent-1,sq-1-1,sq-2-1)"
       - distance is the number of actions in the plan (i.e. each action has cost 1)
       - visited is the total number of nodes that were added to the frontier during the execution of the algorithm 
       - expanded is the total number of nodes that were expanded (i.e. whose neighbors were added to the frontier)
    """
    '''
    domain[0] = pddl_types, domain[1] = pddl_constants, domain[2] = pddl_predicates, domain[3] = pddl_actions
    problem[0] = pddl_objects, problem[1] = pddl_init_exp, problem[2] = pddl_goal_exp
    '''
    def heuristic(state, action):
        """Calculates a heuristic following some basic principles of Fast-Forward algorithm"""
        # initial state is a neighbor of a previous state that A* needs to evaluate
        props_layer = state
        # relaxed plan has layers, each with and action layer and a propositions layer
        relaxed_plan_graph = [[[], props_layer]]

        # extend one action layer and proposition layer at a time while goal is not reached
        while not isgoal(props_layer):
            # next action layer: get "relaxed" neighbors whose Add Lists have a real effect and ignoring Delete Lists
            actions_layer = props_layer.get_neighbors(True)
            # next props layer: start with propositions in current layer and add new ones generated by each new action
            next_props_layer = set(props_layer.world.atoms)
            for next_action in actions_layer:
                next_props_layer = next_props_layer.union(
                    next_action.target.world.atoms)

            # stop if next propositions layer did not add any new propositions, otherwise continue in the loop
            if props_layer.world.atoms.issuperset(next_props_layer):
                break

            # new propositional layer
            new_world = expressions.World(next_props_layer,
                                          props_layer.world.sets)
            props_layer = graph.ExpressionNode(new_world, props_layer.actions,
                                               props_layer.preceding_action)
            # add new actions and props layer to relaxed plan
            relaxed_plan_graph.append([actions_layer, props_layer])

        # extract relaxed plan size and return it as the heuristic value
        return extract_plan_size(relaxed_plan_graph)

    def extract_plan_size(rpg):
        """Extract relaxed plan size based on the number of actions required to complete it"""
        goal = problem[2]
        final_state = rpg[len(rpg) - 1][1]

        # if the world in final proposition layer does not contain the goal, return magic large number as h ...
        if not isgoal(final_state):
            return 1000

        # find the layer where each sub-goal appears for the first time on the relaxed planning graph
        first_goal_levels = {}
        add_first_goal_levels(rpg, goal, first_goal_levels)
        # obtain maximum level number where a goal was found
        first_goal_levels_max = max(first_goal_levels.keys())

        # backtrack starting on the last proposition layer we need to consider
        logger.debug("Goal Levels: %s" % first_goal_levels)
        for i in range(first_goal_levels_max, 0, -1):
            logger.debug("BACKTRACKING i: %s" % i)
            # if there is at least one sub-goal on level i
            if i in first_goal_levels:
                add_first_action_levels(rpg, first_goal_levels, i)
        logger.debug("Action-Goal Levels: %s" % first_goal_levels)

        h = 0
        for layer, actions in first_goal_levels.items():
            h += len(actions)

        return h

    def add_first_goal_levels(rpg, goal, first_goal_levels):
        """Find the layer where each sub-goal appears for the first time on the relaxed planning graph"""
        # handle special case when the goal is not a conjunction of atoms, but one atom
        if isinstance(goal, expressions.Atom):
            goal = expressions.And([goal])

        # for each sub-goal in goal
        for sub_goal in goal.operands:
            level = 0
            # for each layer in relaxed planning graph
            for layer in rpg:
                # if the world in this propositional layer models this sub-goal, add sub-goal to that level
                if layer[1].world.models(sub_goal):
                    if level in first_goal_levels:
                        first_goal_levels[level] = first_goal_levels[
                            level].union({sub_goal})
                    else:
                        first_goal_levels[level] = {sub_goal}
                    # break to guarantee we always only use only the first appearance
                    break
                level += 1

    def add_first_action_levels(rpg, first_goal_levels, layer):
        """Find the layer where each action whose effect is a sub-goal appears for the first time on the relaxed
        planning graph. Then consider its preconditions as new sub-goals and add them to preceding layers of
        first_goal_levels that will eventually be reached by the backtracking process to also process their
        preconditions"""
        for sub_goal in first_goal_levels[layer]:
            level = 0
            # for each layer in the relaxed planning graph
            for layer_index in range(len(rpg)):
                # for each action on this layer of the relaxed planning graph
                for action in rpg[layer_index][0]:
                    # determine if this action introduces sub_goal for the first time
                    previous_props_layer = rpg[layer_index - 1][1]
                    next_props_layer = action.target
                    if next_props_layer.world.models(
                            sub_goal
                    ) and not previous_props_layer.world.models(sub_goal):
                        # each precondition must now be considered a sub-goal
                        preconditions = action.target.preceding_action.expression.operands[
                            0]
                        logger.debug("\tACTION: %s" % action.name)
                        logger.debug("\tPRECONS: %s" % preconditions)
                        # find the layer where each sub-goal appears for the first time on the relaxed planning graph
                        add_first_goal_levels(rpg, preconditions,
                                              first_goal_levels)
                        # break to guarantee we always only use only the first appearance
                        break
                level += 1

    def isgoal(state):
        """Check is goal is reached"""
        return state.world.models(problem[2])

    # get the sets variable required to make a n initial world
    world_sets = build_world_sets(domain[1], problem[0], domain[0])

    # get all expanded expressions for all actions
    expanded_expressions = []

    # for each action in the domain
    for action in domain[3]:
        substitutions_per_action = []
        # for each group of params of the same type for this action
        for parameter_type in action.parameters:
            logger.debug("Action: %s - Param Type: %s - Params: %s" %
                         (action.name, parameter_type,
                          action.parameters[parameter_type]))
            # for each param in each group of params of the same type for this action
            for parameter in action.parameters[parameter_type]:
                substitutions_per_param = []
                # for each ground param as taken from world_sets based on type
                for ground_param in world_sets[parameter_type]:
                    logger.debug("\tParam: %s, Ground Param: %s" %
                                 (parameter, ground_param))
                    substitutions_per_param.append([parameter, ground_param])
                substitutions_per_action.append(substitutions_per_param)
        # expand the action with all possible substitutions
        expanded_expressions.extend(
            expand_action(action, substitutions_per_action))

    # create the initial world with pddl_init_exp and world_sets and the start node for astar
    logger.info("Grounded Actions: %s" % len(expanded_expressions))
    world = expressions.make_world(problem[1], world_sets)
    start = graph.ExpressionNode(world, expanded_expressions, None)

    return pathfinding.astar(
        start, heuristic if useheuristic else pathfinding.default_heuristic,
        isgoal)
	def LevelGridUpdate(self):
		mx, my = PKFW.gtmp() #mouse x and y
		tx = int(mx/self.tileSize['width'])
		ty = int(my/self.tileSize['height'])	#current tile mouse is over

		if(tx<0):tx=0
		if(ty<0):ty=0
		if(tx>self.levelSize['x']-1):
			tx = self.levelSize['x']-1
		if(ty>self.levelSize['y']-1):
			ty = self.levelSize['y']-1	#current tile mouse is over window clamp	
				

		#left mouse button sets tile to start
		#right mouse button sets tile to wall
		#middle mouse button sets tile to blank				
		if(PKFW.gmpr(0) and self.buttonpressed[0] is False):
			self.buttonpressed[0] = True
			self.levelTiles[tx][ty].setS(sprites[1])
		self.buttonpressed[0] = not PKFW.gtmr(0)
		if(PKFW.gmpr(1)):
			self.levelTiles[tx][ty].setS(sprites[3])
		if(PKFW.gmpr(2)):
			self.levelTiles[tx][ty].setS(sprites[0])
		

		#if the start exists and there is only one finish and the 'a' key is pressed
		#astar runs and sets the tiles in the returned path to the path sprite	
		if isinstance(start, Tile) and len(finish)==1 and PKFW.gtkp(65) and self.buttonpressed[1] is False: 
			self.buttonpressed[1] = True
			self.path = pathfinding.astar(start, finish[0], self.levelTiles, self.levelSize)
			if(isinstance(self.path, list)):
				for i in range(len(self.path)):
					self.path[i].setS(sprites[4])
		self.buttonpressed[1] = not PKFW.gtkr(65)
		
		#if the start exists and there is at least 1 finish and the 'd' key is pressed
		#dijkstra runs (path tiles sprite set to path)
		if isinstance(start, Tile) and len(finish)>0 and PKFW.gtkp(68) and self.buttonpressed[2] is False:
			self.buttonpressed[2] = True
			self.path = pathfinding.dijkstra(start, finish, self.levelTiles, self.levelSize)
			if(isinstance(self.path,list)):
				for i in range(len(self.path)):
					self.path[i].setS(sprites[4])
		self.buttonpressed[2] = not PKFW.gtkr(68)

		#checks if path is a list
		#if so then delete all the elements and set to None
		#in case previous tiles from previous paths are left over when attempting new path
		
		if(isinstance(self.path,list)):
			for i in range(len(self.path)):
				self.path[i].resetTile()
			del self.path[:]
			self.path = None
			
		
		#when the 'c' button is pressed all the tiles that are not walls are set to blank tiles
		if(PKFW.gtkp(67)):
			for x in range(len(self.levelTiles)):
				for y in range(len(self.levelTiles[x])):
					if(self.levelTiles[x][y].Sid != sprites[3]):
						self.levelTiles[x][y].resetTile()
						self.levelTiles[x][y].setS(sprites[0])


		#the f1 button clears all the wanderes and tiles and initialises the flock class
		#to return to the wanderers and tiles press ESC
		if(PKFW.gtkp(kd.keys['F1']) and self.buttonpressed[3] is False):
			self.buttonpressed[3] = True
			self.flock = ai.flock(30, sprites[5])
			for i in range (len(self.wanderers)):
				del self.wanderers[:]
			for x in range(len(self.levelTiles)):
				for y in range(len(self.levelTiles[x])):
					self.levelTiles[x][y].setS(sprites[0])
		self.buttonpressed[3] = not PKFW.gtkr(kd.keys['F1'])


		#pressing f12 sets debug to !debug
		#used when creating boid steering behaviours
		if(PKFW.gtkp(kd.keys['F12']) and self.buttonpressed[4] is False):
			self.buttonpressed[4] = True
			kd.debug = not kd.debug
		self.buttonpressed[4] = not PKFW.gtkr(kd.keys['F12'])