def construct_path(self, start, end): # Rooms the path can go through allowedRooms = list(self.waypointRooms[start] | self.waypointRooms[end]) # Queue of paths so far frontierPaths = Queue.PriorityQueue() frontierPaths.put([0, [start], 0]) # Dict of points reached so far (to keep contains() at O(1)) visited = dict() visited[start] = True while not frontierPaths.empty(): currentNode = frontierPaths.get() currentPath = currentNode[1] # A list of waypoints # Check if we've reached the goal - if so, terminate pathfinding currentWaypoint = currentPath[-1] if currentWaypoint == end: # Concatenate all the steps between the waypoints together currentSteps = [] for i in range(0, len(currentPath) - 1): a = currentPath[i+1] b = currentPath[i] fullPath = self.allPaths[a][b] currentSteps.extend(fullPath) return (currentSteps, currentPath) # Expand it for nextWaypoint in self.availableConnections[currentWaypoint]: # Don't include already-visited points if nextWaypoint in visited: continue # Don't include waypoints in non-allowed rooms inAllowedRooms = False for r in self.waypointRooms[nextWaypoint]: if r in allowedRooms: inAllowedRooms = True break if not inAllowedRooms: continue # Mark next waypoint as visited visited[nextWaypoint] = True # Add path to frontier nextPath = self.allPaths[nextWaypoint][currentWaypoint] travelled = currentNode[2] + len(nextPath) * self.mapConstants["path_step_size"] dist = vecLen(end, nextWaypoint) frontierPaths.put([travelled + dist, currentPath + [nextWaypoint], travelled]) # No paths found print '\033[91mERROR: no path found between ' + str(start) + ' --> ' + str(end) + '\033[0m' return ([], [])
def turn(self, turn=None): while self.running and self.update_state(json.loads(turn)): # Get paths for p in self.people: p.path = [] if p.pos != p.targetPos: (p.path, p.waypoints) = self.construct_path(p.pos, p.targetPos) p.pathLength = len(p.path) # Smooth moving framesLeft = float(self.constants["FRAMES_PER_TURN"]) movementFinalized = False while framesLeft >= 0 or not movementFinalized: movementFinalized = self.movementIsComplete() self.draw() self.update() self.GameClock.tick(self.MAX_FPS) framesLeft -= 1.0 for p in self.people: # --- Calculate path length --- # Initial float iterSteps = float(p.pathLength) / float(self.constants["FRAMES_PER_TURN"]) # Smooth float part out over frames iterSteps = math.ceil(framesLeft * iterSteps) - math.floor((framesLeft - 1) * iterSteps) # Keep people moving at a minimum pace iterSteps = min(iterSteps, self.constants["MIN_STEPS_PER_FRAME"]) # ------ End path length ------ if p.path and len(p.path) > iterSteps: for i in range(0, int(iterSteps)): p.pos = p.path[0] p.path.pop(0) # Adjust rotation rotationLookahead = self.constants["ROTATION_LOOKAHEAD"] if len(p.path) > rotationLookahead: p.set_rotation(angleBetween(p.pos, p.path[rotationLookahead]) - 90) else: p.set_rotation(angleBetween(p.pos, p.targetPos) - 90) else: p.pos = p.targetPos p.path = [] # Check for direction marker, otherwise just keep current rotation for d in self.rooms[p.room].dirmarkers: if vecLen(d, p.pos) < self.constants["DIR_MARKER_RADIUS"]: p.set_rotation(angleBetween(p.pos, d) - 90) break for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() self.running = False movementFinalized = True if self.running: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() self.running = False if not self.game_done: break
def _findShortestValidPath(start, end, roomColor, pixels, imgSize, stepSize=1): # Ace settings playerSize = 4 # Should be 12, use 4 for testing playerStep = 4 # seen seen = dict() seen[(start[0], start[1])] = ((-1, -1), 0, False) # Queues nodeQueue = Queue.PriorityQueue() nodeQueue.put((0.0, 0.0, start[0], start[1])) width = imgSize[0] height = imgSize[1] # Do BFS pathFound = False node = None while not nodeQueue.empty(): node = nodeQueue.get() coord = node[2:] seenval = seen[coord] seen[coord] = (seenval[0], seenval[1], True) x = coord[0] y = coord[1] # Base case 1: too close to a wall pathIsValid = True for i in range(x - playerSize, x + playerSize + 1, playerStep): if not pathIsValid: break # Bounds check (1/2) if (i < 0 or width <= i): continue for j in range(y - playerSize, y + playerSize + 1, playerStep): # Bounds check (2/2) if (j < 0 or height <= j): continue color = _stringify(pixels[i, j]) if color == wallColor: pathIsValid = False break if not pathIsValid: continue # Base case 2: hit a different color color = _stringify(pixels[x, y]) if color != roomColor and color in roomNames: continue # Base case 3: hit goal if vecLen(coord, end) <= stepSize: pathFound = True break # Iterative case for mx in range(-1, 2): for my in range(-1, 2): # Skip identical pixels if (mx == 0) and (my == 0): continue px = x + mx * stepSize py = y + my * stepSize # Skip out of bounds pixels if (px < 0 or width <= px or py < 0 or height <= py): continue # Skip visited pixels nextCoord = (px, py) travelled = float(node[1]) + vecLen((0,0), (stepSize*mx, stepSize*my)) if not seen.get(nextCoord, None): # Add pixel to queue seen[nextCoord] = (coord, travelled, False) dist = float(travelled) + _heuristic(nextCoord, end) nodeQueue.put((dist, travelled, px, py)) elif not seen[nextCoord][2] and seen[nextCoord][1] > travelled: seen[nextCoord] = (coord, travelled, False) dist = float(travelled) + _heuristic(nextCoord, end) nodeQueue.put((dist, travelled, px, py)) # Backtrack to start (if possible) if not pathFound: print "\033[91mDEST NOT REACHED " + str(start) + " --> " + str(end) + "\033[0m" return None path = list() if coord != end: path.append(end) while coord != start: path.append(coord) coord = seen[coord][0] return path
def _findClosestPixel(inX, inY, targetColor, pixels, imgSize, searchRadius, stepSize=1): start = (inX, inY) # Queues coordQueue = Queue.Queue() coordQueue.put(start) width = imgSize[0] height = imgSize[1] # Visited visited = dict() visited[start] = True # Search while not coordQueue.empty(): coord = coordQueue.get() x = coord[0] y = coord[1] # Base case 1: hit target curColor = _stringify(pixels[x, y]) if curColor == targetColor: return coord # Base case 2: out of search range if vecLen(coord, start) > searchRadius: continue # Iterative case 1: further iteration (basically recursion) for mx in range(-1, 2): px = x + mx * stepSize # Skip out of bounds pixels (pt 1/2) if (px < 0 or width <= px): continue for my in range(-1, 2): # Skip identical pixels if (mx == 0) and (my == 0): continue py = y + my * stepSize # Skip out of bounds pixels (pt 2/2) if (py < 0 or height <= py): continue # Add pixel to queue nextPos = (px, py) if not visited.get(nextPos, False): visited[nextPos] = True coordQueue.put((px, py)) # No match found return None
def turn(self, turn=None): while self.running and self.update_state(json.loads(turn)): # Get paths for p in self.people: p.path = [] if p.pos != p.targetPos: (p.path, p.waypoints) = self.construct_path(p.pos, p.targetPos) p.pathLength = len(p.path) # Smooth moving turns = float(self.constants["TURN_FRAMES"]) movementFinalized = False while turns >= 0 or not movementFinalized: movementFinalized = self.movementIsComplete() self.draw() self.update() self.GameClock.tick(self.MAX_FPS) turns -= 1.0 for p in self.people: # Calculate path length iterSteps = float(p.pathLength) / float(self.constants["TURN_FRAMES"]) # Initial float iterSteps = math.ceil(turns * iterSteps) - math.floor((turns - 1) * iterSteps) # Smooth float part out over turns if p.path and len(p.path) > iterSteps: for i in range(0, int(iterSteps)): p.pos = p.path[0] p.path.pop(0) # Adjust rotation rotationLookahead = int(self.constants["ROTATION_LOOKAHEAD"]) if len(p.path) > rotationLookahead: p.set_rotation(angleBetween(p.pos, p.path[rotationLookahead]) - 90) else: p.set_rotation(angleBetween(p.pos, p.targetPos) - 90) else: p.pos = p.targetPos # Check for direction marker, otherwise just keep current rotation rotated = False for d in self.rooms[p.room].dirmarkers: if not rotated and vecLen(d, p.pos) < self.constants["DIR_MARKER_RADIUS"]: p.set_rotation(angleBetween(p.pos, d) - 90) rotated = True for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() self.running = False movementFinalized = True if self.running: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() self.running = False if not self.game_done: break
def construct_path(self, start, end): #print "construct paths " + str(start) + " --> " + str(end) # Rooms the path can go through allowedRooms = list(self.waypointRooms[start] | self.waypointRooms[end]) # Queue of paths so far frontierPaths = Queue.PriorityQueue() frontierPaths.put([0, [start], 0]) # Dict of points reached so far (to keep contains() at O(1)) visited = dict() visited[start] = True while not frontierPaths.empty(): currentNode = frontierPaths.get() currentPath = currentNode[1] # A list of waypoints # Check if we've reached the goal - if so, terminate pathfinding currentWaypoint = currentPath[-1] if currentWaypoint == end: # Concatenate all the steps between the waypoints together currentSteps = [] for i in range(0, len(currentPath) - 1): a = currentPath[i+1] b = currentPath[i] fullPath = self.allPaths[a][b] currentSteps.extend(fullPath) #print '-- Done --' return (currentSteps, currentPath) # Expand it for nextWaypoint in self.availableConnections[currentWaypoint]: # Don't include already-visited points if nextWaypoint in visited: continue # Don't include waypoints in non-allowed rooms inAllowedRooms = False for r in self.waypointRooms[nextWaypoint]: if r in allowedRooms: inAllowedRooms = True break if not inAllowedRooms: continue # Mark next waypoint as visited visited[nextWaypoint] = True # Add path to frontier travelled = currentNode[2] + len(self.allPaths[nextWaypoint][currentWaypoint]) * self.mapConstants["path_step_size"] dist = vecLen(end, nextWaypoint) frontierPaths.put([travelled + dist, currentPath + [nextWaypoint], travelled]) # No paths found #print '\033[91mERROR at construct_path: no path found between ' + str(start) + ' --> ' + str(end) + '\033[0m' return ([], [])
def _findShortestValidPath(start, end, roomColor, pixels, imgSize, stepSize=1): # Ace settings playerSize = 4 # Should be 12, use 4 for testing playerStep = 4 # seen seen = dict() seen[(start[0], start[1])] = ((-1, -1), 0, False) # Queues nodeQueue = Queue.PriorityQueue() nodeQueue.put((0.0, 0.0, start[0], start[1])) width = imgSize[0] height = imgSize[1] # Do BFS pathFound = False node = None while not nodeQueue.empty(): node = nodeQueue.get() coord = node[2:] seenval = seen[coord] seen[coord] = (seenval[0], seenval[1], True) x = coord[0] y = coord[1] # Base case 1: too close to a wall pathIsValid = True for i in range(x - playerSize, x + playerSize + 1, playerStep): if not pathIsValid: break # Bounds check (1/2) if (i < 0 or width <= i): continue for j in range(y - playerSize, y + playerSize + 1, playerStep): # Bounds check (2/2) if (j < 0 or height <= j): continue color = _stringify(pixels[i, j]) if color == wallColor: pathIsValid = False break if not pathIsValid: continue # Base case 2: hit a different color color = _stringify(pixels[x, y]) if color != roomColor and color in roomNames: continue # Base case 3: hit goal if vecLen(coord, end) <= stepSize: pathFound = True break # Iterative case for mx in range(-1, 2): for my in range(-1, 2): # Skip identical pixels if (mx == 0) and (my == 0): continue px = x + mx * stepSize py = y + my * stepSize # Skip out of bounds pixels if (px < 0 or width <= px or py < 0 or height <= py): continue # Skip visited pixels nextCoord = (px, py) travelled = float(node[1]) + vecLen( (0, 0), (stepSize * mx, stepSize * my)) if not seen.get(nextCoord, None): # Add pixel to queue seen[nextCoord] = (coord, travelled, False) dist = float(travelled) + _heuristic(nextCoord, end) nodeQueue.put((dist, travelled, px, py)) elif not seen[nextCoord][2] and seen[nextCoord][1] > travelled: seen[nextCoord] = (coord, travelled, False) dist = float(travelled) + _heuristic(nextCoord, end) nodeQueue.put((dist, travelled, px, py)) # Backtrack to start (if possible) if not pathFound: print "\033[91mDEST NOT REACHED " + str(start) + " --> " + str( end) + "\033[0m" return None path = list() if coord != end: path.append(end) while coord != start: path.append(coord) coord = seen[coord][0] return path
def _findShortestValidPath(start, end, roomColor, pixels, imgSize, stepSize=1): # Ace settings playerSize = 4 # Should be 12, use 4 for testing playerStep = 4 # Parent positions parents = dict() parents[(start[0], start[1])] = (-1, -1) # Visited visited = dict() # Queues nodeQueue = Queue.PriorityQueue() nodeQueue.put((0.0, 0.0, start[0], start[1], [])) width = imgSize[0] height = imgSize[1] # Do BFS pathFound = False node = None while not nodeQueue.empty(): node = nodeQueue.get() coord = node[2:4] # Skip visited nodes if visited.get(coord, False): continue visited[coord] = True x = coord[0] y = coord[1] # Base case 1: too close to a wall pathIsValid = True for i in range(x - playerSize, x + playerSize + 1, playerStep): if not pathIsValid: break # Bounds check (1/2) if (i < 0 or width <= i): continue for j in range(y - playerSize, y + playerSize + 1, playerStep): # Bounds check (2/2) if (j < 0 or height <= j): continue color = _stringify(pixels[i, j]) if color == wallColor: pathIsValid = False break if not pathIsValid: continue # Base case 2: hit a different color color = _stringify(pixels[x, y]) if color != roomColor and color in roomNames: continue # Base case 3: hit goal if vecLen(coord, end) <= stepSize: pathFound = True break # Iterative case for mx in range(-1, 2): for my in range(-1, 2): # Skip identical pixels if (mx == 0) and (my == 0): continue px = x + mx * stepSize py = y + my * stepSize # Skip out of bounds pixels if (px < 0 or width <= px or py < 0 or height <= py): continue # Skip visited pixels nextCoord = (px, py) if visited.get(nextCoord, False): continue # Add pixel to queue travelled = float(node[1]) + vecLen((0,0), (stepSize*mx, stepSize*my)) dist = float(travelled) + vecLen(nextCoord, end) # <-- disable A* because bugs nodeQueue.put((dist, travelled, px, py, [nextCoord] + node[4])) # Backtrack to start (if possible) if not pathFound: print "\033[91mDEST NOT REACHED " + str(start) + " --> " + str(end) + "\033[0m" return None path = node[4] return path