// Start the Transport. func (t *Transport) start() { dialer := &net.Dialer{Timeout: t.DialTimeout} t.transport = &http.Transport{ Dial: dialer.Dial, Proxy: t.Proxy, TLSClientConfig: t.TLSClientConfig, DisableKeepAlives: t.DisableKeepAlives, DisableCompression: t.DisableCompression, MaxIdleConnsPerHost: t.MaxIdleConnsPerHost, ResponseHeaderTimeout: t.ResponseHeaderTimeout, } t.closeMonitor = make(chan bool) t.pq = pqueue.New(16) go t.monitor() }
// FindPath finds a path // Returns a slice of points which consists the starting point up to the end point inclusively func (p *Pathfinder) FindPath(startX int, startY int, endX int, endY int) ([]*Point, error) { // No acceptable tiles were set if len(p.acceptableTiles) == 0 { return nil, errors.New("You can't find a path without first calling SetAcceptableTiles()") } // No grid was set if p.collisionGrid == nil { return nil, errors.New("You can't find a path without first calling SetGrid()") } // Start or endpoint outside of scope if startX < 0 || startY < 0 || endX < 0 || endX < 0 || startX > len(p.collisionGrid[0])-1 || startY > len(p.collisionGrid)-1 || endX > len(p.collisionGrid[0])-1 || endY > len(p.collisionGrid)-1 { return nil, errors.New("You can't find a path without first calling SetGrid()") } // Start and end are the same tile if startX == endX && startY == endY { return make([]*Point, 0), nil } // End point is not an acceptable tile endTile := p.collisionGrid[endY][endX] isAcceptable := false for i := 0; i < len(p.acceptableTiles); i++ { if endTile == p.acceptableTiles[i] { isAcceptable = true break } } if isAcceptable == false { return make([]*Point, 0), nil } p.startX = startX p.startY = startY p.endX = endX p.endY = endY // TODO is there a more memory-efficient way to do this ? p.openList = pqueue.New(len(p.collisionGrid[0]) * len(p.collisionGrid)) p.coordinateToNode = make(map[string]*node) n := newNode(p.startX, p.startY, p.endX, p.endY, nil, straightCost) p.coordinateToNode[getHashKeyForPoint(startX, startY)] = n item := &pqueue.Item{Value: n, Priority: int64(n.bestGuessDistance() * costPrecision)} p.openList.Push(item) for { if p.openList.Len() == 0 { return nil, errors.New("path not found") } item, _ := p.openList.PeekAndShift(math.MaxInt64) parent := item.Value.(*node) var sn searchNodes if parent.y > 0 { sn = append(sn, newSearchNode(0, -1, p.endX, p.endY, straightCost*p.getTileCost(parent.x, parent.y-1), parent)) } if parent.x < len(p.collisionGrid[0])-1 { sn = append(sn, newSearchNode(1, 0, p.endX, p.endY, straightCost*p.getTileCost(parent.x+1, parent.y), parent)) } if parent.y < len(p.collisionGrid)-1 { sn = append(sn, newSearchNode(0, 1, p.endX, p.endY, straightCost*p.getTileCost(parent.x, parent.y+1), parent)) } if parent.x > 0 { sn = append(sn, newSearchNode(-1, 0, p.endX, p.endY, straightCost*p.getTileCost(parent.x-1, parent.y), parent)) } if p.diagonalsEnabled { if parent.x > 0 && parent.y > 0 { if p.allowCornerCutting || (isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x, parent.y-1) && isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x-1, parent.y)) { sn = append(sn, newSearchNode(-1, -1, p.endX, p.endY, diagonalCost*p.getTileCost(parent.x-1, parent.y-1), parent)) } } if parent.x < len(p.collisionGrid[0])-1 && parent.y < len(p.collisionGrid)-1 { if p.allowCornerCutting || (isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x, parent.y+1) && isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x+1, parent.y)) { sn = append(sn, newSearchNode(1, 1, p.endX, p.endY, diagonalCost*p.getTileCost(parent.x+1, parent.y+1), parent)) } } if parent.x < len(p.collisionGrid[0])-1 && parent.y > 0 { if p.allowCornerCutting || (isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x, parent.y-1) && isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x+1, parent.y)) { sn = append(sn, newSearchNode(1, -1, p.endX, p.endY, diagonalCost*p.getTileCost(parent.x+1, parent.y-1), parent)) } } if parent.x > 0 && parent.y < len(p.collisionGrid)-1 { if p.allowCornerCutting || (isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x, parent.y+1) && isTileWalkable(p.collisionGrid, p.acceptableTiles, parent.x-1, parent.y)) { sn = append(sn, newSearchNode(-1, 1, p.endX, p.endY, diagonalCost*p.getTileCost(parent.x-1, parent.y+1), parent)) } } } // First sort all of the potential nodes we could search by their cost + heuristic distance sort.Sort(sn) // Search all of the adjacent nodes for i := 0; i < len(sn); i++ { adjacentCoordinateX := sn[i].parent.x + sn[i].x adjacentCoordinateY := sn[i].parent.y + sn[i].y hashKey := getHashKeyForPoint(adjacentCoordinateX, adjacentCoordinateY) _, exists := p.additionalPointsToAvoid[hashKey] if !exists { if sn[i].endX == adjacentCoordinateX && sn[i].endY == adjacentCoordinateY { var path []*Point path = append(path, &Point{X: adjacentCoordinateX, Y: adjacentCoordinateY}, &Point{X: sn[i].parent.x, Y: sn[i].parent.y}) parent := sn[i].parent for { parent = parent.parent if parent == nil { break } path = append(path, &Point{X: parent.x, Y: parent.y}) } // Reverse path slice for i := len(path)/2 - 1; i >= 0; i-- { opp := len(path) - 1 - i path[i], path[opp] = path[opp], path[i] } return path, nil } if isTileWalkable(p.collisionGrid, p.acceptableTiles, adjacentCoordinateX, adjacentCoordinateY) { existingNode, exists := p.coordinateToNode[hashKey] if exists { if sn[i].parent.costSoFar+sn[i].cost < existingNode.costSoFar { existingNode.costSoFar = sn[i].parent.costSoFar + sn[i].cost existingNode.parent = sn[i].parent } } else { n := newNode(adjacentCoordinateX, adjacentCoordinateY, p.endX, p.endY, sn[i].parent, sn[i].cost) p.coordinateToNode[hashKey] = n item := &pqueue.Item{Value: n, Priority: int64(n.bestGuessDistance() * costPrecision)} p.openList.Push(item) } } } } } return nil, errors.New("path not found") }