From bb604633ef91764156132f456c2726e3abc9cdaf Mon Sep 17 00:00:00 2001 From: DeathPhoenix22 <122117914+DeathPhoenix22@users.noreply.github.com> Date: Wed, 31 Jan 2024 12:31:07 -0500 Subject: [PATCH] feat: Support 8 directional Grids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jean-ReneĢ Lavoie <> --- .../fxgl/core/collection/grid/Grid.java | 61 ++++++++++++++++-- .../grid/NeighborFilteringOption.java | 28 +++++++++ .../fxgl/core/collection/grid/GridTest.java | 63 ++++++++++++++++++- .../grid/NeighborFilteringOptionTest.java | 21 +++++++ 4 files changed, 167 insertions(+), 6 deletions(-) create mode 100644 fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOption.java create mode 100644 fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOptionTest.java diff --git a/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/Grid.java b/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/Grid.java index b90cc4981..70c92e9a2 100644 --- a/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/Grid.java +++ b/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/Grid.java @@ -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; @@ -15,7 +16,6 @@ import java.util.Random; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * @param cell type @@ -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. @@ -124,18 +123,37 @@ public final List 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 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 getNeighbors(int x, int y, NeighborFilteringOption neighborFilteringOption) { List 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; } @@ -171,6 +189,22 @@ public final Optional getDown(Cell cell) { return getDown(cell.getX(), cell.getY()); } + public final Optional getUpRight(Cell cell) { + return getUpRight(cell.getX(), cell.getY()); + } + + public final Optional getUpLeft(Cell cell) { + return getUpLeft(cell.getX(), cell.getY()); + } + + public final Optional getDownRight(Cell cell) { + return getDownRight(cell.getX(), cell.getY()); + } + + public final Optional getDownLeft(Cell cell) { + return getDownLeft(cell.getX(), cell.getY()); + } + public final Optional getRight(int x, int y) { return getOptional(x + 1, y); } @@ -187,6 +221,23 @@ public final Optional getDown(int x, int y) { return getOptional(x, y + 1); } + public final Optional getUpRight(int x, int y) { + return getOptional(x + 1, y - 1); + } + + public final Optional getUpLeft(int x, int y) { + return getOptional(x - 1, y - 1); + } + + public final Optional getDownRight(int x, int y) { + return getOptional(x + 1, y + 1); + } + + public final Optional getDownLeft(int x, int y) { + return getOptional(x - 1, y + 1); + } + + /** * @param x pixel coord x * @param y pixel coord y @@ -248,7 +299,7 @@ public final Optional getRandomCell(Predicate predicate) { public final Optional getRandomCell(Random random, Predicate predicate) { List filtered = getCells().stream() .filter(predicate) - .collect(Collectors.toList()); + .toList(); if (filtered.isEmpty()) return Optional.empty(); diff --git a/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOption.java b/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOption.java new file mode 100644 index 000000000..c54f617dc --- /dev/null +++ b/fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOption.java @@ -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; + } + +} \ No newline at end of file diff --git a/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/GridTest.java b/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/GridTest.java index 0c5ec391d..4d7a5e70c 100644 --- a/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/GridTest.java +++ b/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/GridTest.java @@ -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++) { @@ -165,7 +174,7 @@ public void testRandomCell() { } @Test - public void testDirections() { + public void testFourDirections() { // right cell @@ -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 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 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 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 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) { diff --git a/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOptionTest.java b/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOptionTest.java new file mode 100644 index 000000000..97a869026 --- /dev/null +++ b/fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/NeighborFilteringOptionTest.java @@ -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)); + } + +} \ No newline at end of file