I am using a 2 dimensional boolean array to check where an entity is inside of my 2D side scroller as well as for collision. I know I am not looking for how high or low an entity away is and that is intentional. When I run this code it says the closest entity is 15 cells away. However, when I run my code it says the closest entity away is 15 blocks. Also when I print out distanceX it prints out the following:
9
0
0
2
2
15
9
0
0
2
2
15. I don't know why it won't register 9 as the closest even though that's is the first closest distance it recieves.
I can't post pictures yet however the reason 0,0,2, and 2 get printed is because I have 4 rectangles in all four corners of my player that are considered true in the grid so it detects the two on top of eachother and the other 2 or 2 spots away in the grid. Since I cant upload pictures try to see what I mean with this image i made. https://lh3.googleusercontent.com/OLSDPshjeU0YMahcmc0MDk-NocBMoG-7iN2xFTeFsQ8mAfF-sEPD8NBqXP4ENoN4YWmfUQ=s114
Thanks for any help!!
//Loop through my grid of booleans
for (int x = 0; x < map.getMapGrid().length; x++) {
for (int y = 0; y < map.getMapGrid().length; y++) {
//For comparison
Long distance = Long.MAX_VALUE;
// The second part of the if statement is to make sure it is checking for
// entities that arent the floor, therefor one above the grid position of the player
if (map.getMapGrid()[x][y] && y > ((Player) player).getGridPositionLeft().y - 1){
// distanceX = where something true was found (x) - where the player is in the grid
// Ex: 1 - 4 = |-3|, there is an entity 3 away
distanceX = Math.abs((int)(x - ((Player) player).getGridPositionLeft().x));
// if the distance of the entity from the player is less then the comparison variable,
// the closest entity x coordinate is distanceX
if(distanceX < distance){
closestCoord.x = distanceX;
closestCoord.y = 0;
}
}
}
}
return closestCoord;
}
Long distance = Long.MAX_VALUE;
This variable is never re-assigned, so it will always have the value Long.MAX_VALUE.
Also it is declared inside the innermost loop, so it will reset on each iteration. If you want the value of a variable to be remembered between iterations you need to declare and initialize it outside the loops.
Related
I have been trying to trouble shoot this section for a while now and can't seem to understand why this keeps throwing an out of bounds exception. Trouble shooting seems to say that I shouldn't be I shouldn't be going out of bounds however the results produced seem inconsistent. For instance, here is a result from a test. I can't really understand how something like this would happen. Is there anything obviously wrong with this method for setting neighbors of objects in an ArrayList? I just want to know if there are any glaring logical errors here, if not I will just have to test more on my own. Thank you for the help.
public void setNeighbors(ArrayList<ArrayList<Objects>> arrayList) //sets the neighboring tiles for each tile
{
//arrayList is an multi dimensional array of Objects with a variable size. It is created in another method
for(int i = 0; i < arrayList.size(); i++)
{
for(int x = 0; x < arrayList.get(i).size(); x++)
{
// 1 2 3
// 4 # 6
// 7 8 9
if((i>0&&x>0) && x<arrayList.get(i).size()-1 && i<arrayList.size()-1)
{ //goes 1 3 7 9
System.out.println("Max X:"+(arrayList.get(i).size()-1));
System.out.println("Max Y:"+(arrayList.size()-1));
System.out.println("X:"+x);
System.out.println("Y:"+i);
// A Floor is a type of Object and addNeighbor adds a Floor object to an ArrayList of Floor Objects within a Floor
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x+1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x+1));
}
if (x>0 && x<arrayList.get(i).size()-1)
{ // 4 6
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i).get(x+1));
}
if (i>0 && i<arrayList.size()-1)
{ // 2 8
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x));
}
}
}
}
Since the code seems to be blowing up on the value of x+1, either the line
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x+1));
or the line
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x+1));
are at fault. In either case, it suggests that the individual ArrayLists are not of a constant length.
In your if-statement you have:
if((i>0&&x>0) && x<arrayList.get(i).size()-1 && i<arrayList.size()-1)
So you check to make sure that x is in the bounds for the arrayList in the ith position. However you change i. So while x could be in bounds for arrayList(i) it might not be in bounds for arrayList(i + 1)
When either i or x are already at their maximum valid values, your code can still try to add 1 to them and use the result for indexing.
the cause are the following lines regarding the x+1 and i+1
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x+1));
Your if clause have to check for size()-2 on the x and i variable not -1.
Without knowing what your are exactly doing this should work. Think the algorithm will not work in the right manner , you have to check
for(int x = 0; x < arrayList.get(i).size(); x++)
{
// 1 2 3
// 4 # 6
// 7 8 9
if((i>0&&x>0) && x<arrayList.get(i).size()-2 && i<arrayList.size()-2)
{ //goes 1 3 7 9
System.out.println("Max X:"+(arrayList.get(i).size()-1));
System.out.println("Max Y:"+(arrayList.size()-1));
System.out.println("X:"+x);
System.out.println("Y:"+i);
// A Floor is a type of Object and addNeighbor adds a Floor object to an ArrayList of Floor Objects within a Floor
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x+1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x+1));
}
if (x>0 && x<arrayList.get(i).size()-2)
{ // 4 6
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i).get(x-1));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i).get(x+1));
}
if (i>0 && i<arrayList.size()-2)
{ // 2 8
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i-1).get(x));
((Floor)arrayList.get(i).get(x)).addNeighbor((Floor)arrayList.get(i+1).get(x));
}
}
}
I'm new to coding and have not been coding for more than two months.
For my assignment, I'm making an escape the maze algorithm.
The user defines a 2D array and a start point, then the program must take the least damaging route to find its way out. The "AI" can only move north, east, south, or west. It can escape from any edge of the array.
Enter the starting x coordinate: 2
Enter the starting y coordinate: 4
0 1 4 2 6 0 1
1 7 4 2 2 6 0
0 0 0 8 * 4 1
1 1 2 7 3 4 2
5 1 6 4 2 2 1
In this example, the user has selected [2,4] as the start location of the array (remember, indexing begins at 0).
The AI can escape from any edge of the array. It is going to want to pick the smallest integer for each movement. For this example, the AI will move up to 2, then left, then up. Thus it took a sum amount of "6 damage" to exit the array.
My issue is comparing whether North is smaller than East, and if North is smaller than East, is it smaller than West? Or South? If East is smaller than North, is it smaller than West? Or South? & so on and so forth.
I'm not sure whether I'm going about this in the correct manner.
My attempt can be found at lines 44 - 78 in the hastebin link below.
I have no idea what I'm doing.
I created an int minimumValue; but I'm not sure how to utilize it, or where. If boardArray[north][currentY] < boardArray[east][currentY] then boardArray[north][currentY] is my new minimum value correct? Then I would need to write code comparing that to west and south as well. I feel like there has to be a simpler method to go about it.
I've tried googling solutions, Reddit, The Coding Den discord server, but I simply can't get this down.
Any and all help will be appreciated!
https://hastebin.com/acopoborut.java
Holy nested else's Batman!
I would replace lines 55-78 with something like this:
//find the least danger:
int leastDanger = northDanger;
if(southDanger < leastDanger) leastDanger = southDanger;
if(eastDanger < leastDanger) leastDanger = eastDanger;
if(westDanger < leastDanger) leastDanger = westDanger;
// Go the first direction equal to least danger
if (northDanger == leastDanger) { moveNorth
}else if(southDanger == leastDanger) { moveSouth
}else if(eastDanger == leastDanger) { moveEast
}else if(westDanger == leastDanger) { moveWest
}
The moveDirections would be your code like
visitedPath = visitedPath + "[" + currentX + "," + currentY + "]";
And the danger values are your code like
boardArray[north][currentY]
It could also be done with a switch statement, if you know those.
I assume by saying north you refer to -y direction and east you refer to +x direction
if boardArray[x][y] represent coordinate (x,y), then the coordinate north of it should be (x,y-1) and east is (x+1,y). You can compare them like this
boardArray[x][y-1] < boardArray[x+1][y] //Is North smaller than East?
Of course you should first check if the north and east are both inside the array, otherwise you will get ArrayIndexOutOfBoundException
Problem 15:
Starting in the top left corner of a 2×2 grid, there are 6 routes (without backtracking) to the bottom right corner.
How many routes are there through a 20×20 grid?
So my attempt at Problem 15 is kinda bruteforcy because I try to get permutations of all of the possible valid paths by going from right to left and changing the predecessor of the first change of direction. For example, when I have a 2x2 grid (look at the Problem 15 link graphics) the first path I'll take is right - right - down - down and the last one I'll take is down - down - right - right, which is also my termination criteria. I add the possible valid paths into a list and also use that list to determine whether the valid path has been already added or not. And to permutate a path I'll do what I've mentioned earlier: I go from right to left in my array (Which in the graphic would be the bottom right corner where the arrowhead points at) and change the first element of which the next element is different from itself. So right - right - down - down would become right - right - right - down, which is obviously invalid since you have to have the same amount of rights and downs to be able to reach the end corner. So what I thought is to make another loop going from left to right and change as many elements as needed to get a valid path. So in this example right - right - right - down becomes down - right - right - down.
Also, what I forgot is that I'm not counting the points, I'm counting the edges from top left corner to bottom right corner.
So I have already written some code, but it doesn't work at all.
package projecteuler;
import java.util.ArrayList;
public class Projecteuler {
public static final int GRIDSIZE = 2;
public static void main(String[] args) {
ArrayList<boolean[]> paths = new ArrayList<>();
paths.add(new boolean[GRIDSIZE * 2]);
for(int i = 0; i < GRIDSIZE; i++) {
paths.get(0)[i] = true;
paths.get(0)[GRIDSIZE * 2 - 1 - i] = false;
}
boolean[] buf = paths.get(0).clone();
printArr(buf);
boolean tmp;
while(!checkTerminate(paths)) {
while(paths.contains(buf)) {
tmp = buf[buf.length - 1];
for(int i = buf.length - 1; buf[i - 1] != tmp && 0 < i; i--) {
buf[i] = !buf[i];
for(int j = 0; checkValid(buf) && j < i; j++)
buf[j] = !buf[j];
}
}
paths.add(buf.clone());
printArr(buf);
}
System.out.println(paths.size());
}
public static boolean checkTerminate(ArrayList<boolean[]> paths) {
boolean[] endPath = new boolean[GRIDSIZE * 2];
for(int i = 0; i < GRIDSIZE; i++) {
endPath[i] = false;
endPath[GRIDSIZE * 2 - 1 - i] = true;
}
return paths.contains(endPath);
}
public static boolean checkValid(boolean[] arr) {
int countR = 0,
countL = 0;
for(int i = 0; i < arr.length; i++)
if(arr[i])
countR++;
else
countL++;
return countR == countL;
}
public static void printArr(boolean[] arr) {
for(int i = 0; i < arr.length; i++)
System.out.print(arr[i] ? "right " : "down ");
System.out.println();
}
}
It somehow doesn't change anything anywhere.
right right down down
right right down down
right right down down
right right down down ...
and so on is all it's outputting. It seems that the code simply doesn't permutate my path, but also doesn't get stuck in any of the for loops. My best guess would be that my function criteria are placed in the wrong sequence
I also thought of a solution with backtracking like we did for a labyrinth two years ago in school, but I want to see if this approach is anywhere viable or not before redoing everything.
EDIT:
I'll try to implement the images of the 2 x 2 grid example asap, but the ProjectEuler website is under maintainance at the moment.
The solution is given by the number of combinations of "down" and "right" movements we can have. Since there is no backtracking, there are N downwards and N rightwards movements in total (in any route, for an NxN grid). There are 2N movements in total.
We can obtain this using the binomial coefficient, nCr (pronounced "n choose r"), which is the number of ways of choosing r objects from n objects (each of which can be two things). In our case an "object" is either a downward or rightward movement. This is given by
Thus the number we want is:
For N = 2 this gives 6. For N = 20 this gives 137846528820.
Let a step in right be termed as R and a step down is termed as D.
In order to reach from top-left to bottom-right on a n rows and m column grid, you will have to go right m times and go down n times.
Essentially, you will have to get all the possible arrangements of m R's and n D's.
Example: For a 2 by 2 grid, the number of unique permutations of the word RRDD will be the number of ways in which you can go, viz.
RRDD
RDRD
DRDR
DDRR
Google the formula to calculate the permutations of letters with repetition, which is given by:
n! / ( r1! * r2! ... ), where sum of all r's is n.
This question on Math SE pops up first when looking for repetitive letter permutation count, and the second answer explains better in my opinion.
So, to return the count AND even to return the paths, you don't need to traverse the maze at all. Just do the formula calculation for first one and print the permutations for second problem.
Giving the paths when certain steps are off grid will be the only case that requires you to actually traverse the maze.
UPDATE:
It helps to visualize the formula for permutation of repeated letters.
Here is a slide that demonstrates that case. See how the 2 E's end up duplicating the arrangements when generating the permutations. In general, any letter that's repeated r times will cause r! duplication because wherever in the arrangement that letter is put, it can be replaced with another same letter without giving a new permutation.
That way, if we divide the total n! permutations with r!, we get the actual unique permutations.
Image Source
I have created TicTacToe game. I use minmax algorithm.
When the board is 3x3 I just calculate every possible move for a game till the end and -1 for loss, 0 for tie, 1 for win.
When it comes to 5x5 it can't be done(to many options(like 24^24) so I have created evaluation method which gives: 10^0 for one CIRCLE inline, 10^1 for 2 CIRCLE inline, ..., 10^4 for 5 CIRCLES inline, but it is useless.
Does anybody have better idea for assesment?
Example:
O|X|X| | |
----------
|O| | | |
----------
X|O| | | |
----------
| | | | |
----------
| | | | |
Evaluation -10, 2 circles across once and inline once (+200), 2 crosses inline(-100), and -1 three times and + 1 three times for single cross and circle.
This is my evaluation method now:
public void setEvaluationForBigBoards() {
int evaluation = 0;
int howManyInLine = board.length;
for(; howManyInLine > 0; howManyInLine--) {
evaluation += countInlines(player.getStamp(), howManyInLine);
evaluation -= countInlines(player.getOppositeStamp(), howManyInLine);
}
this.evaluation = evaluation;
}
public int countInlines(int sign, int howManyInLine) {
int points = (int) Math.pow(10, howManyInLine - 1);
int postiveCounter = 0;
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
//czy od tego miejsca jest cos po przekatnej w prawo w dol, w lewo w dol, w dol, w prawo
if(toRigth(i, j, sign, howManyInLine))
postiveCounter++;
if(howManyInLine > 1) {
if(toDown(i, j, sign, howManyInLine))
postiveCounter++;
if(toRightDiagonal(i, j, sign, howManyInLine))
postiveCounter++;
if(toLeftDiagonal(i, j, sign, howManyInLine))
postiveCounter++;
}
}
}
return points * postiveCounter;
}
Number of options (possible sequences of moves) after the first move is 24! and not 24^24. It is still a too much high
number so it is correct to implement an heuristic.
Note that answers about good heuristics are necessarily based on the opinion of the writer so I give my opinion but to find
out what is "the best heuristic" you should make the various ideas playing one against the other in the following way:
take the two heuristics A and B that you want to compare
generate at random a starting configuration
let A play with O and B play with X
from the same starting configuration let A play with X and B play with O
take stats of which one wins more
Now my thoughts about good possible heuristics starting points for an nxn playfield with winning sequence length of n:
since the winning condition for a player it to form a straight sequence of its marks my idea is to use as base values the number of possibilities that each player has still available to built such a straight sequence.
in an empty field both O and X have ideally the possibility to realize the winning sequence in several ways:
horizontal possibilities: n
vertical possibilities: n
diagonal possibilities: 2
total possibilities: 2n+2
in the middle of a round the number of remaining opportunities for a player are calculated as: "the number of rows without opponent's marks + the number of columns without opponent's marks + the number of diagonals without opponent's marks.
instead than calculate all each time it can be considered that:
after a move of one player the umber of still available possibilities are:
unchanged for him
equal or lowered for the opponent (if the mark has been placed in a row/col/diagonal where no marks had already been placed by the considered player)
as heuristic i can propose -
is possible that - k * with k > 1 give better results and in the end this can be related to how a draw is considered with regard to a lose.
One side consideration:
playfield cells are n^2
winning possibilities are 2n+2 if we keep the winning length equal to the field edge size
this give me the idea that the more the size is increased the less interesting is to play because the probability of a draw after a low number of moves (with reference to the playfield area) becomes higher and higher.
for this reason I think that the game with a winning length lower that n (for example 3 independently from the playfield size) is more interesting.
Named l the wining length we have that the number of possibilities is 2*((n+1-l)*(2n+1-l)) = O(n^2) and so well proportioned with the field area.
I am implementing a NxN puzzle solver using A* search algorithm and using Manhattan distance as a heuristic and I've run into a curious bug (?) which I can't wrap my head around.
Consider these puzzles (0 element being blank space):
(initial)
1 0 2
7 5 4
8 6 3
(goal)
1 2 3
4 5 6
7 8 0
The minumum number of moves to reach solution from initial state is 11. However, my solver, reaches goal in 17 moves.
And therein lies the problem - my puzzle solver mostly solves the solvable puzzles in a correct (minimum) number of moves but for this particular puzzle, my solver overshoots the minimum number of moves and I think I've nailed down the problem to a miscalculation of Manhattan distance in this particular case.
At this link you can see what my solver is doing (on the right) and what a tried-n-tested solver is doing (Brian Borowski's excellent solver, available here).
In the very first move, Brian's solver immediately chooses solution that pushes element 5 up, but my solver has other ideas, and on the stacktrace (given on the link), my solver chooses solution which pushes 2 to the left (since that board's Manhattan distance is lower, the board is on the front of priority queue).
I can't see what is the problem and I can't blame my Manhattan distance calculation, since it correctly solves a number of other 3x3 puzzles.
Here is how I calculate the Manhattan distance of a given Board:
/**
* Calculates sum of Manhattan distances for this board and stores it in private field to promote immutability.
*/
private void calculateManhattanDistance() {
int manhattanDistanceSum = 0;
for (int x = 0; x < N; x++) // x-dimension, traversing rows (i)
for (int y = 0; y < N; y++) { // y-dimension, traversing cols (j)
int value = tiles[x][y]; // tiles array contains board elements
if (value != 0) { // we don't compute MD for element 0
int targetX = (value - 1) / N; // expected x-coordinate (row)
int targetY = (value - 1) % N; // expected y-coordinate (col)
int dx = x - targetX; // x-distance to expected coordinate
int dy = y - targetY; // y-distance to expected coordinate
manhattanDistanceSum += Math.abs(dx) + Math.abs(dy);
}
}
manhattanDistance = manhattanDistanceSum;
}
I would appreciate any insight or idea you may have.
If any additional code is needed, I'll post it right away.
I was stuck in the same place sometime back where I was solving this in 17 moves.The problem was that I was only using heuristic h(n) for the A* algorithm and whereas for choosing the next node A* uses manhattan distance(heuristic) + pathcost (cost to reach the node from root called as g(n)) to make the choice.
Once you plug in this to the algorithm it works like a charm.
Hope this helps someone who is stuck in the same place.
If your heuristic it's admissible (and it is, check this) than A* always return optimal solution. Can be slower or faster (expand more or less nodes) but it returns the optimal solution.
So, cause your heuristic is admissible the problem must be in A* algorithm implementation.
In addition the fact that its first step it's different from the optimal one is meaningless: the algorithm can correctly performs backtrace to get the correct solution path in the future. All the open nodes are candidates for the next step, not only the child of the current node.