Skip to content

Commit

Permalink
feat: Support 8 directional Grids
Browse files Browse the repository at this point in the history
Co-authored-by: Jean-René Lavoie <>
  • Loading branch information
DeathPhoenix22 authored Jan 31, 2024
1 parent f0cae6a commit bb60463
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.almasb.fxgl.core.collection.grid;

import com.almasb.fxgl.core.math.FXGLMath;
import static com.almasb.fxgl.core.collection.grid.NeighborFilteringOption.*;

import java.lang.reflect.Array;
import java.util.ArrayList;
Expand All @@ -15,7 +16,6 @@
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
* @param <T> cell type
Expand Down Expand Up @@ -98,7 +98,6 @@ public final int getCellHeight() {
return cellHeight;
}


/**
* Checks if given (x,y) is within the bounds of the grid,
* i.e. get(x, y) won't return OOB.
Expand All @@ -124,18 +123,37 @@ public final List<T> getCells() {
}

/**
* Note: returned cells are in the grid (i.e. bounds are checked).
* Diagonal cells are not included.
* Note: returned cells are in the grid (i.e. bounds are checked). (defaulted to 4 directions)
* The order is left, up, right, down.
*
* @return a new list of neighboring cells to given (x, y)
*/
public final List<T> getNeighbors(int x, int y) {
return getNeighbors(x, y, FOUR_DIRECTIONS);
}

/**
* Note: returned cells are in the grid (i.e. bounds are checked).
* NeighborFilteringOption allow filtering based on desired # of directions
* The order is left, up, right, down. + "Optionally" up-left, up-right, down-left, down-right
*
* @return a new list of neighboring cells to given (x, y)
*/
public final List<T> getNeighbors(int x, int y, NeighborFilteringOption neighborFilteringOption) {
List<T> result = new ArrayList<>();
getLeft(x, y).ifPresent(result::add);
getUp(x, y).ifPresent(result::add);
getRight(x, y).ifPresent(result::add);
getDown(x, y).ifPresent(result::add);

// Include "Corner" neighbors when eight directions
if(neighborFilteringOption.is(EIGHT_DIRECTIONS)) {
getUpLeft(x, y).ifPresent(result::add);
getUpRight(x, y).ifPresent(result::add);
getDownLeft(x, y).ifPresent(result::add);
getDownRight(x, y).ifPresent(result::add);
}

return result;
}

Expand Down Expand Up @@ -171,6 +189,22 @@ public final Optional<T> getDown(Cell cell) {
return getDown(cell.getX(), cell.getY());
}

public final Optional<T> getUpRight(Cell cell) {
return getUpRight(cell.getX(), cell.getY());
}

public final Optional<T> getUpLeft(Cell cell) {
return getUpLeft(cell.getX(), cell.getY());
}

public final Optional<T> getDownRight(Cell cell) {
return getDownRight(cell.getX(), cell.getY());
}

public final Optional<T> getDownLeft(Cell cell) {
return getDownLeft(cell.getX(), cell.getY());
}

public final Optional<T> getRight(int x, int y) {
return getOptional(x + 1, y);
}
Expand All @@ -187,6 +221,23 @@ public final Optional<T> getDown(int x, int y) {
return getOptional(x, y + 1);
}

public final Optional<T> getUpRight(int x, int y) {
return getOptional(x + 1, y - 1);
}

public final Optional<T> getUpLeft(int x, int y) {
return getOptional(x - 1, y - 1);
}

public final Optional<T> getDownRight(int x, int y) {
return getOptional(x + 1, y + 1);
}

public final Optional<T> getDownLeft(int x, int y) {
return getOptional(x - 1, y + 1);
}


/**
* @param x pixel coord x
* @param y pixel coord y
Expand Down Expand Up @@ -248,7 +299,7 @@ public final Optional<T> getRandomCell(Predicate<T> predicate) {
public final Optional<T> getRandomCell(Random random, Predicate<T> predicate) {
List<T> filtered = getCells().stream()
.filter(predicate)
.collect(Collectors.toList());
.toList();

if (filtered.isEmpty())
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* FXGL - JavaFX Game Library. The MIT License (MIT).
* Copyright (c) AlmasB (almaslvl@gmail.com).
* See LICENSE for details.
*/

package com.almasb.fxgl.core.collection.grid;


/**
* Define Movement Directions
*
* @author Jean-Rene Lavoie (jeanrlavoie@gmail.com)
*/
public enum NeighborFilteringOption {

FOUR_DIRECTIONS, EIGHT_DIRECTIONS;

public boolean is(NeighborFilteringOption... neighborFilteringOptions) {
for(NeighborFilteringOption neighborFilteringOption : neighborFilteringOptions) {
if(neighborFilteringOption.equals(this)) {
return true;
}
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ public void testGetNeighbors() {
assertThat(grid.getNeighbors(3, GRID_SIZE - 1), containsInAnyOrder(grid.get(3, GRID_SIZE - 2), grid.get(2, GRID_SIZE - 1), grid.get(4, GRID_SIZE - 1)));
}

@Test
public void testGetNeighborsEightDirections() {
assertThat(grid.getNeighbors( 3,3, NeighborFilteringOption.EIGHT_DIRECTIONS), containsInAnyOrder(
grid.get(2, 2), grid.get(2, 3), grid.get(2, 4),
grid.get(3, 2), grid.get(3, 4), // Doesn't contain 3, 3 (self)
grid.get(4, 2), grid.get(4, 3), grid.get(4, 4)
));
}

@Test
public void testGetRandomCell() {
for (int i = 0; i < 50; i++) {
Expand All @@ -165,7 +174,7 @@ public void testRandomCell() {
}

@Test
public void testDirections() {
public void testFourDirections() {

// right cell

Expand Down Expand Up @@ -209,6 +218,58 @@ public void testDirections() {
assertThat(grid.getDown(grid.get(1, GRID_SIZE - 1)).isPresent(), is(false));
}

@Test
public void testEightDirections() {
// up right cell
Optional<MockCell> upRightCell = grid.getUpRight(grid.get(1, 1));

assertThat(upRightCell.isPresent(), is(true));
assertThat(upRightCell.get().getX(), is(2));
assertThat(upRightCell.get().getY(), is(0));

assertThat(grid.getUpRight(grid.get(0, 0)).isPresent(), is(false));
assertThat(grid.getUpRight(grid.get(0, GRID_SIZE-1)).isPresent(), is(true));
assertThat(grid.getUpRight(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
assertThat(grid.getUpRight(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));

// up left Cell
Optional<MockCell> upLeftCell = grid.getUpLeft(grid.get(1, 1));

assertThat(upLeftCell.isPresent(), is(true));
assertThat(upLeftCell.get().getX(), is(0));
assertThat(upLeftCell.get().getY(), is(0));

assertThat(grid.getUpLeft(grid.get(0, 0)).isPresent(), is(false));
assertThat(grid.getUpLeft(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
assertThat(grid.getUpLeft(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
assertThat(grid.getUpLeft(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(true));

// down right Cell
Optional<MockCell> downRightCell = grid.getDownRight(grid.get(1, 1));

assertThat(downRightCell.isPresent(), is(true));
assertThat(downRightCell.get().getX(), is(2));
assertThat(downRightCell.get().getY(), is(2));

assertThat(grid.getDownRight(grid.get(0, 0)).isPresent(), is(true));
assertThat(grid.getDownRight(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
assertThat(grid.getDownRight(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
assertThat(grid.getDownRight(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));

// down left cell
Optional<MockCell> downLeftCell = grid.getDownLeft(grid.get(1, 1));

assertThat(downLeftCell.isPresent(), is(true));
assertThat(downLeftCell.get().getX(), is(0));
assertThat(downLeftCell.get().getY(), is(2));

assertThat(grid.getDownLeft(grid.get(0, 0)).isPresent(), is(false));
assertThat(grid.getDownLeft(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
assertThat(grid.getDownLeft(grid.get(GRID_SIZE-1, 0)).isPresent(), is(true));
assertThat(grid.getDownLeft(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));
}


public static class MockCell extends Cell {

public MockCell(int x, int y) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* FXGL - JavaFX Game Library. The MIT License (MIT).
* Copyright (c) AlmasB (almaslvl@gmail.com).
* See LICENSE for details.
*/

package com.almasb.fxgl.core.collection.grid;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class NeighborFilteringOptionTest {

@Test
public void testIs() {
assertTrue(NeighborFilteringOption.FOUR_DIRECTIONS.is(NeighborFilteringOption.FOUR_DIRECTIONS));
assertFalse(NeighborFilteringOption.EIGHT_DIRECTIONS.is(NeighborFilteringOption.FOUR_DIRECTIONS));
}

}

0 comments on commit bb60463

Please sign in to comment.