-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
base: master
Are you sure you want to change the base?
Conversation
Can you review and fix the above issue ? @ivanmayes |
Nice work! 👏 It actually solved the problem I had! PS: The same logic could be applied for |
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:
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:
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. Happy travels, fellow internet wanderer 👋 |
@MajesticGoodness 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'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! |
I found a demo file, you can take a look. |
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @param {number} opt.avoidStarcasing Add penalties to discourage turning and | |
* @param {boolean} opt.avoidStaircase Add penalties to discourage turning and |
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<label class="option_label">Avoid staircasing</label> <br> | |
<label class="option_label">Avoid staircase</label> <br> |
Refactored this from #32 into the
src
and added a configuration to set what the turn penalty is to enforce even more straight paths.