Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add penalties for turns to avoid staircasing in A* algorithm #150

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ivanmayes
Copy link

Refactored this from #32 into the src and added a configuration to set what the turn penalty is to enforce even more straight paths.

@cuixiping
Copy link

This PR doesn't work perfectly. For example:
image
In this case, the result is not the best path.

@cuixiping
Copy link

Refactored this from #32 into the src and added a configuration to set what the turn penalty is to enforce even more straight paths.

Can you review and fix the above issue ? @ivanmayes

@piotrmitrega
Copy link

Nice work! 👏 It actually solved the problem I had!

PS: The same logic could be applied for BiAStarFinder which gives you path with even less turns 😁

@MajesticGoodness
Copy link

MajesticGoodness commented Jan 22, 2024

Thanks so much for the fix. By itself, it works surprisingly well.

I'm trying to recreate the path finding of an old school game and added some tweaks to improve the behavior to match up with the expected result like @cuixiping pointed out.

In particular, when two moves are tied, this game's path finding prefers:

  1. vertical movements before horizontal ones
  2. prefers to move right instead of left
  3. prefers to move up instead of down

I implemented a tiebreaker to be able to replicate these behaviors. I also added a momentum to paths, so that 'straighter' paths receive a small reward.

The 'solution,' if we can call it that, wasn't particularly pretty. I ended up doing the following:

  1. Run A*.
  2. Block the first tile that A* took in the last iteration.
  3. Run A* again.
  4. Now, compare the f-scores of the two paths. Return the path which has the lowest f-score.

I'm not sure if there's a way to coerce A* into taking the optimal path on the first iteration. I kept running into the problem where the algorithm would get tunnel-visioned on one particular path and completely ignore exploring the alternatives. A* will forsake considering a more optimal route if the route it's going down is 'optimal enough'. But many times that 'optimal enough' route isn't the one we want, and it often looks a lot like what @cuixiping posted.

On the bright side, I don't think there should be too much of a loss in performance with an extra iteration (hopefully). If your use case is a very large grid, you might see a bit of a slowdown.

Updated demo
Examples

Happy travels, fellow internet wanderer 👋

@cuixiping
Copy link

@MajesticGoodness
Could you show/share your game here?

I wrote a A* demo of finding shortest and least turns path years ago, and I may not be able to find the old code.
I used a different Grid/Node structure and consider the turns affect the heuristic value.

@MajesticGoodness
Copy link

@MajesticGoodness Could you show/share your game here?

I wrote a A* demo of finding shortest and least turns path years ago, and I may not be able to find the old code. I used a different Grid/Node structure and consider the turns affect the heuristic value.

I'm sorry to hear you haven't been able to locate your old source code. Sadly, I have none of my own to share.

I'm merely creating a bot for this particular game, and I needed to replicate its path finding so that my bot would know in advance which moves would be advantageous. The game is very dead and no one plays anymore 😔. My hope is to at least populate it with bots so that the few people who do still play have a slightly better experience.

If you are curious about the game, you can check out some game play footage here. Take care!

@cuixiping
Copy link

I found a demo file, you can take a look.
https://cuixiping.github.io/demo/astar-findpath-v3.html

a-star find best path (least turns)

pwrstudio added a commit to pwrstudio/PathFinding.js that referenced this pull request Mar 7, 2024
@@ -16,6 +16,10 @@ var DiagonalMovement = require('../core/DiagonalMovement');
* (defaults to manhattan).
* @param {number} opt.weight Weight to apply to the heuristic to allow for
* suboptimal paths, in order to speed up the search.
* @param {number} opt.avoidStarcasing Add penalties to discourage turning and

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param {number} opt.avoidStarcasing Add penalties to discourage turning and
* @param {boolean} opt.avoidStaircase Add penalties to discourage turning and

Comment on lines +112 to +113
lastDirection = node.parent === undefined? undefined : { x : node.x - node.parent.x, y : node.y - node.parent.y };
var turned = lastDirection === undefined? 0 : lastDirection.x !== x - node.x || lastDirection.y !== y - node.y;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lastDirection = node.parent === undefined? undefined : { x : node.x - node.parent.x, y : node.y - node.parent.y };
var turned = lastDirection === undefined? 0 : lastDirection.x !== x - node.x || lastDirection.y !== y - node.y;
lastDirection = node.parent === undefined ? undefined : { x: node.x - node.parent.x, y: node.y - node.parent.y };
var turned = lastDirection === undefined ? 0 : lastDirection.x !== x - node.x || lastDirection.y !== y - node.y;

<label class="option_label">Weight</label> <br>
<br>
<input type="checkbox" class="avoid_staircase">
<label class="option_label">Avoid staircasing</label> <br>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<label class="option_label">Avoid staircasing</label> <br>
<label class="option_label">Avoid staircase</label> <br>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants