Add unit tests for spatial indexing and random number generation utilities

This commit is contained in:
extio-de
2025-12-21 23:47:14 +01:00
parent 5470c3a180
commit bcf44bb8e2
7 changed files with 923 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.spatial2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.junit.jupiter.api.Test;
import de.extio.game_engine.spatial2.model.Area2;
import de.extio.game_engine.spatial2.model.CoordD2;
import de.extio.game_engine.spatial2.model.CoordI2;
import de.extio.game_engine.spatial2.model.Edge2;
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
import de.extio.game_engine.spatial2.model.MutableCoordD2;
public class WorldUtils2Tests {
@Test
public void testVectorAngle() {
CoordD2 v0 = MutableCoordD2.create(0.0, 0.0);
CoordD2 v1 = MutableCoordD2.create(0.0, 0.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(0.0, 0.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(0.0, 0.0);
v1 = MutableCoordD2.create(-1.0, 0.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(0.5, 0.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(-1.0, 0.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(-1.0, 1.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(-0.5, 1.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(-1.0, 5.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(1.0, 0.0);
v1 = MutableCoordD2.create(0.0, -1.0);
this.calcAngle(v0, v1);
v0 = MutableCoordD2.create(-0.31617965644035745, 0.21078643762690494);
v1 = MutableCoordD2.create(-0.29595508588991065, 0.19730339059327376);
this.calcAngle(v0, v1);
}
@Test
public void testVectorAngle2() {
for (double i = -1.0; i < 1.0; i += 0.2) {
for (double ii = -1.0; ii < 1.0; ii += 0.2) {
final CoordD2 v0 = MutableCoordD2.create(i, ii);
final CoordD2 v1 = MutableCoordD2.create(ii, i);
this.calcAngle(v0, v1);
}
}
}
@Test
public void testWorldUtils2PointsToArea() {
final CoordI2 point0 = ImmutableCoordI2.create(6, 8);
final CoordI2 point1 = ImmutableCoordI2.create(6, 9);
assertEquals(ImmutableCoordI2.create(6, 8), WorldUtils2.pointsToArea(point0, point1).getPosition());
assertEquals(ImmutableCoordI2.create(1, 2), WorldUtils2.pointsToArea(point0, point1).getDimension());
assertEquals(ImmutableCoordI2.create(6, 8), WorldUtils2.pointsToArea(point1, point0).getPosition());
assertEquals(ImmutableCoordI2.create(1, 2), WorldUtils2.pointsToArea(point1, point0).getDimension());
}
@Test
public void testPointInCircle() {
for (double n = -Math.PI; n < Math.PI; n += 0.1) {
System.out.println(n + " " + Math.cos(n) + " " + Math.sin(n));
}
}
@Test
public void testSector() {
final Area2 area = new Area2(ImmutableCoordI2.create(100, 100), ImmutableCoordI2.create(20, 20));
assertEquals(Edge2.RIGHT, WorldUtils2.getSector(ImmutableCoordI2.create(120, 110), area));
assertEquals(Edge2.LEFT, WorldUtils2.getSector(ImmutableCoordI2.create(105, 110), area));
assertEquals(Edge2.TOP, WorldUtils2.getSector(ImmutableCoordI2.create(110, 100), area));
assertEquals(Edge2.BOTTOM, WorldUtils2.getSector(ImmutableCoordI2.create(110, 120), area));
}
@Test
public void testPedalNaN() {
final CoordD2 result = WorldUtils2.getPedalOnLineSegmentAB(ImmutableCoordI2.create(-802, -905), ImmutableCoordI2.create(-805, -887), ImmutableCoordI2.create(-804, -893));
assertNull(result);
}
private void calcAngle(final CoordD2 v0, final CoordD2 v1) {
System.out.println(WorldUtils2.getVectorAngle(v0, v1) + " " + v0 + " " + v1);
}
}

View File

@@ -0,0 +1,340 @@
/*
* Copyright (C) 2023 Stephan Birkl - All Rights Reserved. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.spatial2.index;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import de.extio.game_engine.spatial2.model.Area2;
import de.extio.game_engine.spatial2.model.CoordI2;
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
import de.extio.game_engine.spatial2.model.SpatialIndex2Capable;
import de.extio.game_engine.util.rng.XorShift128Random;
@SuppressWarnings("resource")
public class QuadTreeTests {
@Test
public void testQuadTreeDim1Inserts() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
index.add(new TestEntity(ImmutableCoordI2.create(x, y), ImmutableCoordI2.one()));
}
}
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
final TestEntity entity = index.find(ImmutableCoordI2.create(x, y), ImmutableCoordI2.one()).get(0);
assertEquals(x, entity.getPosition().getX());
assertEquals(y, entity.getPosition().getY());
}
}
}
@Test
public void testQuadTreeNDimInserts() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int i = 10; i < 300; i += 20) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i)));
}
for (int i = 290; i > 0; i -= 20) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i)));
}
for (int i = 15; i < 300; i += 10) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i)));
}
for (int i = 10; i < 300; i += 20) {
final List<TestEntity> objs = index.find(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i));
final int iF = i;
assertTrue(objs.stream().anyMatch(e -> e.getPosition().getX() == iF), String.valueOf(i));
}
for (int i = 290; i > 0; i -= 20) {
final List<TestEntity> objs = index.find(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i));
final int iF = i;
assertTrue(objs.stream().anyMatch(e -> e.getPosition().getX() == iF), String.valueOf(i));
}
for (int i = 15; i < 300; i += 10) {
final List<TestEntity> objs = index.find(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.create(i, i));
final int iF = i;
assertTrue(objs.stream().anyMatch(e -> e.getPosition().getX() == iF), String.valueOf(i));
}
}
@Test
public void testRandomEntities() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
final Random random = new XorShift128Random(42);
final List<TestEntity> testEntities = new ArrayList<>(100);
for (int i = 0; i < 100; i++) {
testEntities.add(new TestEntity(ImmutableCoordI2.create(random.nextInt(1000), random.nextInt(1000)), ImmutableCoordI2.create(random.nextInt(29) + 1, random.nextInt(29) + 1)));
index.add(testEntities.get(i));
}
for (int i = 0; i < 100; i++) {
final TestEntity subject = testEntities.get(i);
final List<TestEntity> objs = index.find(subject);
this.checkForDuplicates(objs);
assertTrue(!objs.isEmpty(), String.valueOf(i));
assertTrue(objs.stream().anyMatch(e -> e == subject));
}
for (int i = 0; i < 100; i++) {
final TestEntity subject = testEntities.get(i);
for (int x = subject.getPosition().getX(); x < subject.getPosition().getX() + subject.getDimension().getX(); x++) {
for (int y = subject.getPosition().getY(); y < subject.getPosition().getY() + subject.getDimension().getY(); y++) {
final List<TestEntity> objs = index.find(ImmutableCoordI2.create(x, y), ImmutableCoordI2.one());
assertTrue(!objs.isEmpty(), String.valueOf(i));
assertTrue(objs.stream().anyMatch(e -> e == subject), String.valueOf(i));
}
}
}
final List<TestEntity> testEntitiesForEach = new ArrayList<>(100);
index.forEach(testEntitiesForEach::add);
this.checkForDuplicates(testEntitiesForEach);
assertEquals(testEntities.size(), testEntitiesForEach.size());
for (int i = 0; i < 100; i++) {
final TestEntity entity = testEntities.get(i);
assertTrue(testEntitiesForEach.contains(entity));
}
final List<TestEntity> testEntitiesIterator = new ArrayList<>(100);
final Iterator<TestEntity> it = index.iterator();
while (it.hasNext()) {
testEntitiesIterator.add(it.next());
}
this.checkForDuplicates(testEntitiesIterator);
assertEquals(testEntities.size(), testEntitiesIterator.size());
for (int i = 0; i < 100; i++) {
final TestEntity entity = testEntities.get(i);
assertTrue(testEntitiesIterator.contains(entity));
}
}
private void checkForDuplicates(final List<TestEntity> in) {
final List<TestEntity> entities = new ArrayList<>(in);
entities.sort((e0, e1) -> Integer.compare(e0.hashCode(), e1.hashCode()));
for (int i = 1; i < entities.size(); i++) {
if (entities.get(i - 1).equals(entities.get(i))) {
fail("Duplicate " + i);
}
}
}
@Test
public void testQuadTreeDim1LinearInserts() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int i = 1; i < 50; i++) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
}
for (int i = 0; i >= -50; i--) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
}
for (int i = -50; i < 50; i++) {
final TestEntity entity = index.find(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()).get(0);
assertEquals(i, entity.getPosition().getX());
}
}
@Test
public void testQuadTreeAddRemoveAdd() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
final List<TestEntity> testEntities = new ArrayList<>();
for (int i = 0; i < 5; i++) {
testEntities.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
index.add(testEntities.get(i));
}
index.remove(testEntities.get(0));
index.add(testEntities.get(0));
for (int i = 0; i < 5; i++) {
final List<TestEntity> result = index.find(testEntities.get(0).getPosition(), testEntities.get(0).getDimension());
assertEquals(1, result.size());
assertEquals(testEntities.get(0).getPosition().getX(), result.get(0).getPosition().getX());
assertEquals(testEntities.get(0).getPosition().getY(), result.get(0).getPosition().getY());
}
}
@Test
public void testQuadTreeRemove() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
final List<TestEntity> testEntities = new ArrayList<>();
for (int i = 0; i < 32; i++) {
testEntities.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
index.add(testEntities.get(i));
}
for (int i = 0; i < 32; i++) {
index.remove(testEntities.get(i));
}
}
@Test
public void testQueryOutsideRange() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int i = 0; i < 50; i++) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
}
assertEquals(50, index.find(new Area2(ImmutableCoordI2.create(0, 0), ImmutableCoordI2.create(50, 1))).size());
assertEquals(50, index.find(new Area2(ImmutableCoordI2.create(-10, 0), ImmutableCoordI2.create(100, 1))).size());
assertEquals(25, index.find(new Area2(ImmutableCoordI2.create(25, 0), ImmutableCoordI2.create(50, 1))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(-10, 0), ImmutableCoordI2.create(5, 1))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(100, 0), ImmutableCoordI2.create(5, 1))).size());
}
public void testQueryOutsideRange2() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int i = 0; i < 50; i++) {
index.add(new TestEntity(ImmutableCoordI2.create(i, 0), ImmutableCoordI2.one()));
}
assertEquals(50, index.find(new Area2(ImmutableCoordI2.create(-100000, -100000), ImmutableCoordI2.create(200000, 200000))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(-100000, 0), ImmutableCoordI2.create(5, 1))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(100000, 0), ImmutableCoordI2.create(5, 1))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(0, -100000), ImmutableCoordI2.create(5, 1))).size());
assertEquals(0, index.find(new Area2(ImmutableCoordI2.create(0, 100000), ImmutableCoordI2.create(5, 1))).size());
}
@Test
public void testQuadTreeExpansion() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
for (int x = 0; x < 100000; x += 1000) {
index.add(new TestEntity(ImmutableCoordI2.create(x, x), ImmutableCoordI2.one()));
}
for (int x = 0; x < 100000; x += 1000) {
final TestEntity entity = index.find(ImmutableCoordI2.create(x, x), ImmutableCoordI2.one()).get(0);
assertEquals(x, entity.getPosition().getX());
}
}
@Test
public void testQuadTreeExpansion2() {
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
index.add(new TestEntity(ImmutableCoordI2.create(1000, 0), ImmutableCoordI2.one()));
index.add(new TestEntity(ImmutableCoordI2.create(900, -5000), ImmutableCoordI2.create(1, 10000)));
index.add(new TestEntity(ImmutableCoordI2.create(-50000, -50000), ImmutableCoordI2.create(100000, 100000)));
}
@Disabled
@Test
public void testCompareToSearchIndexes() {
final int SIZE = 100000;
final Random random = new XorShift128Random(42);
final SpatialIndex2D<TestEntity> quadTree = new QuadTree<>();
final SpatialIndex2D<TestEntity> linear = new LinearSearchIndex2D<>();
final List<TestEntity> testEntities = new ArrayList<>(SIZE);
for (int i = 0; i < SIZE; i++) {
testEntities.add(new TestEntity(ImmutableCoordI2.create(random.nextInt(10000) + 1, random.nextInt(10000) + 1), ImmutableCoordI2.create(random.nextInt(29) + 1, random.nextInt(29) + 1)));
}
final List<Area2> queries = new ArrayList<>(SIZE);
for (int i = 0; i < SIZE; i++) {
queries.add(new Area2(ImmutableCoordI2.create(random.nextInt(10000), random.nextInt(10000)), ImmutableCoordI2.create(random.nextInt(499) + 1, random.nextInt(499) + 1)));
}
long start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
quadTree.add(testEntities.get(i));
}
System.out.println("QT add took " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
linear.add(testEntities.get(i));
}
System.out.println("LINEAR add took " + (System.currentTimeMillis() - start) + "ms");
long totalQT = 0;
start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
final List<TestEntity> qtResult = quadTree.find(area);
totalQT += qtResult.size();
}
System.out.println("Queried QT " + totalQT + " entities in " + (System.currentTimeMillis() - start) + "ms");
long totalLinear = 0;
start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
final List<TestEntity> bsResult = linear.find(area);
totalLinear += bsResult.size();
}
System.out.println("Queried LINEAR " + totalLinear + " entities in " + (System.currentTimeMillis() - start) + "ms");
if (totalQT != totalLinear) {
System.out.println("Error!");
}
}
private class TestEntity implements SpatialIndex2Capable {
CoordI2 position;
CoordI2 dimension;
transient long bsi2Session;
public TestEntity(final CoordI2 position, final CoordI2 dimension) {
this.position = position;
this.dimension = dimension;
}
@Override
public CoordI2 getPosition() {
return this.position;
}
@Override
public CoordI2 getDimension() {
return this.dimension;
}
@Override
public boolean isInSpatialIndex2ResultSet(final long session) {
return this.bsi2Session == session;
}
@Override
public void includeInSpatialIndex2ResultSet(final long session) {
this.bsi2Session = session;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("TestEntity [position=");
builder.append(this.position);
builder.append(", dimension=");
builder.append(this.dimension);
builder.append("]");
return builder.toString();
}
}
}

View File

@@ -0,0 +1,198 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.spatial2.index;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import de.extio.game_engine.spatial2.model.Area2;
import de.extio.game_engine.spatial2.model.CoordI2;
import de.extio.game_engine.spatial2.model.ImmutableCoordI2;
import de.extio.game_engine.spatial2.model.MutableCoordI2;
import de.extio.game_engine.spatial2.model.SpatialIndex2Capable;
import de.extio.game_engine.util.rng.XorShift128Random;
public class SpatialIndex2DTests {
@Disabled
@Test
public void testQuadTreePerformance() {
System.out.println("---");
System.out.println("testQuadTreePerformance");
final SpatialIndex2D<TestEntity> index = new QuadTree<>();
this.doTestPerformance(index);
}
@Disabled
@Test
public void testLinearPerformance() {
System.out.println("---");
System.out.println("testLinearPerformance");
final SpatialIndex2D<TestEntity> index = new LinearSearchIndex2D<>();
this.doTestPerformance(index);
}
private void doTestPerformance(final SpatialIndex2D<TestEntity> index) {
final int SIZE = 100000;
final Random random = new XorShift128Random(42);
System.gc();
try {
Thread.sleep(5000l);
}
catch (final InterruptedException e) {
e.printStackTrace();
}
// Add
final List<TestEntity> testEntities = new ArrayList<>(SIZE);
for (int i = 0; i < SIZE; i++) {
testEntities.add(new TestEntity(MutableCoordI2.create(random.nextInt(10000), random.nextInt(10000)), ImmutableCoordI2.create(random.nextInt(29) + 1, random.nextInt(29) + 1)));
}
long start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
index.add(testEntities.get(i));
}
System.out.println("Add " + SIZE + " entities: " + (System.currentTimeMillis() - start));
// Query
final List<Area2> queries = new ArrayList<>(SIZE);
for (int i = 0; i < SIZE; i++) {
queries.add(new Area2(ImmutableCoordI2.create(random.nextInt(10000), random.nextInt(10000)), ImmutableCoordI2.create(random.nextInt(499) + 1, random.nextInt(499) + 1)));
}
start = System.currentTimeMillis();
long total = 0;
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
total += index.find(area).size();
}
System.out.println("Queried " + total + " entities: " + (System.currentTimeMillis() - start));
// Move
start = System.currentTimeMillis();
final CoordI2 oldPosition = MutableCoordI2.create();
for (int i = 0; i < SIZE; i++) {
final TestEntity entity = testEntities.get(i);
oldPosition.setXY(entity.getPosition());
entity.getPosition().add(1);
index.move(testEntities.get(i), oldPosition, entity.getDimension());
}
System.out.println("Moved all entities: " + (System.currentTimeMillis() - start));
// Query
start = System.currentTimeMillis();
total = 0;
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
total += index.find(area).size();
}
System.out.println("Queried " + total + " entities: " + (System.currentTimeMillis() - start));
// Remove
start = System.currentTimeMillis();
final int cntDelete = SIZE / 2;
for (int i = 0; i < cntDelete; i++) {
index.remove(testEntities.get(i));
}
System.out.println("Removed " + cntDelete + " entities: " + (System.currentTimeMillis() - start));
// Query
start = System.currentTimeMillis();
total = 0;
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
total += index.find(area).size();
}
System.out.println("Queried " + total + " entities: " + (System.currentTimeMillis() - start));
// Clear
start = System.currentTimeMillis();
index.clear();
System.out.println("Clear all entities: " + (System.currentTimeMillis() - start));
// Add
start = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
index.add(testEntities.get(i));
}
System.out.println("Add " + SIZE + " entities: " + (System.currentTimeMillis() - start));
// Query
start = System.currentTimeMillis();
total = 0;
for (int i = 0; i < SIZE; i++) {
final Area2 area = queries.get(i);
total += index.find(area).size();
}
System.out.println("Queried " + total + " entities: " + (System.currentTimeMillis() - start));
System.gc();
try {
Thread.sleep(5000l);
}
catch (final InterruptedException e) {
e.printStackTrace();
}
}
private class TestEntity implements SpatialIndex2Capable {
CoordI2 position;
CoordI2 dimension;
transient long bsi2Session;
public TestEntity(final CoordI2 position, final CoordI2 dimension) {
this.position = position;
this.dimension = dimension;
}
@Override
public CoordI2 getPosition() {
return this.position;
}
@Override
public CoordI2 getDimension() {
return this.dimension;
}
@Override
public boolean isInSpatialIndex2ResultSet(final long session) {
return this.bsi2Session == session;
}
@Override
public void includeInSpatialIndex2ResultSet(final long session) {
this.bsi2Session = session;
}
}
}

View File

@@ -0,0 +1,54 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.util.rng;
import java.util.Random;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class JavaReferenceRandomTests {
@Disabled
@Test
public void testReferenceRandom() {
final Random random = new Random(42);
System.out.println("nextDouble()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextDouble());
}
System.out.println("nextInt()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt());
}
System.out.println("nextInt(5)");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt(5));
}
System.out.println("nextLong()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextLong());
}
System.out.println("nextBoolean()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextBoolean());
}
System.out.println();
System.out.println("Performance:");
final long start = System.currentTimeMillis();
long a = 5;
for (int i = 0; i < 1000000000; i++) {
a = a + random.nextLong();
}
System.out.println(a + " " + (System.currentTimeMillis() - start));
}
}

View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.util.rng;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import org.junit.jupiter.api.Test;
public class JavaThreadLocalRandomTests {
@Test
public void testReferenceRandom() {
final Random random = ThreadLocalRandom.current();
System.out.println("nextDouble()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextDouble());
}
System.out.println("nextInt()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt());
}
System.out.println("nextInt(5)");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt(5));
}
System.out.println("nextLong()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextLong());
}
System.out.println("nextBoolean()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextBoolean());
}
System.out.println();
System.out.println("Performance longs:");
long start = System.currentTimeMillis();
long a = 5;
for (int i = 0; i < 1000000000; i++) {
a = a + random.nextLong();
}
System.out.println(a + " " + (System.currentTimeMillis() - start));
System.out.println();
System.out.println("Performance ints:");
start = System.currentTimeMillis();
int b = 5;
for (int i = 0; i < 1000000000; i++) {
b = b + random.nextInt();
}
System.out.println(b + " " + (System.currentTimeMillis() - start));
}
}

View File

@@ -0,0 +1,101 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.util.rng;
import java.util.Random;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class XorShift128RandomTests {
@Test
public void testXorShift128Random() {
final Random random = new XorShift128Random(42);
System.out.println("nextDouble()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextDouble());
}
System.out.println("nextInt()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt());
}
System.out.println("nextInt(5)");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextInt(5));
}
System.out.println("nextLong()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextLong());
}
System.out.println("nextBoolean()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextBoolean());
}
System.out.println();
System.out.println("Performance longs:");
long start = System.currentTimeMillis();
long a = 5;
for (int i = 0; i < 1000000000; i++) {
a = a + random.nextLong();
}
System.out.println(a + " " + (System.currentTimeMillis() - start));
System.out.println();
System.out.println("Performance ints:");
start = System.currentTimeMillis();
int b = 5;
for (int i = 0; i < 1000000000; i++) {
b = b + random.nextInt();
}
System.out.println(b + " " + (System.currentTimeMillis() - start));
}
@Test
public void testXorShift128RandomSeed0() {
final Random random = new XorShift128Random(0);
System.out.println("nextDouble()");
for (int i = 0; i < 10; i++) {
System.out.println(random.nextDouble());
}
}
@Test
public void testXorShift128RandomIntRange() {
final Random random = new XorShift128Random(777);
for (int i = 1; i < 10; i++) {
for (int ii = 0; ii < 10; ii++) {
System.out.println(i + " " + ii + " random.nextInt(i): " + random.nextInt(i));
}
}
}
@Test
@Disabled
public void testXorShift128RandomDoubleRange() {
final Random random = new XorShift128Random();
final int[] buckets = new int[1000];
for (int i = 0; i < 1000000; i++) {
final double n = random.nextDouble();
final int bucket = (int) Math.floor(n / 0.001);
buckets[bucket]++;
}
for (int i = 0; i < 1000; i++) {
System.out.println(String.format("%03d", i) + " " + buckets[i]);
}
}
}

View File

@@ -0,0 +1,52 @@
/* Copyright (C) 2023 Stephan Birkl - All Rights Reserved.
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.extio.game_engine.util.rng;
import java.util.Random;
import org.junit.jupiter.api.Test;
public class ZeroRandomTests {
@Test
public void testSpeedRunRandom() {
final Random speedRunRandom = new ZeroRandom();
System.out.println("nextDouble()");
for (int i = 0; i < 10; i++) {
System.out.println(speedRunRandom.nextDouble());
}
System.out.println("nextInt()");
for (int i = 0; i < 10; i++) {
System.out.println(speedRunRandom.nextInt());
}
System.out.println("nextInt(5)");
for (int i = 0; i < 10; i++) {
System.out.println(speedRunRandom.nextInt(5));
}
System.out.println("nextLong()");
for (int i = 0; i < 10; i++) {
System.out.println(speedRunRandom.nextLong());
}
System.out.println("nextBoolean()");
for (int i = 0; i < 10; i++) {
System.out.println(speedRunRandom.nextBoolean());
}
System.out.println();
System.out.println("Performance:");
final long start = System.currentTimeMillis();
long a = 5;
for (int i = 0; i < 1000000000; i++) {
a = a + speedRunRandom.nextLong();
}
System.out.println(a + " " + (System.currentTimeMillis() - start));
}
}