I'm having problems with a pathfinder (it's my first, so that was to be expected) : it doesn't always take the shortest way. For example, if I want to go one square down, the path will be : one square left, one down, one right.
public void getSquares(){
actPath = new String[Map.x][Map.y];
isDone = new boolean[Map.x][Map.y];
squareListener = new SquareListener[Map.x][Map.y];
getSquares2(x,y,0,new String());
}
public void getSquares2(int x, int y, int movesused, String path){
boolean test1 = false;
boolean test2 = false;
test1 = (x < 0 || y < 0 || x > Map.x || y > Map.y);
if(!test1){
test2 = Map.landTile[y][x].masterID != 11;
}
if(movesused <= 6 && (test1 || test2)){
addMoveSquare2(x,y, path);
getSquares2(x+1,y,movesused+1,path+"r");
getSquares2(x,y+1,movesused+1,path+"d");
getSquares2(x,y-1,movesused+1,path+"u");
getSquares2(x-1,y,movesused+1,path+"l");
}
}
public void addMoveSquare2(int x, int y, String path){
if(x >= 0 && y>=0 && x < Map.x && y < Map.y && (actPath[x][y] == null || actPath[x][y].length() > path.length())){
if(squareListener[x][y] == null){
actPath[x][y] = new String();
actPath[x][y] = path;
JLabel square = new JLabel();
square.setBounds(x*16,y*16,16,16);
square.setIcon(moveSquare);
squareListener[x][y] = new SquareListener(x,y,path);
square.addMouseListener(squareListener[x][y]);
Map.cases.add(square);
}
else{
squareListener[x][y].path = path;
}
}
}
SquareListener is a simple MouseListener which print the square's location and the path to it.
Map.x, Map.y are the map size.
getSquares2 is called with the start point, and draw every squares that are 6 moves away, and consider every case with the value "11" as obstacle.
Can you please help me finding what I've done wrong ?
Here is a screenshot of the result :
http://img808.imageshack.us/img808/96/screen.gif
The red squares are the possible goal. The real one will be defined only when the player click on one square (the MouseListener being SquareListener, it's supposed to know the path to take). The houses are the cases with a value of "11", the obstacles.
Your algorithm looks nearly correct. Nearly, because you forget to assign actPath[x][y] when a second path to the node is found, rendering your length check with actPath[x][y] incorrect. You should do:
else{
actPath[x][y] = path;
squareListener[x][y].path = path;
}
Your algorithm also has abominable time complexity, as it will iterate all paths of length 6 (all 4^6 = 4096 of them) instead of the just the shortest ones (6*6 + 5*5 = 61)
For inspiration, I recommend looking at Dijkstra's algorithm (the precursor to A*), which manages to only visit the shortest paths and concludes in O(number of reachable nodes) when path lengths are small integers as it the case here.
You can take a look here at my answer with example code for A-Star, not a direct answer but the code is readable and it points you to a good book that deals (among many other things) path finding. I never did get around to commenting the code...
Not sure what you mean, in the comment for Daniel, by "Thanks for the link, however, I don't have 1 goal but a number of moves, which makes a lot of possible goals."
You might be interested in this tutorial on the A* search algorithm.
Related
I have a problem requiring me to implement an algorithm finding path from a character to another character with obstacles along the way.
I know there are a lot of advanced pathfinding algorithms(A*, BFS, DFS,dijkstra....). However, I am struggling to implement all these concepts in my code after plenty of research and attempts, and also I don't think I am required to implement all these advanced algorithms.
"Shortest" path is not the requirement, and all I need is a path that can lead my character to another character by avoiding moving onto obstacles.
Can anyone give me an idea (maybe some algorithms better than backtracking)or useful website (similar examples) for this problem?
Any help would be much appreciated
I can recommend you the A* algortihm.
Its easy to implements the algorithm. For my A* i used the wikipedia code and the geekforgeek code.
I'll post my code aswell its in C# but very similiar to java:
public List<ANote> findPath(ANote start, ANote end)
{
if (start == null || end == null || start == end || !start.walkable || !end.walkable)
return null;
List<ANote> openSet = new List<ANote>();
List<ANote> closedSet = new List<ANote>();
start.parent = null;
openSet.Add(start);
start.h = getDistance(start, end);
while (openSet.Any())
{
openSet = openSet.OrderBy(o => o.f).ToList();
ANote current = openSet[0];
if (current == end)
break;
openSet.Remove(current);
closedSet.Add(current);
foreach (ANote neighbor in current.adjacted)
{
if (closedSet.Contains(neighbor))
continue;
double _gScore = current.g + 1; // For me every distance was 1
if (openSet.Contains(neighbor) && _gScore >= neighbor.g)
continue;
if (!openSet.Contains(neighbor))
openSet.Add(neighbor);
neighbor.parent = current;
neighbor.g = _gScore;
neighbor.h = getDistance(neighbor, end);
}
}
return reconstructPath(start, end);
}
private List<ANote> reconstructPath(ANote start, ANote end)
{
List<ANote> backNotes = new List<ANote>();
ANote current = end;
while (current.parent != null)
{
backNotes.Add(current);
current = current.parent;
}
return backNotes;
}
public class ANote
{
public ANote parent { get; set; }
public double f { get { return g + h; } }
public double g { get; set; }
public double h { get; set; }
public int x { get; set; }
public int y { get; set; }
public bool walkable { get; set; }
public List<ANote> adjacted { get; set; } = new List<ANote>();
public ANote(int x, int y)
{
this.x = x;
this.y = y;
walkable = true;
}
}
Important for this code is that you must define the adjacted nodes and which are walkable and what are not before you search.
I hope my code can help you to implement A* in your code.
Since I have no idea how your "Grid" is described, and what "Cell" is, I assume the grid is rectangular, the cells only map the objects on it, not the empty spaces.
I suggest you make an char[][] array = new char[rows][columns]; (or char) initialize it with some value and iterate over Cells, fill the 2D array in some meaningful manner, the example is G for goal, # for obstacle, etc. Then you start a DFS from Goal to look for Start.
You need to store the correct path somewhere, so you need a ArrayList list; variable too. Since it's a list, you can add items to it with list.add(item);, which is handy.
Non-optimal path: DFS
DFS is a really basic recursive algorithm, in your case it will go like this:
bool DFS(list, array, row, column):
if(array[row][column] == '#' or
array[row][column] == 'v') return False; # Obstacle or visited, ignore it
if( ... == 'S') return True; # It's the Start, path found
array[row][column] = 'v'; # mark as visited, nothing interesting.
# If you want the shortest path, you're supposed to put here the distance from goal,
#that you would pass on and increment as additional argument of DFS
#Check for edge cases, or initialize array to be bigger and place obstacles on edge#
if( DFS(list, array, row-1, column) ){ # If DFS fount a path to Start from cell above
list.add("Move Up"); # Then you add a direction to go below to the list
return True; # And then tell the previous DFS, that the path was found
}
if()
if()
if()
# And then you add the checks for the other directions in a similar manner
return False; # You didn't find anything anywhere
}
That is not the code, but it should be enough for you to do your assignement from there.
Chances are it'll find a path like this:
...→→→→↓
...↑.↓←↓
...S.F↑↓
......↑↓
......↑←
But in grids with a lot of obstacles or only one correct path it'll make more reasonable paths. Also you can improve it by selecting the order you try directions in so it always tries to go towards Goal first, but that's a pain.
Optimal path: augmented DFS
To find the shortest path usually people refer to A*, but I read up on it and it's not as I remember it and it's just unnecessarily complicated, so I'll explain an expanded DFS. It takes a little longer to find the answer, than A* or BFS would, but for reasonably-sized grids it's not noticeable.
The idea of the algorithm is to map the entire grid with distances to Goal and then walk from start to goal following decreasing distance.
First you will need to use int[][] array instead of char of the previous case. That is because you need to store distances, which char can too to some extent, but also non-distance markers in the grid, like obstacles and such.
The idea of the algorithm is you call DFS(array, row, col, distance), where distance is calculated as distance of the Cell that calls DFS incremented by 1. Then DFS in the next cell checks if the distance it was passed is smaller than its current distance, if it is so, then there was a shorter path found to that cell and you need to recalculate all its neighbors too. Otherwise the new path is longer and you can disregard it. By calling DFS recursively you will gradually map the entire maze.
After that you will call another function FindPath(list, array, row, col), that will check the Cell it started in and add a direction to the cell with neighbor.distance == (this.distance - 1) to the list and then call FindPath on that neighbor until distance is 0, at which point it's the goal.
It should look smth like this:
main()
{
# initialize grid with Integer.MAX_VALUE or just a big enough number
# for Cell in Cells -> put obstacles on Grid as -1,
# find the Start and Goal and record them somewhere
# DFS_plus(array, Goal, 0);
# FindPath(list, array, Start);
# Done
}
void DFS_plus(array, row, column, distance):
if(array[row][col] <= distance) return; # There already exists a shorter path there
# or it's an obstacle, we store obstacles as -1.
# It's smaller than any possible path and thus blocks further search
array[row][column] = distance; # update distance.
# If this happened its neighbors will need to be updated too.
#Check for edge cases, or initialize array to be bigger and place obstacles on edge#
DFS_plus(array, row-1, column, distance+1); # You just map everything, no returns expected
DFS_plus(); # For all 4 directions
DFS_plus();
DFS_plus();
}
FindPath(list, array, row, col){
if(array[row][col] == 0) return; # It's the Goal
if(array[row-1][col] == (array[row][col] - 1)){ # Check if Cell above is 1 closer to Goal
list.add("MoveUp"); # Add direction
FindPath(list, array, row-1, col); # Look for next direction
return; # You don't need to check other directions as path is guaranteed
}
if(){}; # Check other directions if Up wasn't the one
if(){};
if(){};
}
It is not much more complicated, but it gets you the shortest path. It's not the quickest way to find the shortest path, but it's relatively simple as any recursive algoithm.
I have looked everywhere for answers for fixing my code but after long hours spent trying to debug it I find myself hopelessly stuck. The problem is that my minimax function will not return the correct values for the best possible move, I even attempted to fix it by storing the best first moves (when depth = 0), but if the solution is not obvious, then the algorithm fails horribly. I also tried modifying the return values from the base cases in order to prioritize earlier wins, but this didn't solve the problem.
Currently I am testing the function on a TicTacToe board and the helper classes (Eg getMoves() or getWinner are working properly), I know my style is not the most efficient but I needed the code to be fairly explicit.
By adding a bunch of print statements I realized that under some circumstances my bestFinalMoves ArrayList was not modified, so this may be related to the issue. Another related problem is that unless the algorithm finds a direct win (in the next move), then instead of choosing a move that may lead to a future win or tie by blocking a square that leads to an immediate block, it just yields the space for the minimizing player to win.
For example on the board:
aBoard= new int[][] {
{0,1,0}, // 1 is MAX (AI), -1 is MIN (Human)
{-1,0,0},
{-1,0,0}
};
Yields the incorrect result of 2,0, where it is obvious that it should be 0,0, so that it blocks the win for the minimizing player, and the bestFinalMoves ArrayList is empty.
private result miniMaxEnd2(Board tmpGame, int depth){
String winner = tmpGame.whoWon();
ArrayList<Move> myMoves = tmpGame.getMoves();
if (winner == 'computer'){ //Base Cases
return new result(1000);
}else if (winner == 'human'){
return new result(-1000);
}
else if (winner == 'tie'){
return new result(0);
}
if (tmpGame.ComputerTurn) {//MAX
bestScore = -99999;
for (Move m : tmpGame.getMoves()){
Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
result aScore = miniMaxEnd2(newGame, depth+1);
if (aScore.score > bestScore) {
bestScore = aScore.score;
bestMove = m;
if (depth == 0) {
bestFinalMoves.add(m);
}
}
}
return new result(bestScore, bestMove);
} else {//MIN
bestScore = 99999;
for (Move m : tmpGame.getMoves()) {
Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
result aScore = miniMaxEnd2(newGame, depth + 1);
if (aScore.score < bestScore) {
bestScore = aScore.score;
bestMove = m;
}
}
return new result(bestScore,bestMove);
}
}
I know this was a long post, but I really appreciate your help. The full code can be accessed at https://github.com/serch037/UTC_Connect
The bestScore and bestMove variables must be declared as local variables inside the miniMaxEnd2 method for this logic to work properly.
Those variables' values are being replaced by the recursive call.
I need for my java-program a function that checks for polygon-collision, but the algorithms (for point-in-polygon) I tried were not correct for my needs, the degenerative cases are a problem for me.
This is what i try to reach with my program: I have 2 polygons and want to put them nearest possible together. I want to place them on their vertices and rotate them along the edge to fit optimal. Therefor I need a collision-detection, if they intersect or not.
My biggest problem is that those polygon-edges could be on the same point. The researched algorithms decide if it is in polygon a or b (mostly with y-value).
What I use
Polygon with double coordinates for x and y
standard java
no external librarys
My required rules:
polygons can have same edge and same vertices (can be on same boundary, but not complete polygon overlay)
the edges should not be allowed to intersect
it is not allowed, that one polygon is completly surrounded by another polygon (a hole).
(an optional very small epsilon in algorithm would be good, because rotating with double is not very exact)
I tried too the internal classes like Path2D.Double() with contains too without success to this problem.
The last algorithm (of about minimum of 8) i tried was this:
wiki.cizmar.org/doku.php?id=physics:point-in-polygon_problem_with_simulation_of_simplicity
This is C Code of the linked algorithm (last one I tried)
int i, j, c = 0;
for (i = 0, j = number_of_vertices-1; i < number_of_vertices; j = i++) {
if ( ((vertices[i].y>p.y) != (vertices[j].y>p.y)) &&
(p.x < (vertices[j].x-vertices[i].x) * (p.y-vertices[i].y) / (vertices[j].y-vertices[i].y) + vertices[i].x) )
c = !c;
}
return c;
My adapted JAVA code (Punkt=Point, Form.getCoords = List of Coordinates with x,y)
private boolean testPointInsidePolygon3c(Punkt p, Form f){
int number_of_vertices = f.getCoords().size();
int i, j = 0;
boolean odd = false;
for (i = 0, j = number_of_vertices-1; i < number_of_vertices; j = i++) {
if ( ((f.getCoords().get(i).getY() >p.getY()) != (f.getCoords().get(j).getY() >p.getY())) &&
( p.getX() < (f.getCoords().get(j).getX() -f.getCoords().get(i).getX())
* (p.getY() -f.getCoords().get(i).getY())
/ (f.getCoords().get(j).getY() -f.getCoords().get(i).getY())
+ f.getCoords().get(i).getX())
){
odd = !odd;
}
}
return odd;
}
To show that problem: here are pictures with 2 polygons. the blue vertices are the troublesomes.
Problem Example #1 example from another source
I hope you got some ideas, links, algorithm or anything for me. i got stucked too long with that problem ;-)
What a pity - i could not do a complete correct algorithm, that solves my problem.
That is why I now use the JTS-Library!
With overlaps and covers/within i got everything correct in my test-cases.
This is my first year with programming at university and we have just started using java. I've already wrote a bunch of codes for calculating "shortest" path through all points, but it has one problem. Sometimes the path will be overlapping each other. I have been looking for 2-opt swap, but have no clue on how to implement this to my code. Would be awesome with help. Here is my code for calculating distances between points ( cities ):
public void calculate(){
Point current = null;
current = points.get(0);
Point nearestPoint = null;
ArrayList<Point> remainingPoints = new ArrayList<Point>(points);
remainingPoints.remove(current);
lines.clear();
while(!remainingPoints.isEmpty()){
double minimumDistance = -1;
for (int i = 0; i < remainingPoints.size(); i ++){
if (minimumDistance == - 1 || current.distance(remainingPoints.get(i)) < minimumDistance){
minimumDistance = current.distance(remainingPoints.get(i));
nearestPoint = remainingPoints.get(i);
}
}
lines.add(new Point[] { current, nearestPoint });
remainingPoints.remove(current);
current = nearestPoint;
}
lines.add(new Point[] { points.get(0), current });
}
What does it do? Well it is quiet basic. It starts with the first point, then will find the nearest point. This will be saved in an array called lines. This will continue like this until no points are left. Line-array will then be sorted by distances so we can draw lines between them. My question is how can i prevent overlapping? See the links bellow for better description:
I dont want this
I want this
I am writing a snake game, specifically, is a centipede game. It needs me to draw a snake and that snake will automatically move one line by one line.
I did draw a snake, and it can move from left side to right side. However, the problem is:
I can't make the snake changes line, if it finish the first line, I need it changes to the second line and which starts from the right side.
My code is like this:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
myCentipedes[0].segments = new Point[Settings.centipedeStartSize];
myCentipedes[0].segments[0] = new Point(0, 0);
boolean dr = true;
if (dr == true) {
if (myCentipedes[0].segments[0].x < 30) {
System.out.println(myCentipedes[0].segments[0].x +
" " +
myCentipedes[0].segments[0].y);
myCentipedes[0].segments[0] = new Point(x, 0);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
x++;
}
}
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
myCentipedes[0].segments[0] = new Point(x, 1);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x + 1, 1);
}
x--;
}
}
}
It appears to me that you re-create your entire centipede on every single move:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
Is re-creating the centipede every move() intentional? Or should move() run the centipede entirely down the board, from start to finish? (If so, you'll need to add some looping to this method.)
I assume the myCentipedes[0] is simply a placeholder for future extensions, involving two or more centipedes on the board simultaneously. This sort of over-generic programming can sometimes make the code more difficult to read and write while initially programming, and almost certainly doesn't help matters. You can always re-factor a move() method that works on one centipede to a move(int centipede) method that works on a specific centipede and a move() method that calls move(int) for every centipede on the board. Or maybe you'll find it easier to place the movement code into the Centipede class, and need to remove the array indexes then and use class member storage instead.
boolean dr = true;
if (dr == true) {
dr will always equal true at this point. You might as well remove the variable and the test.
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
Since you're counting up, you'll actually copy the value from segment[0] through to all elements in the array, one element at a time. Can't you just assign the Point objects new array indexes? Starting from i=centipede.segments.length and counting down, it'll look more like this:
for (int i=myCentipede[0].segments.length; i > 0; i--) {
myCentipede[0].segments[i] = myCentipede[0].segments[i-1];
}
myCentipede[0].segments[0] = new Point(...,...);
Some of your tests can be simplified:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
If dr == false at this point, you might as well have written it like this instead:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
if (myCentipedes[0].segments[0].x > 0) {
But then the second if is obviously not needed -- after all, 29 > 0.
While you're here, clean up all those hard-coded 10 with either a constant (Settings.centipedeStartSize) or find the actual length of the centipede (myCentipedes[0].segments.length).
Now that I've critiqued your current approach, I'd like to suggest a different tack:
Take a step back and break your problem down into smaller methods.
You've embedded two for loops that move the centipede one segment at a time by assigning to segment[i] the values from segment[i-1]. Instead of duplicating the code, write a new method with the body of the for loop to move the centipede forward. Make it take a Point object for the new first element each trip through the function. (Don't forget to make it count down rather than up.)
Once you've broken apart the for loops, I think it will be easier to make whatever changes are necessary for traveling left-to-right and right-to-left. You will probably want to write it with nested for loops -- one to control the vertical dimension, and within it, perhaps one or two new for loops to control the horizontal dimension. Make these loops work with a simple Centipede c, rather than the complicated expression you've currently got.
Breaking apart the larger function into smaller function will give you a better opportunity to test your functions in isolation -- test movement manually, with simple test methods like this:
move_forward(Centipede c, Point p) {
/* code to move forward one space to occupy `p` */
}
test_right() {
Centipede c = new Centipede(/* ... */);
move_forward(c, new Point(0,0));
move_forward(c, new Point(1,0));
move_forward(c, new Point(2,0));
move_forward(c, new Point(3,0));
move_forward(c, new Point(4,0));
move_forward(c, new Point(5,0));
/* ... */
}
Take it slow, test every method as you write them, and I think you'll find this is an easier problem than it currently looks.