at the Moment i do a 2D strategy game using pathfinding to navigate my Units over the (still small) tilemap. The tiles are 32x32 and the map is 50x100 big so ist very small :) . It works all so far but i have the more laggs the more Units i create. Till 30 Units it works as it should but more makes my Programm lagg very strong.
So i use an ArrayList for my openSet and (after doing some googling) i know thats bad. So i need to Keep my openList sorted by using TreeSet, but by using TreeSet its necessary to Override compareTo(). Im not fit enough with comparisions like this.
What must i compare exactly, the f value or the Signum? I dont know that and i Need some help.
Here is the A* Algorithm:
public static List<Tile> findPath(int startx,int starty,int endx,int endy){
for(int i = 0; i < width; i++){
for(int j = 0;j < height;j++){
tiles[i][j] = new Tile(i,j,size,size,obstacles[i][j],false);
}
}
for(int i = 0; i < width; i++){
for(int j = 0;j < height;j++){
tiles[i][j].addNeighbours(tiles,width,height);
}
}
List<Tile> openList = new ArrayList<Tile>(); // Here i want a TreeSet
HashSet<Tile> closedList = new HashSet<Tile>();
List<Tile> path = null;
Tile start = tiles[startx][starty];
Tile end = tiles[endx][endy];
Tile closest = start;
closest.h = heuristic(closest,end);
openList.add(start);
while(!openList.isEmpty()) {
int winner = 0;
for (int i = 0; i < openList.size(); i++) {
if (openList.get(i).f < openList.get(winner).f) {
winner = i;
}
}
Tile current = openList.get(winner);
openList.remove(current);
if (current == end) {
path = new ArrayList<Tile>();
Tile tmp = current;
path.add(tmp);
while (tmp.previous != null) {
path.add(tmp);
tmp = tmp.previous;
}
return path;
}
closedList.add(current);
List<Tile> neighbours = current.neighbours;
for (int i = 0; i < neighbours.size(); i++) {
Tile neighbour = neighbours.get(i);
int cost = current.g + heuristic(current,neighbour);
if (openList.contains(neighbour) && cost < neighbour.g) {
openList.remove(neighbour);
}
if (closedList.contains(neighbour) && cost < neighbour.g) {
closedList.remove(neighbour);
}
int newcost = heuristic(neighbour, end);
if (!openList.contains(neighbour) && !closedList.contains(neighbour) && !neighbour.obstacle) {
neighbour.h = newcost;
if (neighbour.h < closest.h) {
closest = neighbour;
}
}
if (!openList.contains(neighbour) && !closedList.contains(neighbour) && !neighbour.obstacle) {
neighbour.g = cost;
openList.add(neighbour);
neighbour.f = neighbour.g + neighbour.h;
neighbour.previous = current;
}
}
}
Tile tmp = closest;
path = new ArrayList<Tile>();
path.add(tmp);
while (tmp.previous != null) {
path.add(tmp);
tmp = tmp.previous;
}
return path;
}
public static int heuristic(Tile A,Tile B) {
int dx = Math.abs(A.x - B.x);
int dy = Math.abs(A.y - B.y);
return 1 * (dx + dy) + (1 - 2 * 1) * Math.min(dx,dy);
}
And i have another Problem. I load the whole entire map inclusive ist obstacle during calling the finPath-Method, but i didnt find another solution, where i can load it only once. And i really tried a lot believe me... .
So here my two Questions:
What must i exactly compare within the compareTo Method to make it work?
Where can i load my TiledMap once, so A* havent got to update it during it is called?
Related
I have two 2d boolean arrays, the smaller array (shape) is going over the larger array (world).
I am having trouble to find a method to find out when the smaller array can "fit" into the larger one.
When I run the code it either just goes through the larger array, never stopping, or stops after one step (incorrectly).
public void solve() {
ArrayList<Boolean> worldList=new ArrayList<>();
ArrayList<Boolean> shapeList=new ArrayList<>();
for (int i = 0; i < world.length; i++) {
for (int k = 0; k < world[i].length; k++) {
worldList.add(world[i][k]);
display(i, k, Orientation.ROTATE_NONE);
for (int j = 0; j < shape.length; j++) {
for (int l = 0; l < shape[j].length; l++) {
shapeList.add(shape[j][l]);
if(shapeList.equals(worldList)) {
return;
}
}
}
}
}
}
A good place to start with a problem like this is brute force for the simplest case. So, for each index in the world list, just check to see if every following index of world and shapes match.
Notice we only iterate to world.size()-shapes.size(), because naturally if shapes is longer than the portion of world we haven't checked, it won't fit.
import java.util.ArrayList;
public class Test {
ArrayList<Boolean> world = new ArrayList<>();
ArrayList<Boolean> shapes = new ArrayList<>();
public static void main(String[] args) {
new Work();
}
public Test() {
world.add(true);
world.add(false);
world.add(false);
world.add(true);
shapes.add(false);
shapes.add(true);
// Arraylists initialized to these values:
// world: T F F T
// shapes: F T
System.out.println(getFitIndex());
}
/**
* Get the index of the fit, -1 if it won't fit.
* #return
*/
public int getFitIndex() {
for (int w = 0; w <= world.size()-shapes.size(); w++) {
boolean fits = true;
for (int s = 0; s < shapes.size(); s++) {
System.out.println("Compare shapes[" + s + "] and world["+ (w+s) + "]: " +
shapes.get(s).equals(world.get(w+s)));
if (!shapes.get(s).equals(world.get(w+s))) fits = false;
}
System.out.println();
if (fits) return w;
}
return -1;
}
}
When we run this code, we get a value of 2 printed to the console, since shapes does indeed fit inside world, starting at world[2].
You can find the row and column of fitting like this
public void fit() {
int h = world.length - shape.length;
int w = world[0].length - shape[0].length;
for (int i = 0; i <= h; i++) {
for (int k = 0; k <= w; k++) {
boolean found = true;
for (int j = 0; j < shape.length && found; j++) {
for (int l = 0; l < shape[j].length && found; l++) {
if (shape[j][l] != world[i + j][k + l])
found = false;
}
}
if (found) {
//Your shape list fit the world list at starting index (i, k)
//You can for example save the i, k variable in instance variable
//Or return then as an object for further use
return;
}
}
}
I am having trouble creating a Genetic Algorithm in java. I am competing in an online GA contest. I am trying to save the best result each time back into index 0, but it just becomes a reference to the original index. Meaning when I evolve the rest of the indexes, if it evolves the best members original index I lose it.
I have tried shimming it with a getClone method that converts the objects data to and int array and creates a new object from it.
Individual class:
class Individual {
public int[] angle;
public int[] thrust;
public double fitness;
public Individual(){
angle = new int[2];
thrust = new int[2];
for (int i = 0; i < 2; i++) {
this.angle[i] = ThreadLocalRandom.current().nextInt(0, 37) - 18;
this.thrust[i] = ThreadLocalRandom.current().nextInt(0, 202);
this.thrust[i] = ( (this.thrust[i] == 201) ? 650 : this.thrust[i] );
}
this.fitness = Double.MIN_VALUE;
}
public Individual(int[][] genes, double f){
this.fitness = f;
angle = new int[2];
thrust = new int[2];
this.angle[0] = genes[0][0];
this.angle[1] = genes[0][1];
this.thrust[0] = genes[1][0];
this.thrust[1] = genes[1][1];
}
public Individual getClone() {
int[][] genes = new int[2][2];
genes[0][0] = (int)this.angle[0];
genes[0][1] = (int)this.angle[1];
genes[1][0] = (int)this.thrust[0];
genes[1][1] = (int)this.thrust[1];
return ( new Individual(genes, this.fitness) );
}
public Individual crossover(Individual other) {
int[][] genes = new int[2][2];
genes[0][0] = (int)( (this.angle[0] + other.angle[0])/2 );
genes[0][1] = (int)( (this.angle[1] + other.angle[1])/2 );
genes[1][0] = ( (this.thrust[0] == 650 || other.thrust[0] == 650) ? 650: (int)( (this.thrust[0] + other.thrust[0])/2 ) );
genes[1][1] = ( (this.thrust[1] == 650 || other.thrust[1] == 650) ? 650: (int)( (this.thrust[1] + other.thrust[1])/2 ) );
return ( new Individual(genes, Double.MIN_VALUE) );
}
public void mutate() {
for (int i = 0; i < 2; i++) {
if(ThreadLocalRandom.current().nextInt(0, 2)==1) {
this.angle[i] = ThreadLocalRandom.current().nextInt(0, 37) - 18;
}
if(ThreadLocalRandom.current().nextInt(0, 2)==1) {
this.thrust[i] = ThreadLocalRandom.current().nextInt(0, 202);
this.thrust[i] = ( (this.thrust[i] == 201) ? 650 : this.thrust[i] );
}
}
}
Population class:
class Population {
public Individual[] individuals;
public Population(int populationSize) {
individuals = new Individual[populationSize];
for (int i = 0; i < populationSize; i ++) {
individuals[i] = new Individual();
}
}
public void resetFitness() {
for (int i = 0; i < individuals.length; i++) {
individuals[i].fitness = Double.MIN_VALUE;
}
}
public void setIndividual(int i, Individual indiv) {
individuals[i] = indiv.getClone();
}
public Individual getIndividual(int i) {
return individuals[i].getClone();
}
public int size() {
return this.individuals.length;
}
public Individual getFittest() {
int fittest = 0;
// Loop through individuals to find fittest
for (int i = 0; i < individuals.length; i++) {
if (individuals[i].fitness > individuals[fittest].fitness) {
fittest = i;
}
}
return individuals[fittest].getClone();
}
}
The necessaries from the sim class:
class simGA {
private Population pop;
private final static int TSIZE = 5; //tournement size
public simGA (int poolsize) {
this.pop = new Population(poolsize);
}
public Individual search(int generations, int totalMoves) {
//this.pop.resetFitness();
for (int g = 0; g < generations; g++) {
for (int i = 0; i < this.pop.individuals.length; i++) {
this.pop.individuals[i].fitness = sim(this.pop.individuals[i],totalMoves);
}
System.err.print("Generation " + g + " ");
this.pop = evolvePopulation(this.pop);
}
return pop.getFittest();
}
private Population evolvePopulation(Population p) {
//save fittest
Population tempPop = new Population(p.individuals.length);
tempPop.setIndividual(0, p.getFittest().getClone() );
System.err.print("Best move: " + tempPop.individuals[0].fitness);
System.err.println();
for (int i = 1; i < p.individuals.length; i++) {
Individual indiv1 = tournamentSelection(p);
Individual indiv2 = tournamentSelection(p);
Individual newIndiv = indiv1.crossover(indiv2);
newIndiv.mutate();
tempPop.setIndividual(i, newIndiv.getClone() );
}
return tempPop;
}
// Select individuals for crossover
private Individual tournamentSelection(Population pop) {
// Create a tournament population
Population tournament = new Population(TSIZE);
// For each place in the tournament get a random individual
for (int i = 0; i < TSIZE; i++) {
int randomId = ThreadLocalRandom.current().nextInt(1, this.pop.individuals.length);
tournament.setIndividual(i, pop.getIndividual(randomId).getClone() );
}
// Get the fittest
return tournament.getFittest().getClone();
}
private double sim(Individual s, int moves) {
return score; //score of simmed moves
}
How can I make sure that the best individual is getting saved, not as a reference? When I error print the best score, sometimes it is lost and a worse scoring move is chosen. I don't think it is necessarily a object cloning issue, I can clone the game objects that are simulated just fine, resetting them each run.
As I said, this is for a contest, so I cannot use any libraries on the site, and also is the reason I am not posting the full code, the intricacies of the simulator it self that scores the moves are not to be just given away. But suffice it to say the scores come back as expected for the move when worked out on paper.
I response to NWS, I thought my getClone method was doing a deep copy.
Reference used beside wiki and other knowledge on Genetic Algorithms: http://www.theprojectspot.com/tutorial-post/creating-a-genetic-algorithm-for-beginners/3
I have fixed it by not resimming the individual at index 0. However this means there are other issue with my code not related to the question.
Individual newIndiv = indiv1.crossover(indiv2);
Above line is resetting the fitness to Double.MIN_VALUE. So, whenever evolvePopulation is called, only individual at index 0 is fittest.
I have fixed it by not resimming the individual at index 0. However this means there are other issue with my code not related to the question, since resimming the same individual from the same point in time as before should not change it's fitness.
I tried writing a maze solution method using DFS to find a path through a maze that's generated. But I'm having trouble with it. It doesn't even look like it ever finishes the traversal. Here is some output from a sample run. The maze looks like this:
+ +--+--+--+
| | |
+ +--+ + +
| | |
+--+--+--+ +
| | |
+ + + +--+
| | |
+--+--+--+ +
And my DFS method produces this:
0 1 5 9
In the end, I want to display that same maze but with numbers inside of it's path that represent the order which I have visited and ran through it.
Anyway, here's my code:
public static void depthFirstSearch(){
boolean[] visited = new boolean[totalCells]; // marks which vertices have been visited during the search
Stack<Vertex> st = new Stack<Vertex>();
st.push(graph[0][0]);
while(!st.isEmpty()){
Vertex v = st.pop();
if(!visited[v.label]){
visited[v.label] = true;
System.out.print(v.label + " ");
// auxiliary stack to visit neighbors in the order which they appear
Stack<Vertex> auxStack = new Stack<Vertex>();
for(Vertex w : v.neighbors){
if(!visited[w.label]){
auxStack.push(w);
}
}
while(!auxStack.isEmpty()){
st.push(auxStack.pop());
}
}
}
System.out.println();
}
Here is also the Vertex:
class Vertex{
int label;
int x;
int y;
boolean isVisited = false;
boolean hasNorthWall = true;
boolean hasSouthWall = true;
boolean hasEastWall = true;
boolean hasWestWall = true;
boolean hasAllWalls = true;
ArrayList<Vertex> neighbors = new ArrayList<Vertex>();
public Vertex(int x, int y){
this.x = x;
this.y = y;
}
}
And my constructor:
public Maze(int size)
{
this.SIZE = size;
totalCells = SIZE * SIZE;
cellStack = new Stack<Vertex>();
graph = new Vertex[SIZE][SIZE];
}
Thank you in advance for any help!
EDIT: Adding how neighbors are assigned.
public void assignNeighbors(Vertex v)
{
//This handles the cell north of current cell
if(v.y != 0)
{
v.neighbors.add(graph[v.x][v.y-1]);
}
//This handles the cell south of the current cell
if(v.y != (SIZE-1))
{
v.neighbors.add(graph[v.x][v.y+1]);
}
//This handles the cell left of the current cell
if(v.x != 0)
{
v.neighbors.add(graph[v.x -1][v.y]);
}
//right of the current
if(v.x != SIZE-1)
{
v.neighbors.add(graph[v.x + 1][v.y]);
}
}
EDIT2: Adding in how the label is assigned (it just stores the vertex number)
public void fill()
{
int vertexNumber = 0;
//This loop creates a new vertex
for(int i=0; i < SIZE; i++)
{
for(int j = 0; j < SIZE; j++)
{
Vertex v = new Vertex(j,i);
graph[j][i] = v;
}
}
//adds values to vertex
for(int i = 0; i < SIZE; i++)
{
for(int j = 0; j < SIZE; j++)
{
graph[j][i].label = vertexNumber;
vertexNumber++;
}
}
//This loop assigns the neighbors
for(int i = 0; i < SIZE; i++)
{
for(int j = 0; j < SIZE; j++)
{
assignNeighbors(graph[j][i]);
}
}
mazeGenerator();
}
I'm not quite sure about this part
for(Vertex w : v.neighbors){
if(!visited[w.label]){
auxStack.push(w);
}
}
while(!auxStack.isEmpty()){
st.push(auxStack.pop());
}
If I'm correct you can replace this with just one loop but this shouldn't be the problem. Have you tried debugging it step by step? You know how the maze looks like and thus you know how the alghoritm should behave in every step. I suggest you try it and then maybe update your post and describe at which step your algorithm behaves weird.
I wanted to add this as comment but I lack the reputation.
I have an ArrayList with a lot of points (so x,y).
I sorted the points on XY.
Is there a datatype/algorithm to get all y points a certain x fast? (or the other way around, all x on a certain y).
At the moment I have something like this, which works ok but I have the feeling it's to complex for what I need.
int lastXPos;
int lastIndex;
int[] workArray = new int[4096];
int workArrayIndex;
// returns all the y values where x matches
public int[] grab(int xPos) {
workArrayIndex = 0;
int startIndex = 0;
// this can increase speed a lot
if (lastXPos+1 == xPos) {
startIndex = lastIndex+1;
}
PVector v;
for (int i = startIndex; i < vecs.size(); i++) {
v = vecs.get(i);
if (v.x > xPos) {
lastIndex = i-1;
break;
}
if (v.x == xPos) {
workArray[workArrayIndex++] = (int) v.y;
}
}
lastXPos = xPos;
int[] result = new int[workArrayIndex];
for (int i = 0; i < workArrayIndex; i++) {
result[i] = workArray[i];
}
return result;
}
Edit:
One more thing, it has to process a new list 60 times a second, so creating the data object also has to be fast.
Then as a bonus question, we have rows and columns, is there a way to describe both of those? (direction for example).
I have two arrays that I create like this:
public int GameBoard[][] = new int[30][14];
public int DirectionMap[][] = new int[30][14];
I then initialize the arrays like this:
for (int i = 0; i < GameBoard.length; i++)
{
for (int j = 0; j < GameBoard[i].length; j++)
{
GameBoard[i][j] = 0;
}
}
... //Same for DirectionMap
When I run the function:
DirectionMap = AStar(GameBoard);
To render the pathfinding map that my units will follow, DirectionMap is correctly set to the values generated based on my GameBoard. However GameBoard is set to the result as well. When I run the application in Debug Mode within Eclipse, I can see that the ID's of the two arrays are the same. For some reason they seem to be pointing to the memory space. My AStar function does not modify the GameBoard array at all. The only reference to it is int retVal[][] = GameBoard;
My function prototype is public int[][] AStar(int[][] Board); and it returns the int[][] retVal.
I have no idea why I cannot change the values of DirectionMap without GameBoard following. I have never had any issues like this before.
Any ideas are really appreciated. Thanks for your help.
public int[][] AStar(int[][] Board)
{
int retVal[][] = Board;
//Initialize All Needed Lists
int width = retVal.length;
int height = retVal[0].length;
int goalX = 0;
int goalY = 0;
//List<Node> fieldInfo = new ArrayList<Node>();
Node fieldArray[][] = new Node[width][height];
for (int i = 0; i < fieldArray.length; i++)
{
for (int j = 0; j < fieldArray[i].length; j++)
{
fieldArray[i][j] = new Node(i, j);
if (retVal[i][j] == 2)
{
fieldArray[i][j].setOpen(1);
fieldArray[i][j].setDirection(10); //Set as target
goalX = i;
goalY = j;
}
if (retVal[i][j] == 1)
{
fieldArray[i][j].setOpen(0);
fieldArray[i][j].setDirection(9); //Set as wall
}
}
}
//Add AStar Algorithm Here
for (int i = 0; i < fieldArray.length; i++)
{
for (int j = 0; j < fieldArray[i].length; j++)
{
if (fieldArray[i][j].getDirection() == 0)
{
//Occurs when node was never reached
int dX = i - goalX;
int dY = j - goalY;
if (dX < 0)
dX = -dX;
if (dY < 0)
dY = -dY;
if (dY > dX)
fieldArray[i][j].setDirection(1);
else
{
if (i > goalX)
fieldArray[i][j].setDirection(7);
if (i < goalX)
fieldArray[i][j].setDirection(3);
}
}
}
}
for (int i = 0; i < fieldArray.length; i++)
{
for (int j = 0; j < fieldArray[i].length; j++)
{
retVal[i][j] = fieldArray[i][j].getDirection();
}
}
return retVal;
}
Remember when you are passing an object to methods you are actually passing a copy of reference. So when you initialise retVal[][] = Board; you actually point Board using another reference retVal. And you are returning the same reference to DirectionMap. Hence same id's for Board and DirectionMap. Consider array copy instead.
I can see that the ID's of the two arrays are the same. For some
reason they seem to be pointing to the memory space
The int[] array in Java has 0's as default values.
int[] x = new int[2];
System.out.println(x[0]); // prints 0
System.out.println(x[1]); // prints 0
The only reference to it is int retVal[][] = GameBoard;
Java arrays are objects. If at any point you are setting array = array, you are setting one reference to point to the same object as the other.