Skip to content

Commit bb60463

Browse files
feat: Support 8 directional Grids
Co-authored-by: Jean-René Lavoie <>
1 parent f0cae6a commit bb60463

File tree

4 files changed

+167
-6
lines changed

4 files changed

+167
-6
lines changed

fxgl-core/src/main/java/com/almasb/fxgl/core/collection/grid/Grid.java

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package com.almasb.fxgl.core.collection.grid;
88

99
import com.almasb.fxgl.core.math.FXGLMath;
10+
import static com.almasb.fxgl.core.collection.grid.NeighborFilteringOption.*;
1011

1112
import java.lang.reflect.Array;
1213
import java.util.ArrayList;
@@ -15,7 +16,6 @@
1516
import java.util.Random;
1617
import java.util.function.Consumer;
1718
import java.util.function.Predicate;
18-
import java.util.stream.Collectors;
1919

2020
/**
2121
* @param <T> cell type
@@ -98,7 +98,6 @@ public final int getCellHeight() {
9898
return cellHeight;
9999
}
100100

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

126125
/**
127-
* Note: returned cells are in the grid (i.e. bounds are checked).
128-
* Diagonal cells are not included.
126+
* Note: returned cells are in the grid (i.e. bounds are checked). (defaulted to 4 directions)
129127
* The order is left, up, right, down.
130128
*
131129
* @return a new list of neighboring cells to given (x, y)
132130
*/
133131
public final List<T> getNeighbors(int x, int y) {
132+
return getNeighbors(x, y, FOUR_DIRECTIONS);
133+
}
134+
135+
/**
136+
* Note: returned cells are in the grid (i.e. bounds are checked).
137+
* NeighborFilteringOption allow filtering based on desired # of directions
138+
* The order is left, up, right, down. + "Optionally" up-left, up-right, down-left, down-right
139+
*
140+
* @return a new list of neighboring cells to given (x, y)
141+
*/
142+
public final List<T> getNeighbors(int x, int y, NeighborFilteringOption neighborFilteringOption) {
134143
List<T> result = new ArrayList<>();
135144
getLeft(x, y).ifPresent(result::add);
136145
getUp(x, y).ifPresent(result::add);
137146
getRight(x, y).ifPresent(result::add);
138147
getDown(x, y).ifPresent(result::add);
148+
149+
// Include "Corner" neighbors when eight directions
150+
if(neighborFilteringOption.is(EIGHT_DIRECTIONS)) {
151+
getUpLeft(x, y).ifPresent(result::add);
152+
getUpRight(x, y).ifPresent(result::add);
153+
getDownLeft(x, y).ifPresent(result::add);
154+
getDownRight(x, y).ifPresent(result::add);
155+
}
156+
139157
return result;
140158
}
141159

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

192+
public final Optional<T> getUpRight(Cell cell) {
193+
return getUpRight(cell.getX(), cell.getY());
194+
}
195+
196+
public final Optional<T> getUpLeft(Cell cell) {
197+
return getUpLeft(cell.getX(), cell.getY());
198+
}
199+
200+
public final Optional<T> getDownRight(Cell cell) {
201+
return getDownRight(cell.getX(), cell.getY());
202+
}
203+
204+
public final Optional<T> getDownLeft(Cell cell) {
205+
return getDownLeft(cell.getX(), cell.getY());
206+
}
207+
174208
public final Optional<T> getRight(int x, int y) {
175209
return getOptional(x + 1, y);
176210
}
@@ -187,6 +221,23 @@ public final Optional<T> getDown(int x, int y) {
187221
return getOptional(x, y + 1);
188222
}
189223

224+
public final Optional<T> getUpRight(int x, int y) {
225+
return getOptional(x + 1, y - 1);
226+
}
227+
228+
public final Optional<T> getUpLeft(int x, int y) {
229+
return getOptional(x - 1, y - 1);
230+
}
231+
232+
public final Optional<T> getDownRight(int x, int y) {
233+
return getOptional(x + 1, y + 1);
234+
}
235+
236+
public final Optional<T> getDownLeft(int x, int y) {
237+
return getOptional(x - 1, y + 1);
238+
}
239+
240+
190241
/**
191242
* @param x pixel coord x
192243
* @param y pixel coord y
@@ -248,7 +299,7 @@ public final Optional<T> getRandomCell(Predicate<T> predicate) {
248299
public final Optional<T> getRandomCell(Random random, Predicate<T> predicate) {
249300
List<T> filtered = getCells().stream()
250301
.filter(predicate)
251-
.collect(Collectors.toList());
302+
.toList();
252303

253304
if (filtered.isEmpty())
254305
return Optional.empty();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* FXGL - JavaFX Game Library. The MIT License (MIT).
3+
* Copyright (c) AlmasB (almaslvl@gmail.com).
4+
* See LICENSE for details.
5+
*/
6+
7+
package com.almasb.fxgl.core.collection.grid;
8+
9+
10+
/**
11+
* Define Movement Directions
12+
*
13+
* @author Jean-Rene Lavoie (jeanrlavoie@gmail.com)
14+
*/
15+
public enum NeighborFilteringOption {
16+
17+
FOUR_DIRECTIONS, EIGHT_DIRECTIONS;
18+
19+
public boolean is(NeighborFilteringOption... neighborFilteringOptions) {
20+
for(NeighborFilteringOption neighborFilteringOption : neighborFilteringOptions) {
21+
if(neighborFilteringOption.equals(this)) {
22+
return true;
23+
}
24+
}
25+
return false;
26+
}
27+
28+
}

fxgl-core/src/test/java/com/almasb/fxgl/core/collection/grid/GridTest.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ public void testGetNeighbors() {
142142
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)));
143143
}
144144

145+
@Test
146+
public void testGetNeighborsEightDirections() {
147+
assertThat(grid.getNeighbors( 3,3, NeighborFilteringOption.EIGHT_DIRECTIONS), containsInAnyOrder(
148+
grid.get(2, 2), grid.get(2, 3), grid.get(2, 4),
149+
grid.get(3, 2), grid.get(3, 4), // Doesn't contain 3, 3 (self)
150+
grid.get(4, 2), grid.get(4, 3), grid.get(4, 4)
151+
));
152+
}
153+
145154
@Test
146155
public void testGetRandomCell() {
147156
for (int i = 0; i < 50; i++) {
@@ -165,7 +174,7 @@ public void testRandomCell() {
165174
}
166175

167176
@Test
168-
public void testDirections() {
177+
public void testFourDirections() {
169178

170179
// right cell
171180

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

221+
@Test
222+
public void testEightDirections() {
223+
// up right cell
224+
Optional<MockCell> upRightCell = grid.getUpRight(grid.get(1, 1));
225+
226+
assertThat(upRightCell.isPresent(), is(true));
227+
assertThat(upRightCell.get().getX(), is(2));
228+
assertThat(upRightCell.get().getY(), is(0));
229+
230+
assertThat(grid.getUpRight(grid.get(0, 0)).isPresent(), is(false));
231+
assertThat(grid.getUpRight(grid.get(0, GRID_SIZE-1)).isPresent(), is(true));
232+
assertThat(grid.getUpRight(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
233+
assertThat(grid.getUpRight(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));
234+
235+
// up left Cell
236+
Optional<MockCell> upLeftCell = grid.getUpLeft(grid.get(1, 1));
237+
238+
assertThat(upLeftCell.isPresent(), is(true));
239+
assertThat(upLeftCell.get().getX(), is(0));
240+
assertThat(upLeftCell.get().getY(), is(0));
241+
242+
assertThat(grid.getUpLeft(grid.get(0, 0)).isPresent(), is(false));
243+
assertThat(grid.getUpLeft(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
244+
assertThat(grid.getUpLeft(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
245+
assertThat(grid.getUpLeft(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(true));
246+
247+
// down right Cell
248+
Optional<MockCell> downRightCell = grid.getDownRight(grid.get(1, 1));
249+
250+
assertThat(downRightCell.isPresent(), is(true));
251+
assertThat(downRightCell.get().getX(), is(2));
252+
assertThat(downRightCell.get().getY(), is(2));
253+
254+
assertThat(grid.getDownRight(grid.get(0, 0)).isPresent(), is(true));
255+
assertThat(grid.getDownRight(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
256+
assertThat(grid.getDownRight(grid.get(GRID_SIZE-1, 0)).isPresent(), is(false));
257+
assertThat(grid.getDownRight(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));
258+
259+
// down left cell
260+
Optional<MockCell> downLeftCell = grid.getDownLeft(grid.get(1, 1));
261+
262+
assertThat(downLeftCell.isPresent(), is(true));
263+
assertThat(downLeftCell.get().getX(), is(0));
264+
assertThat(downLeftCell.get().getY(), is(2));
265+
266+
assertThat(grid.getDownLeft(grid.get(0, 0)).isPresent(), is(false));
267+
assertThat(grid.getDownLeft(grid.get(0, GRID_SIZE-1)).isPresent(), is(false));
268+
assertThat(grid.getDownLeft(grid.get(GRID_SIZE-1, 0)).isPresent(), is(true));
269+
assertThat(grid.getDownLeft(grid.get(GRID_SIZE-1, GRID_SIZE-1)).isPresent(), is(false));
270+
}
271+
272+
212273
public static class MockCell extends Cell {
213274

214275
public MockCell(int x, int y) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* FXGL - JavaFX Game Library. The MIT License (MIT).
3+
* Copyright (c) AlmasB (almaslvl@gmail.com).
4+
* See LICENSE for details.
5+
*/
6+
7+
package com.almasb.fxgl.core.collection.grid;
8+
9+
import org.junit.jupiter.api.Test;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
public class NeighborFilteringOptionTest {
14+
15+
@Test
16+
public void testIs() {
17+
assertTrue(NeighborFilteringOption.FOUR_DIRECTIONS.is(NeighborFilteringOption.FOUR_DIRECTIONS));
18+
assertFalse(NeighborFilteringOption.EIGHT_DIRECTIONS.is(NeighborFilteringOption.FOUR_DIRECTIONS));
19+
}
20+
21+
}

0 commit comments

Comments
 (0)