Optimal algorithm to move a a rope from one position to another
Your bolded question What is the optimal algorithm is off-topic for Code Review. If you're really interested in original-research answers to that question, I think it might plausibly be on-topic for Puzzling SE or Computer Science SE.

Certainly if you post in either of those places, looking for "optimal" algorithms, you will have to define what you mean by "optimal." The simplest way of doing that would also be useful on CodeReview — and also in general in your programming career! Provide test cases.

assert solve([2, 4, 6, 3], [-2, -4, -6, -3], 3) == 42


This test case was constructed by looking at your sample program and then filling in an utterly random number 42 in the one place that matters. When you post the question elsewhere (and/or here again), make sure to have that number filled in.
And then give some other test cases!

assert solve([2, 4, 6, 3], [-2, -4, -6, -3], float('inf')) == 4
assert solve([1, 1, 1], [0, 0, 0], 1) == 3


And then consider what should happen in cases of "invalid input":

assert solve([1, 1, 1], [0, 0, 0], 0) is None
assert solve([1, 2, 1], [1, 3, 1], 1) is None
assert solve([1, 3, 1], [1, 2, 1], 1) is None
assert solve([1, 3, 1], [1, 3, 1], 1) is None




On your code itself, try to write out full identifiers instead of abbreviations: index (index of what?) instead of ind, for example.

When writing a "predicate" function that returns bool, give it a name that indicates the predicate, rather than an action verb: instead of check_legal (which should really be check_legality), prefer is_legal, so that you can write

assert is_legal(init, max_dist)


Notice that max_dist has no reason to be a keyword argument, and no reason to be optional. Instead of passing None and special-casing it, just pass float('inf') and don't write any special cases.



pos_options = [final[ind]]\
                  +[n+sign*max_dist for n in neighbors]


This line of code is impenetrable, due to the lack of whitespace and the backslash in the middle. I'd at least recommend

pos_options = [final[ind]] + [n + sign * max_dist for n in neighbors]


and then look for a way to refactor that or at least put a code comment explaining the logic behind the expression.