A Mars rover plans a drive across a boulder field with a rapidly-exploring random tree (RRT). To make the planner repeatable, its "random" points are given as a list samples. Positions are in metres; each boulder is a disc (cx, cy, r).
The tree starts with the single node start (node 0, no parent). If start is already within goal_radius of goal (distance <= goal_radius), the plan is just [start]. Otherwise take the samples in order; for each sample:
- Nearest. Find the tree node nearest to the sample (straight-line distance; on a tie, the node added earliest). If the sample is that node (distance 0), skip the sample.
- Steer. If the sample is within
stepof that node (distance<= step), the new point is the sample; otherwise it is the pointstepmetres from the node toward the sample. - Collide. If the segment from the node to the new point comes within or onto any boulder (the shortest distance from the boulder's centre to the segment is
<= r), skip the sample: the tree does not change. - Add the new point as a node whose parent is the nearest node.
- Goal. If the new node is within
goal_radiusofgoal(<=), stop: return the path of nodes fromstartto the new node, following the parents.
If the samples run out first, return None. Return the path as a list of (x, y) tuples.
The setup provides scatter(n, seed, width, height): n sample points spread over the rectangle [0, w] \times [0, h], the same on every device. The larger tests use it. Press Run with plot(xs, ys) on your path to see the route.
Examples
Input: start = (0, 0), goal = (3, 0), obstacles = [], samples = [(5, 0), (5, 0), (5, 1)],
step = 1, goal_radius = 0.5
Output: [(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (2.948683298050514, 0.31622776601683794)]
Explanation: two steps along the x axis; the third grows from (2, 0) toward (5, 1)
and ends 0.32 m from the goal.
Input: start = (0, 0), goal = (4, 0), obstacles = [(2, 0, 0.5)],
samples = [(4, 0), (1, 2), (4, 2), (4, 0), (4, 0)], step = 1.5, goal_radius = 0.5
Output: [(0.0, 0.0), (0.6708203932499369, 1.3416407864998738), (2.142323497022232, 1.6326366895440598),
(3.2690308160687436, 0.6424192299893302), (4.0, 0.0)]
Explanation: the first sample would end the branch at (1.5, 0), exactly 0.5 m from the
boulder's centre: touching counts, so it is skipped. The tree climbs over the boulder.
Input: start = (0, 0), goal = (4, 0), obstacles = [(2, 0, 0.5)], samples = [(4, 0), (1, 2)],
step = 1.5, goal_radius = 0.5
Output: None
Constraints
startlies outside every boulder; answers are compared with a tolerance of1e-6
Goals
- Grow a rapidly-exploring random tree from a given list of samples, one rule at a time
- Reject a branch whose segment comes within an obstacle's radius
- Recover the path from the tree by following parent links back to the root