Is there an efficient algorithm for calculating which tiles are within a set walking distance of your character in a 2d grid? - javafx

Lets say that on a 2d grid of 20x20, you have your character at position (5,5).
He is able to walk up to 4 tiles in his move. However, there may be obstacles blocking your path such as a wall.
Is there any efficient / easy way for calculating exactly which tiles he would be able to walk to without checking every single possible move ( e.g. move up 0 and right 0 then move up 0 and right 1 e.t.c )?
At the moment I'm calculating the places that you can walk through with this horrific thing:
int playerx = GridPane.getRowIndex(button);
int playery = GridPane.getColumnIndex(button);
int position = playery*8+playerx;
for (int i = 0; i < 5; i++)
{
for (int j = i-4; j < 5-i; j++)
{
try
{
int expectedCollumn = playerx+j;
int actualCollumn = ((position+i+j*8)-((position+i+j*8)%8))/8;
if(expectedCollumn==actualCollumn)
{
Button temp = (Button)gridPane.getChildren()
.get(position+i+j*8);
if (!temp.getText().equals("W") &&
!temp.getText().equals("P"))
{
temp.setText("T");
}
}
actualCollumn = ((position-i+j*8)-((position-i+j*8)%8))/8;
if(expectedCollumn==actualCollumn)
{
Button temp2 = (Button)
gridPane.getChildren().get(position-i+j*8);
if (!temp2.getText().equals("W") &&
!temp2.getText().equals("P"))
{
temp2.setText("T");
}
}
}
}
}
However, its showing as if you are able to walk to the otherside of the wall and I'm not sure how I would go about fixing this.
Many thanks in advance.

For path finding, you should figure out how this works:
https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
and then move on to A* or something more efficient.

Thanks to everyone that answered but the solution was simple
incase somehow someone finds this post and is interested it was a simple recursive call
void getReachableTiles(Tile current, Int stamina, List<Tile> visited, List<Tile> reachable) {
if (stamina <= 0) return;
List<Tile> neighbours = new List<>(current + up, current + left, ..)
for (Tile t in neighbours) {
if (!visited.contains(t)) {
visited.append(t);
if (!t.isWall()) {
reachable.append(t);
getReachableTiles(t, stamina - 1, visited, reachable);
}
}
}
}

Related

Array grid with click functions in Processing

I have a grid that is clickable but I am unsure how to proceed with a certain set of rules.
Edit: I rewrote the rules in a more understandable fashion. Very similar to that of the game of life.
Setup
21 cells across / columns
10 cells down / rows
4 base cells vertically aligned in the centre of the board.
Outline cells will surround the base cells.
Every other cell begins as inactive.
Base Cells [2]
Constant and active blue cells in the middle, which cannot be removed.
Active [0] -> [1]
When clicked, an inactive white cell becomes black
if
the edge touches the edge of a base cell
or
the edge touches the edge of another active cell
(either to the left, right, top or bottom – not diagonally.)
else
remain inactive
Inactive [1] -> [0]
When clicked, an active black cell returns to white.
Outline [3]
A series of yellow cells that will constantly update to surround the neighborhood of active cells.
Could anyone help me in achieving this, I would appreciate comments to help me understand the process.
Here is my current code:
int boxsize = 100;
int cols, rows;
color[][] colors;
int saved_i = -1;
int saved_j = -1;
void setup() {
size(1300, 600);
cols = width/boxsize;
rows = height/boxsize;
colors = new color[cols][rows];
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
colors[i][j] = color(255);
}
}
}
void draw() {
background(255);
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
fill(colors[i][j]);
rect(i*boxsize, j*boxsize, boxsize, boxsize);
}
}
}
void mousePressed() {
for (int i=0; i<cols; i++) {
for (int j=0; j<rows; j++) {
int x = i*boxsize;
int y = j*boxsize;
if (mouseX > x && mouseX < (x + boxsize) && mouseY > y && mouseY < (y + boxsize)) {
if ( saved_i == -1 || saved_i == i || saved_j == j ) {
colors[i][j] = color(0);
if (j>0) colors[i][j-1]=color(255, 255, 0);
if (j>0) colors[i+1][j-1]=color(255, 255, 0);
if (j<rows-1) colors[i][j+1]=color(255, 255, 0);
if (j<rows-1) colors[i+1][j+1]=color(255, 255, 0);
if (i>0) colors[i-1][j]=color(255, 255, 0);
if (i>0) colors[i-1][j-1]=color(255, 255, 0);
if (i>0) colors[i-1][j+1]=color(255, 255, 0);
if (i<cols-1) colors[i+1][j]=color(255, 255, 0);
saved_i = i;
saved_j = j;
}
}
}
}
}
Your question is pretty broad, so I'll answer in broad terms. You need to figure out four things:
How to represent your cells. In other words, what type of variable you want to store your grid in. You're using colors now, but you probably don't want to do it that way. The way I see it, you have three logical options:
Use a 2D array of enum values. The enum would have states for BASE, ACTIVE, INACTIVE, and OUTLINE. This is probably the correct way to go.
Use a 2D array of ints. 0 for base, 1 for active, 2 for inactive, 3 for outline. Using an enum is probably better, but this is probably easier for a novice to understand.
Use a 2D array of objects. Create a class that represents a cell, and the object would store its state (in either an enum or an int). You would use this approach if you wanted other logic inside each cell, or maybe if you wanted each cell to keep track of its own neighbors.
How to change the state of a single cell on mouse click. You've got logic that deals with colors, now you just have to apply that logic to the data structure you choose in step 1. Maybe create a function that takes mouseX and mouseY and returns the position in the array at that location.
How to get the new state for each cell for the next generation. Create a function that takes the position of one cell (its row and column in the 2D array) and returns the state that the cell should have in the next generation. This is the "meat and potatoes" of your project, and separating it out will help you isolate the logic. Get out a piece of grid paper and draw some examples. If you know the position of a cell, what are the positions of its neighbors? There are a ton of tutorials on the Game of Life out there that will have this logic.
How to update your grid. Remember that you have to do step 2 to every cell in the grid before you update the whole grid. This means that you have to make a new 2D array each iteration.
Break your problem down down like this, and post a new question if you get stuck on a particular step. It's hard to help with general "how do I do this" type questions. It's much easier to help with more specific questions like "I tried X, expected Y, but got Z instead. What am I doing wrong?"
Good luck!

QGraphicsItem: Why no `stackAfter` method?

I'm having an annoying time trying to get around the 'recommended' way of doing something.
So, I have a stack of cards. I want to make it so that when I deal a card, it becomes the last-drawn object of the entire scene (typical bring_to_front functionality).
The recommended way to do this is just adding to the object's zValue until it is larger than all the rest, but I was hoping to do away with rather "lazy" integers running around all over the place with judicious use of the stackBefore method, which simulates reorganizing the order in which objects were added to the scene.
This works perfectly fine when I shuffle my cards in a limited set (get list of selected items, random.shuffle, for item do item.stackBefore(next item)), but it is certainly not working when it comes to bubbling the card to the top of the entire scene.
I considered adding a copy of the object to the scene and then removing the original, but it just seems like I should be able to do stackAfter like I would when using a Python list (or insertAt or something).
Sample code:
def deal_items(self):
if not self.selection_is_stack():
self.statusBar().showMessage("You must deal from a stack")
return
item_list = self.scene.sorted_selection()
for i,item in enumerate(item_list[::-1]):
width = item.boundingRect().width()
item.moveBy(width+i*width*0.6,0)
another_list = self.scene.items()[::-1]
idx = another_list.index(item)
for another_item in another_list[idx+1:]:
another_item.stackBefore(item)
This works. It just seems somewhat... ugly.
self.scene.items returns the items in the stacking order (link). So if you want to stackAfter an item, you can just query the z value of the current topmost item and then set the z value of the new topmost card to a value one larger.
item.setZValue(self.scene.items().first().zValue() + 1)
Hope that helps.
Edit added src for stackBefore and setZValue from http://gitorious.org/qt/
src/gui/graphicsview/qgraphicsitem.cpp
void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
{
if (sibling == this)
return;
if (!sibling || d_ptr->parent != sibling->parentItem()) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
QList<QGraphicsItem *> *siblings = d_ptr->parent
? &d_ptr->parent->d_ptr->children
: (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
if (!siblings) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
// First, make sure that the sibling indexes have no holes. This also
// marks the children list for sorting.
if (d_ptr->parent)
d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
else
d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
// Only move items with the same Z value, and that need moving.
int siblingIndex = sibling->d_ptr->siblingIndex;
int myIndex = d_ptr->siblingIndex;
if (myIndex >= siblingIndex) {
siblings->move(myIndex, siblingIndex);
// Fixup the insertion ordering.
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
++index;
}
d_ptr->siblingIndex = siblingIndex;
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
siblings->at(i)->d_ptr->siblingOrderChange();
}
d_ptr->siblingOrderChange();
}
}
void QGraphicsItem::setZValue(qreal z)
{
const QVariant newZVariant(itemChange(ItemZValueChange, z));
qreal newZ = newZVariant.toReal();
if (newZ == d_ptr->z)
return;
if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
// Z Value has changed, we have to notify the index.
d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
}
d_ptr->z = newZ;
if (d_ptr->parent)
d_ptr->parent->d_ptr->needSortChildren = 1;
else if (d_ptr->scene)
d_ptr->scene->d_func()->needSortTopLevelItems = 1;
if (d_ptr->scene)
d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
itemChange(ItemZValueHasChanged, newZVariant);
if (d_ptr->flags & ItemNegativeZStacksBehindParent)
setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
if (d_ptr->isObject)
emit static_cast<QGraphicsObject *>(this)->zChanged();
}

2D Continuous Collision Detection

I'm trying to implement simple continuous collision detection for my pong game however i'm not sure i'm implementing or understand this right. AFAIR continuous collision detection is used for fast moving objects that may pass through another object circumventing normal collision detection.
So what I tried was that because the only fast moving object I have is a ball I would just need the position of the ball, its move speed, and the position of the object we are comparing to.
From this I figured it would be best that for example if the ball's move speed indicated it was moving left, I would compare it's left-most bound to the right-most bound of the other object. From this I would step through by adding the move speed to the left-most bound of the ball and compare to make sure it's greater than the other objects right bound. This would show that there is no left right collision.
I have something somewhat working, but unfortunately, the ball starts bouncing normally for a while then it acts as if it hits a paddle when nothing is there.
I'm a bit lost, any help would be appreciated!
static bool CheckContinuousCollision(PActor ball, PRect ballRect, PActor other, PRect otherRect)
{
PVector ballMoveSpeed;
int ballXLimit;
int ballYLimit;
ballMoveSpeed = ball.moveSpeed;
// We are moving left
if ( sgn(ball.moveSpeed.x) < 0 )
{
ballXLimit = std.math.abs(ballMoveSpeed.x) / 2;
for ( int i = 0; i <= ballXLimit; i++ )
{
if ( ballRect.Left < otherRect.Right && otherRect.Left < ballRect.Left)
{
return true;
}
ballRect.Left -= i;
}
}
//We are moving right
if ( sgn(ball.moveSpeed.x) > 0)
{
ballXLimit = std.math.abs(ballMoveSpeed.x) / 2;
for ( int i = 0; i < ballXLimit; i ++ )
{
if ( ballRect.Right > otherRect.Left && ballRect.Right < otherRect.Right )
{
return true;
}
ballRect.Right += i;
}
}
// we are not moving
if ( sgn(ball.moveSpeed.x) == 0)
{
return false;
}
}
You seem to be checking the collision of only one dimension, i.e the X dimension of your ball versus your Other.
What you probably want is to compare whether the two objects collide in 2d space. This can be easily done by adjusting each objects Bounding Rectangle and checking whether the rectangles overlap. Then in your for loop you can adjust your Ball rectangle accordingly

Collision Detection and maintaining momentum on an object

I have been implementing various forms of simple collision detection with varying results. I have a fairly good working version of collision detection, but there are some odd behaviors that I can't work out.
Just for a reference, i'm making a simple pong game, and trying to refine the collision. The problems I get are when the ball collides with the paddle on either the top or bottom side. In those cases, the ball hovers above (or below) the paddle and does not move. I'm guessing this is because of how i'm checking for collision and how i'm altering the movespeed of the ball.
I would like to implement a way I differentiate between top/bottom and left/right collision but this is the only method that works decently:
static void CheckCollision(PActor object1, PActor object2, PInput pinput)
{
if ( CheckObjectCollision( object1, object2 ) )
{
AdjustMoveSpeed( object1, object2, pinput );
}
}
static bool CheckObjectCollision(PActor object1, PActor object2)
{
int object1LeftBound = object1.position.x;
int object1RightBound = object1.position.x + object1.actorTextureXSize;
int object1TopBound = object1.position.y;
int object1BottomBound = object1.position.y + object1.actorTextureYSize;
int object2LeftBound = object2.position.x;
int object2RightBound = object2.position.x + object1.actorTextureXSize;
int object2TopBound = object2.position.y;
int object2BottomBound = object2.position.y + object2.actorTextureYSize;
if ( object1RightBound < object2LeftBound )
return false;
if ( object1LeftBound > object2RightBound )
return false;
if ( object1BottomBound < object2TopBound )
return false;
if ( object1TopBound > object2BottomBound )
return false;
return true;
}
I am guessing that the root of some of the problems i'm having is the function AdjustMoveSpeed, here it is:
static void AdjustMoveSpeed(PActor object1, PActor object2, PInput pinput)
{
PVector prevMouseLocation = pinput.GetPrevMouseLocation();
PVector currMouseLocation = pinput.GetCurrMouseLocation();
int currentMoveSpeed;
int nextMoveSpeed;
if (typeid(object1) == typeid(PBall))
{
object1.moveSpeed.x *= -1;
if ( typeid(object2) == typeid(PPlayer) )
{
currentMoveSpeed = object1.moveSpeed.y;
nextMoveSpeed = prevMouseLocation.y - currMouseLocation.y;
object1.moveSpeed.y = (prevMouseLocation.y - currMouseLocation.y) * -1;
}
else
{
if (object1.moveSpeed.y > 0)
object1.moveSpeed.y *= -1;
}
}
else if (typeid(object2) == typeid(PBall))
{
object2.moveSpeed.x *= -1;
if ( typeid(object1) == typeid(PPlayer) )
{
currentMoveSpeed = object1.moveSpeed.y;
nextMoveSpeed = prevMouseLocation.y - currMouseLocation.y;
object2.moveSpeed.y = (prevMouseLocation.y - currMouseLocation.y) * -1;
}
else
{
if (object2.moveSpeed.y > 0)
object2.moveSpeed.y *= -1;
}
}
}
What I was attempting to do with AdjustMoveSpeed, is first check to see which object is the ball, after this, multiply the x move speed by -1 to reverse its direction. After this, I check to see if the other object is a player, if so I set the y move speed to the difference between the previous mouse location and current mouse location. This is here to give the player option to change the balls y speed, or add spin.
I've tried checking for intersection between objects so that I can get a specific side, and the result is the ball just flying in the middle of the screen without actually hitting either paddle.
How do I properly check for collision detection on two objects that are squares?
How can I fix AdjustMoveSpeed so that it works properly with collision detection?
Lastly, how do I keep the momentum of the ball of its current speed is greater than the difference of the mouse location before and after the hit?
I've tried taking comparing the absolute value of currentMoveSpeed and nextMoveSpeed but then the ball doesn't change y speed. Something like this:
if ( abs(currentMoveSpeed) < abs(nextMoveSpeed )
object1.moveSpeed.y = (prevMouseLocation.y - currMouseLocation.y) * -1;
else
object1.moveSpeed.y *= -1
Pong is simple enough that, rather than moving the ball each frame and checking for a collision with a paddle, you can actually solve the equation for when the paddle and ball will collide - if that time is less than one frame, there is a collision.
This completely eliminates the issue of the ball moving so fast it moves through the paddle, an issue that plagues many pong-clones that use the naive method of collision-detection.
This solution is called continuous collision detection - see this answer for more information.
If the ball gets stuck on the paddle instead of bouncing it is probably because it keeps changing direction back and forth. The ball should only bounce if it is heading towards the paddle.
if (sgn(object1.moveSpeed.x) == sgn(object1.x - object2.x)) {
// Ball is already moving away from the paddle, don't bounce!
}
else {
// Ok to bounce!
object1.moveSpeed.x *= -1;
}

Recursive Stackoverflow Error

Alright, so I'm trying to make a Java program to solve a picross board, but I keep getting a Stackoverflow error. I'm currently just teaching myself a little Java, and so I like to use the things I know rather than finding a solution online, although my way is obviously not as efficient. The only way I could think of solving this was through a type of brute force, trying every possibility. The thing is, I know that this function works because it works for smaller sized boards, the only problem is that with larger boards, I tend to get errors before the function finishes.
so char[][] a is just the game board with all the X's and O's. int[][] b is an array with the numbers assigned for the picross board like the numbers on the top and to the left of the game. isDone() just checks if the board matches up with the given numbers, and shift() shifts one column down. I didn't want to paste my entire program, so if you need more information, let me know. Thanks!
I added the code for shift since someone asked. Shift just moves all the chars in one row up one cell.
Update: I'm thinking that maybe my code isn't spinning through every combination, and so it skips over the correct answer. Can anyone verify is this is actually trying every possible combination? Because that would explain why I'm getting stackoverflow errors. On the other hand though, how many iterations can this go through before it's too much?
public static void shifter(char[][] a, int[][] b, int[] clockwork)
{
boolean correct = true;
correct = isDone(a, b);
if(correct)
return;
clockwork[a[0].length - 1]++;
for(int x = a[0].length - 1; x > 0; x--)
{
if(clockwork[x] > a.length)
{
shift(a, x - 1);
clockwork[x - 1]++;
clockwork[x] = 1;
}
correct = isDone(a, b);
if(correct)
return;
}
shift(a, a[0].length - 1);
correct = isDone(a, b);
if(correct)
return;
shifter(a, b, clockwork);
return;
}
public static char[][] shift(char[][] a, int y)
{
char temp = a[0][y];
for(int shifter = 0; shifter < a.length - 1; shifter++)
{
a[shifter][y] = a[shifter + 1][y];
}
a[a.length - 1][y] = temp;
return a;
}
Check Recursive call.and give the termination condition.
if(terminate condition)
{
exit();
}
else
{
call shifter()
}

Resources