0

A frog wants to cross a river.

There are 3 stones in the river she can jump to.

She wants to choose among all possible paths the one that leads to the smallest longest jump.

Ie. each of the possible paths will have one jump that is the longest. She needs to find the path where this longest jump is smallest.

The 2 shores are 10 apart and are parallel to the y axis.

Each stone position is given by a list x=[x1,x2,x3] of the x positions and y=[y1,y2,y3] of the y positions.

Return both the longest jump in this path (rounded to the closest integer) and the path itself through a list of indices in the lists x and y of the stones in the path.

Here it is my python code to find the longest jump.

How would I track the path itself?

And my code looks clumsy with 3 nested loops is there a better/more elegant way to write this code?

def longestJump(x, y):
        best = 10
        for i in range(0,3):           
            for j in range(0,3):  
                for k in range(0,3):                
                   # first jump from shore to a stone
                   dist = x[i] 
                   # second jump between stones
                   dist = max(dist, round(math.sqrt((x[i]-x[j])**2 + (y[i]-y[j])**2))) 
                   # third jump between stones
                   dist = max(dist, round(math.sqrt((x[i]-x[k])**2 + (y[i]-y[k])**2))) 
                   dist = max(dist, round(math.sqrt((x[j]-x[k])**2 + (y[j]-y[k])**2)))
                   # last jump from a stone to the opposite shore 
                   dist = max(dist, 10 - x[j])
                   best = min(dist, best)
        return best
user35202
  • 389
  • 1
  • 10
  • 1
    What if the best path doesn't go through all 3 stones? – user2357112 Apr 06 '15 at 00:53
  • Yes good point. It can go through only one but I think the solution above takes that into account. – user35202 Apr 06 '15 at 01:02
  • Your solution doesn't take that into account. Inside the three loops, you compute the distance from one shore to `i`, the distance from `i` to `j`, the distance from `i` to `k`, the distance from `j` to `k`, and the distance from `j` to the other shore. This is neither a coherent path nor an exhaustive consideration of all possible jumps among `i`, `j`, `k`, and the shores. – abcd Apr 06 '15 at 01:19
  • also, see my comment for the first answer. your code won't even run as it stands without raising an error, due to the use of `range(0, 4)`. i'd recommend taking an arrangement of stones with a known answer, writing a test function that tests whether `longestJump` returns the correct answer, and the editing `longestJump` until the test passes. – abcd Apr 06 '15 at 01:21
  • if you rewrite your code so that a coherent path is tested on each iteration (or a set of coherent paths), a way of tracking that path will be revealed. – abcd Apr 06 '15 at 01:26

2 Answers2

0

You don't need to take the square-root except for the final result. Just compute "distance squared" and compare with that.

Not sure what you are calling "round" either. That would potentially create a bug.

Also, don't you need to skip all cases of "i == j" from the inner loop?

def longestJump(x, y):
        best = 10
        for i in range(0,3):           
            for j in range(0,3):  
                for k in range(0,3):                
                   # first jump from shore to a stone
                   dist = x[i] 
                   # second jump between stones
                   dist = max(dist, (x[i]-x[j])**2 + (y[i]-y[j])**2)
                   # third jump between stones
                   dist = max(dist, (x[i]-x[k])**2 + (y[i]-y[k])**2) 
                   dist = max(dist, x[j]-x[k])**2 + (y[j]-y[k])**2)
                   # last jump from a stone to the opposite shore 
                   dist = max(dist, 10 - x[j])
                   best = min(dist, best)
        return math.sqrt(best)
user35202
  • 389
  • 1
  • 10
selbie
  • 100,020
  • 15
  • 103
  • 173
  • why are you using `range(0, 4)`? there are only three entries in `x`. hence, the max index is 2. `range(0, 3)` is what you should use. – abcd Apr 06 '15 at 01:02
  • Every path could be represented by a tuple: `(i,j,k)`. So every time you compute a new "best", you have a new "best_path" – selbie Apr 06 '15 at 01:33
  • @dbliss - not sure. That's what the OP's original code was. – selbie Apr 06 '15 at 01:35
0

You can simplify the three loops by using itertools.permutations on a range. That will return a three-tuple if you pass it a range of length 3.

As for keeping track of the path, I think it would be much easier if you used an actual if statement to compare the largest jump lengths from each path to the best you've seen so far, rather than using min. In an if, you can also save additional information (such as the path that has the smallest largest jump) at the same time you're saving that jump's length.

def longestJump(x, y):
    best_jump = 10 # infinity
    best_path = ()
    for i, j, k in itertools.permutations(range(3)):           
        jump0 = x[i]                                      # shore to i
        jump1 = sqrt((x[i]-x[j])**2 + (y[i]-y[j])**2)     # i to j
        jump2 = sqrt((x[j]-x[k])**2 + (y[i]-y[j])**2)     # j to k
        jump3 = 10 - x[k]                                 # k to far shore
        longest = max(jump0, jump1, jump2, jump3)
        if longest < best_jump:
            best_jump = longest
            best_path = (i, j, k)
    return best_jump, best_path

This always expects the path to use all three stones. If that's not required, you may want to iterate over permutations of the each subset of the stones. I'm not sure if there's a particularly easy way to do that, but you could try combining itertools.combinations and the permutations code above.

Blckknght
  • 100,903
  • 11
  • 120
  • 169