package squidpony.squidmath; import org.junit.Test; import squidpony.squidai.AimLimit; import squidpony.squidai.Reach; import squidpony.squidgrid.FOV; import squidpony.squidgrid.Radius; import squidpony.squidgrid.mapping.DungeonGenerator; import squidpony.squidgrid.mapping.DungeonUtility; import squidpony.squidgrid.mapping.SerpentMapGenerator; import squidpony.squidgrid.mapping.styled.TilesetType; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashSet; import static org.junit.Assert.*; import static squidpony.squidmath.CoordPacker.*; /** * Created by Tommy Ettinger on 10/1/2015. */ public class CoordPackerTest { public static short[] dataCross = unionPacked(rectangle(25, 2, 14, 60), rectangle(2, 25, 60, 14)); public static short[] dataCross2 = unionPacked(rectangle(24, 2, 16, 60), rectangle(2, 24, 60, 16)); public static StatefulRNG srng = new StatefulRNG(0x1337BEEF); @Test public void testBasics() { //printPacked(dataCross, 64, 64); assertArrayEquals(dataCross, unionPacked(rectangle(25, 2, 14, 60), rectangle(2, 25, 60, 14))); short[] singleNegative = negatePacked(unionPacked(rectangle(25, 2, 14, 60), rectangle(2, 25, 60, 14))), doubleNegative = negatePacked(singleNegative); assertArrayEquals(dataCross, doubleNegative); } public static int FOV_RANGE = 12; public static Radius RADIUS = Radius.SQUARE; public void printBits16(int n) { for (int i = 0x8000; i > 0; i >>= 1) System.out.print((n & i) > 0 ? 1 : 0); } public void printBits32(int n) { for (int i = 1 << 31; i != 0; i >>>= 1) System.out.print((n & i) != 0 ? 1 : 0); } public long arrayMemoryUsage(int length, long bytesPerItem) { return (((bytesPerItem * length + 12 - 1) / 8) + 1) * 8L; } public long arrayMemoryUsage2D(int xSize, int ySize, long bytesPerItem) { return arrayMemoryUsage(xSize, (((bytesPerItem * ySize + 12 - 1) / 8) + 1) * 8L); } public int arrayMemoryUsageJagged(short[][] arr) { int ctr = 0; for (int i = 0; i < arr.length; i++) { ctr += arrayMemoryUsage(arr[i].length, 2); } return (((ctr + 12 - 1) / 8) + 1) * 8; } @Test public void testBraille() { String encoded = encodeBraille(dataCross2); //System.out.println(encoded); //System.out.println("short array length: " + dataCross2.length); //System.out.println("encoded length: " + encoded.length()); short[] decoded = decodeBraille(encoded); assertArrayEquals(dataCross2, decoded); } @Test public void testHilbertCurve() { assertEquals(0, posToHilbert(0, 0)); assertEquals(21845, posToHilbert(255, 0)); assertEquals(65535, posToHilbert(0, 255)); assertEquals(43690, posToHilbert(255, 255)); assertEquals(43690, coordToHilbert(Coord.get(255, 255))); assertEquals(posToHilbert(255, 255), coordToHilbert(Coord.get(255, 255))); assertEquals(Coord.get(255, 255), hilbertToCoord(coordToHilbert(Coord.get(255, 255)))); } //@Test public void testHilbertCurve3D() { for(int i : new int[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31,32,33,63,64,255,256,4092,4093,4094,4095}) System.out.println("index " + i + ", x:" + hilbert3X[i] + ", y:" + hilbert3Y[i] + ", z:" + hilbert3Z[i]); } @Test public void testMooreCurve3D() { int x0 = getXMoore3D(0, 3), y0 = getYMoore3D(0, 3), z0 = getZMoore3D(0, 3), x1, y1, z1; for (int s = 1; s < 16 * 16 * 8 * 3; s++) { x1 = getXMoore3D(s, 3); y1 = getYMoore3D(s, 3); z1 = getZMoore3D(s, 3); assertEquals(1, Math.abs(x0 - x1) + Math.abs(y0 - y1) + Math.abs(z0 - z1)); x0 = x1; y0 = y1; z0 = z1; } } //@Test public void testMooreCurve3DOld() { for (int s = 0; s < 12; s++) { for (int i0 : new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 31, 32, 33, 63, 64, 255, 256, 511, 512, 1023, 1024, 4092, 4093, 4094, 4095}) { int i = i0 + s * 4096; System.out.println("index " + i + ", sector " + (i >> 12) + ", x:" + getXMoore3D(i, 3) + ", y:" + getYMoore3D(i, 3) + ", z:" + getZMoore3D(i, 3)); } } } //@Test public void testMooreCurve() { for (int i = 0; i < 256; i++) { System.out.println("index " + i + "x:" + mooreX[i] + ", y:" + mooreY[i] + ", dist:" + mooreDistances[mooreX[i] + (mooreY[i] << 4)]); } } @Test public void testTranslate() { short[] packed = new short[]{0, 4}, squashed = new short[]{0, 1}; short[] translated = translate(packed, -2, -2, 60, 60); assertArrayEquals(squashed, translated); /* false true true false */ /* MOVE OVER, X 1, limit width to 2 false true false true */ boolean[][] grid = new boolean[][]{new boolean[]{false, true}, new boolean[]{true, false}}; boolean[][] grid2 = new boolean[][]{new boolean[]{false, false}, new boolean[]{true, true}}; short[] packed2 = pack(grid), packed3 = pack(grid2); short[] translated2 = translate(packed2, 1, 0, 2, 2); assertArrayEquals(packed3, translated2); short[] crossZeroTranslated = translate(dataCross, 0, 0, 64, 64); short[] crossTranslated = translate(dataCross, 1, 1, 64, 64); short[] crossUnTranslated = translate(crossTranslated, -1, -1, 64, 64); assertArrayEquals(dataCross, crossZeroTranslated); assertArrayEquals(dataCross, crossUnTranslated); short[] crossBox = translate(translate(dataCross, 25, 25, 64, 64), -50, -50, 64, 64); //printPacked(crossBox, 64, 64); assertArrayEquals(crossBox, rectangle(14, 14)); } @Test public void testUnion() { short[] union = unionPacked(new short[]{300, 5, 6, 8, 2, 4}, new short[]{290, 12, 9, 1}); // 300, 5, 6, 8, 2, 4 // 290, 12, 9, 1 // = // 290, 15, 6, 8, 2, 4 /* System.out.println("Union: "); for (int i = 0; i < union.length; i++) { System.out.print(union[i] + ", "); } System.out.println(); */ assertArrayEquals(new short[]{290, 15, 6, 8, 2, 4}, union); union = unionPacked(new short[]{300, 5, 6, 8, 2, 4}, new short[]{290, 10, 10, 1}); /* System.out.println("Union: "); for (int i = 0; i < union.length; i++) { System.out.print(union[i] + ", "); } System.out.println(); */ assertArrayEquals(new short[]{290, 15, 5, 9, 2, 4}, union); short[] intersect = intersectPacked(new short[]{300, 5, 6, 8, 2, 4}, new short[]{290, 12, 9, 1}); // 300, 5, 6, 8, 2, 4 // 290, 12, 9, 1 // = // 300, 2, 9, 1 /* System.out.println("Intersect: "); for (int i = 0; i < intersect.length; i++) { System.out.print(intersect[i] + ", "); } System.out.println(); */ assertArrayEquals(new short[]{300, 2, 9, 1}, intersect); intersect = intersectPacked(new short[]{300, 5, 6, 8, 2, 4}, new short[]{290, 10, 11, 1}); /* System.out.println("Intersect: "); for (int i = 0; i < intersect.length; i++) { System.out.print(intersect[i] + ", "); } System.out.println(); */ assertArrayEquals(new short[]{311, 1}, intersect); short[] box = translate(translate(translate(dataCross, 25, 25, 64, 64), -50, -50, 64, 64), 25, 25, 64, 64); assertArrayEquals(box, intersectPacked(rectangle(25, 2, 14, 60), rectangle(2, 25, 60, 14))); short[] minus = differencePacked(dataCross, box); short[] xor = xorPacked(rectangle(25, 2, 14, 60), rectangle(2, 25, 60, 14)); assertArrayEquals(minus, xor); } @Test public void testExpanding() { /* StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(60, 60, rng); char[][] map = dungeonGenerator.generate(); short[] floors = pack(map, '.'); Coord viewer = dungeonGenerator.utility.randomCell(floors); FOV fov = new FOV(FOV.SHADOW); double[][] seen = fov.calculateFOV(DungeonUtility.generateResistances(map), viewer.x, viewer.y, FOV_RANGE, RADIUS); short[] visible = pack(seen); short[] fringe = fringe(visible, 1, 60, 60); printPacked(fringe, 60, 60); short[][] fringes = fringes(visible, 6, 60, 60); for (int i = 0; i < 6; i++) { printPacked(intersectPacked(fringes[i], floors), 60, 60); } */ short[] edge = fringe(dataCross, 1, 64, 64); //printPacked(edge, 64, 64); short[] bonus = expand(dataCross, 1, 64, 64); //printPacked(bonus, 64, 64); assertArrayEquals(differencePacked(bonus, edge), dataCross); short[] flooded = flood(dataCross, packSeveral(Coord.get(26, 2)), 2); short[] manual = packSeveral(Coord.get(25, 2), Coord.get(26, 2), Coord.get(27, 2), Coord.get(28, 2), Coord.get(25, 3), Coord.get(26, 3), Coord.get(27, 3), Coord.get(26, 4)); //printPacked(flooded, 64, 64); assertArrayEquals(flooded, manual); flooded = spill(dataCross, packOne(27, 4), 30, srng); //printPacked(flooded, 64, 64); //System.out.println(count(flooded)); /* flooded = spill(dataCross, packOne(27, 4), count(dataCross), srng); printPacked(flooded, 64, 64); System.out.println(count(flooded));*/ } @Test public void testRetracting() { /* StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(60, 60, rng); char[][] map = dungeonGenerator.generate(); short[] floors = pack(map, '.'); Coord viewer = dungeonGenerator.utility.randomCell(floors); FOV fov = new FOV(FOV.SHADOW); double[][] seen = fov.calculateFOV(DungeonUtility.generateResistances(map), viewer.x, viewer.y, FOV_RANGE, RADIUS); short[] visible = pack(seen); short[] fringe = fringe(visible, 1, 60, 60); printPacked(fringe, 60, 60); short[][] fringes = fringes(visible, 6, 60, 60); for (int i = 0; i < 6; i++) { printPacked(intersectPacked(fringes[i], floors), 60, 60); } */ short[] surf = surface(dataCross, 1, 64, 64); //printPacked(surf, 64, 64); short[] shrunk = retract(dataCross, 1, 64, 64); //printPacked(shrunk, 64, 64); assertArrayEquals(unionPacked(shrunk, surf), dataCross); } /* @Test public void testFloodRadiate() { /* short[] flooded = flood(dataCross, packSeveral(Coord.get(26, 2)), 2); short[] manual = packSeveral(Coord.get(25, 2), Coord.get(26, 2), Coord.get(27, 2), Coord.get(28, 2), Coord.get(25, 3), Coord.get(26, 3), Coord.get(27, 3), Coord.get(26, 4)); //printPacked(flooded, 64, 64); assertArrayEquals(flooded, manual); * / for (int i = 10; i < 50; i++) { for (int j = 0; j < 10; j++) { short[] radiated = radiate(removeSeveralPacked(dataCross, Coord.get(28+j, i), Coord.get(27+j, i+1), Coord.get(28+j, i+1)), packOne(26, 23), 10); count(radiated); } } //printPacked(radiated, 64, 64); } */ @Test public void testRadiate() { short[] groupFOVed = radiate(removeSeveralPacked(dataCross, Coord.get(30, 25), Coord.get(29, 26), Coord.get(30, 26)), packOne(26, 23), 10); //printPacked(groupFOVed, 64, 64); } @Test public void testReachable() { Reach reach = new Reach(3, 8, Radius.DIAMOND); short[] groupReachable = reachable(removeSeveralPacked(dataCross, Coord.get(30, 25), Coord.get(29, 26), Coord.get(30, 26)), packOne(26, 22), reach); //printPacked(groupReachable, 64, 64); reach = new Reach(3, 8, Radius.DIAMOND, AimLimit.ORTHOGONAL); groupReachable = reachable(removeSeveralPacked(dataCross, Coord.get(30, 25), Coord.get(29, 26), Coord.get(30, 26)), packOne(26, 22), reach); //printPacked(groupReachable, 64, 64); reach = new Reach(3, 8, Radius.DIAMOND, AimLimit.EIGHT_WAY); groupReachable = reachable(removeSeveralPacked(dataCross, Coord.get(30, 25), Coord.get(29, 26), Coord.get(30, 26)), packOne(26, 22), reach); //printPacked(groupReachable, 64, 64); } //@Test public void testFraction() { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(60, 60, rng); SerpentMapGenerator serpent = new SerpentMapGenerator(60, 60, rng); serpent.putRoundRoomCarvers(1); serpent.putBoxRoomCarvers(1); serpent.putCaveCarvers(1); char[][] map = dungeonGenerator.generate(serpent.generate()); short[] floors = pack(map, '.'); Coord[] positions = fractionPacked(floors, 29); /* System.out.println(positions.length); System.out.println(count(floors)); System.out.println(positions.length * 1.0 / count(floors)); */ printPacked(floors, 60, 60); System.out.println(); for (int i = 0; i < positions.length; i++) { map[positions[i].x][positions[i].y] = '!'; } dungeonGenerator.setDungeon(map); System.out.println(dungeonGenerator); } //Uncomment the @Test line to get a lot of printed info regarding room-finding //@Test public void testRooms() { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(60, 60, rng); SerpentMapGenerator serpent = new SerpentMapGenerator(60, 60, rng); serpent.putRoundRoomCarvers(1); serpent.putBoxRoomCarvers(1); serpent.putCaveCarvers(1); char[][] map = dungeonGenerator.generate(serpent.generate()); short[] floors = pack(map, '.'), shrunk = retract(floors, 1, 60, 60, true), rooms = flood(floors, shrunk, 2, false), corridors = differencePacked(floors, rooms), doors = intersectPacked(rooms, fringe(corridors, 1, 60, 60, false)); printPacked(floors, 60, 60); System.out.println(); printPacked(shrunk, 60, 60); System.out.println(); printPacked(rooms, 60, 60); System.out.println(); printPacked(corridors, 60, 60); System.out.println(); printPacked(doors, 60, 60); System.out.println(); ArrayList<short[]> separatedCorridors = split(corridors), separatedRooms = split(rooms); for (short[] sep : separatedRooms) { printPacked(sep, 60, 60); System.out.println(); } /* for (short[] sep : separatedCorridors) { short[] someDoors = intersectPacked(rooms, fringe(sep, 1, 60, 60, false)), connectedRooms = flood(rooms, someDoors, 512, false); printPacked(unionPacked(sep, connectedRooms), 60, 60); System.out.println(); } */ } @Test public void testPackOptimalParameters() { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(80, 80, rng); dungeonGenerator.addDoors(15, true); dungeonGenerator.addWater(25); dungeonGenerator.addTraps(2); char[][] map = dungeonGenerator.generate(TilesetType.DEFAULT_DUNGEON); FOV fov = new FOV(); double[][] resMap = DungeonUtility.generateResistances(map), seen; short[] packed; boolean[][] unpacked; int ramPacked = 0, ramBoolean = 0, ramDouble = 0; Coord viewer; for (int t = 0; t < 100; t++) { viewer = dungeonGenerator.utility.randomFloor(map); seen = fov.calculateFOV(resMap, viewer.x, viewer.y, FOV_RANGE, RADIUS); packed = pack(seen); unpacked = unpack(packed, seen.length, seen[0].length); for (int i = 0; i < unpacked.length ; i++) { for (int j = 0; j < unpacked[i].length; j++) { assertTrue((seen[i][j] > 0.0) == unpacked[i][j]); } } ramPacked += arrayMemoryUsage(packed.length, 2); ramBoolean += arrayMemoryUsage2D(seen.length, seen[0].length, 1); ramDouble += arrayMemoryUsage2D(seen.length, seen[0].length, 8); } //assertEquals("Packed shorts", 18, packed.length); //assertEquals("Unpacked doubles: ", 57600, seen.length * seen[0].length); /* System.out.println("Average Memory used by packed short[] (Appropriate):" + ramPacked / 100.0 + " bytes"); System.out.println("Average Memory used by boolean[][] (Appropriate):" + ramBoolean / 100.0 + " bytes"); System.out.println("Average Memory used by original double[][] (Appropriate):" + ramDouble / 100.0 + " bytes"); System.out.println("Average Compression, short[] vs. boolean[][] (Appropriate):" + 100.0 * ramPacked / ramBoolean + "%"); System.out.println("Average Compression, short[] vs. double[][] (Appropriate):" + 100.0 * ramPacked / ramDouble + "%"); System.out.println("FOV Map stored for every cell, booleans, 240x240: " + arrayMemoryUsage2D(240, 240, arrayMemoryUsage2D(240, 240, 1))); System.out.println("FOV Map stored for every cell, floats, 240x240: " + arrayMemoryUsage2D(240, 240, arrayMemoryUsage2D(240, 240, 4))); */ } @Test public void testPackPoorParameters() { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(30, 70, rng); dungeonGenerator.addDoors(15, true); dungeonGenerator.addWater(25); dungeonGenerator.addTraps(2); char[][] map = dungeonGenerator.generate(TilesetType.DEFAULT_DUNGEON); FOV fov = new FOV(); double[][] resMap = DungeonUtility.generateResistances(map), seen; short[] packed; boolean[][] unpacked; int ramPacked = 0, ramBoolean = 0, ramDouble = 0; Coord viewer; for (int t = 0; t < 100; t++) { viewer = dungeonGenerator.utility.randomFloor(map); seen = fov.calculateFOV(resMap, viewer.x, viewer.y, FOV_RANGE, RADIUS); packed = pack(seen); unpacked = unpack(packed, seen.length, seen[0].length); for (int i = 0; i < unpacked.length ; i++) { for (int j = 0; j < unpacked[i].length; j++) { assertTrue((seen[i][j] > 0.0) == unpacked[i][j]); } } ramPacked += arrayMemoryUsage(packed.length, 2); ramBoolean += arrayMemoryUsage2D(seen.length, seen[0].length, 1); ramDouble += arrayMemoryUsage2D(seen.length, seen[0].length, 8); } //assertEquals("Packed shorts", 18, packed.length); //assertEquals("Unpacked doubles: ", 57600, seen.length * seen[0].length); /* System.out.println("Average Memory used by packed short[] (Approaching Worst-Case):" + ramPacked / 100.0 + " bytes"); System.out.println("Average Memory used by boolean[][] (Approaching Worst-Case):" + ramBoolean / 100.0 + " bytes"); System.out.println("Average Memory used by original double[][] (Approaching Worst-Case):" + ramDouble / 100.0 + " bytes"); System.out.println("Average Compression, short[] vs. boolean[][] (Approaching Worst-Case):" + 100.0 * ramPacked / ramBoolean + "%"); System.out.println("Average Compression, short[] vs. double[][] (Approaching Worst-Case):" + 100.0 * ramPacked / ramDouble + "%"); System.out.println("FOV Map stored for every cell, booleans, 30x70: " + arrayMemoryUsage2D(30, 70, arrayMemoryUsage2D(30, 70, 1))); System.out.println("FOV Map stored for every cell, floats, 30x70: " + arrayMemoryUsage2D(30, 70, arrayMemoryUsage2D(30, 70, 4))); */ } /* @Test public void testPackPoorParameters() { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(30, 70, rng); dungeonGenerator.addDoors(15, true); dungeonGenerator.addWater(25); dungeonGenerator.addTraps(2); char[][] map = dungeonGenerator.generate(TilesetType.DEFAULT_DUNGEON); FOV fov = new FOV(); Coord viewer = dungeonGenerator.utility.randomFloor(map); map[viewer.x][viewer.y] = '@'; dungeonGenerator.setDungeon(map); //System.out.println(dungeonGenerator.toString()); double[][] resMap = DungeonUtility.generateResistances(map); double[][] seen = fov.calculateFOV(resMap, viewer.x, viewer.y, 8, Radius.DIAMOND); short[] packed = pack(seen); assertEquals("Packed shorts", 28, packed.length); assertEquals("Unpacked doubles: ", 2100, seen.length * seen[0].length); System.out.println("Memory used by packed short[] (Approaching Worst-Case):" + arrayMemoryUsage(packed.length, 2) + " bytes"); System.out.println("Memory used by boolean[][] (Approaching Worst-Case):" + arrayMemoryUsage2D(30, 70, 1) + " bytes"); System.out.println("Memory used by original double[][] (Approaching Worst-Case):" + arrayMemoryUsage2D(30, 70, 8) + " bytes"); System.out.println("Compression, short[] vs. boolean[][] (Approaching Worst-Case):" + 100.0 * arrayMemoryUsage(packed.length, 2) / arrayMemoryUsage2D(30, 70, 1) + "%"); System.out.println("Compression, short[] vs. double[][] (Approaching Worst-Case):" + 100.0 * arrayMemoryUsage(packed.length, 2) / arrayMemoryUsage2D(30, 70, 8) + "%"); boolean[][]unpacked = unpack(packed, seen.length, seen[0].length); for (int i = 0; i < unpacked.length ; i++) { for (int j = 0; j < unpacked[i].length; j++) { assertTrue((seen[i][j] > 0.0) == unpacked[i][j]); } } } */ @Test public void testPackMultiOptimalParameters() { for(int FOV_RANGE = 1; FOV_RANGE < 21; FOV_RANGE++) { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(80, 80, rng); dungeonGenerator.addDoors(15, true); dungeonGenerator.addWater(25); dungeonGenerator.addTraps(2); char[][] map = dungeonGenerator.generate(TilesetType.DEFAULT_DUNGEON); double[][] resMap = DungeonUtility.generateResistances(map), seen; FOV fov = new FOV(FOV.RIPPLE); double[] packingLevels = generatePackingLevels(FOV_RANGE), lightLevels = generateLightLevels(FOV_RANGE); short[][] packed; int ramPacked = 0, ramFloat = 0, ramDouble = 0; Coord viewer; HashSet<Double> seenValues = new HashSet<>(FOV_RANGE * 2); /* System.out.println("Packing levels at range " + FOV_RANGE + ": "); for (Double d : packingLevels) { System.out.print(d + " "); } System.out.println(); System.out.println("Light levels at range " + FOV_RANGE + ": "); for (Double d : lightLevels) { System.out.print(d + " "); } System.out.println(); */ for (int t = 0; t < 100; t++) { viewer = dungeonGenerator.utility.randomFloor(map); seen = fov.calculateFOV(resMap, viewer.x, viewer.y, FOV_RANGE, RADIUS); packed = packMulti(seen, packingLevels); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { seenValues.add(seen[i][j]); } } for (int ll = 0; ll < lightLevels.length; ll++) { boolean[][] unpackedB = unpack(packed[ll], seen.length, seen[0].length); for (int i = 0; i < unpackedB.length; i++) { for (int j = 0; j < unpackedB[i].length; j++) { assertTrue((seen[i][j] > packingLevels[ll]) == unpackedB[i][j]); } } if (ll + 1 == lightLevels.length) { assertTrue(packed[ll].length == 2); assertTrue(queryPacked(packed[ll], viewer.x, viewer.y)); } } double[][] unpacked2 = unpackMultiDouble(packed, seen.length, seen[0].length, lightLevels); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { /* if(Math.abs(seen[i][j] - unpacked2[i][j]) >= 0.75 / FOV_RANGE) { System.out.println( "seen " + seen[i][j] + ", unpacked " + unpacked2[i][j]); System.out.println(seen[i][j] - unpacked2[i][j]); System.out.println("Values present in seen at range " + FOV_RANGE + ": "); for (Double d : seenValues) { System.out.print(d + " "); } } */ assertTrue(Math.abs(seen[i][j] - unpacked2[i][j]) < 0.75 / FOV_RANGE); } } ramPacked += arrayMemoryUsageJagged(packed); ramFloat += arrayMemoryUsage2D(seen.length, seen[0].length, 4); ramDouble += arrayMemoryUsage2D(seen.length, seen[0].length, 8); } //System.out.println(dungeonGenerator.toString()); /* System.out.println("Appropriate Parameter packed values " + FOV_RANGE); for (int p = 0; p < packed.length; p++) { if (packed[p].length == 0) continue; System.out.print(packed[p][0]); for (int i = 1; i < packed[p].length; i++) { System.out.print(", " + (packed[p][i] & 0xffff)); } System.out.println(); }*/ //assertEquals("Packed shorts", 19, packed.length); //assertEquals("Unpacked doubles: ", 57600, seen.length * seen[0].length); /* System.out.println("Memory used by multi-packed short[][] (Appropriate " + FOV_RANGE + "):" + ramPacked / 100.0 + " bytes"); System.out.println("Memory used by double[][] (Appropriate " + FOV_RANGE + "):" + ramDouble / 100.0 + " bytes"); System.out.println("Memory used by float[][] (Appropriate " + FOV_RANGE + "):" + ramFloat / 100.0 + " bytes"); System.out.println("Compression vs. double[][] (Appropriate " + FOV_RANGE + "):" + 100.0 * ramPacked / ramDouble + "%"); System.out.println("Compression vs. float[][] (Appropriate " + FOV_RANGE + "):" + 100.0 * ramPacked / ramFloat + "%"); */ } /* byte[][] unpacked3 = unpackMultiByte(packed, seen.length, seen[0].length); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { System.out.print(String.format("%x", unpacked3[i][j])); } System.out.println(); } System.out.println(); */ /* byte[][] unpacked3 = unpackMultiByte(packed, seen.length, seen[0].length); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { System.out.print(unpacked3[i][j]); } System.out.println(); } System.out.println(); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { System.out.print((int) (seen[i][j] * 8.05)); } System.out.println(); }*/ } @Test public void testPackMultiPoorParameters() { for(int FOV_RANGE = 1; FOV_RANGE < 21; FOV_RANGE++) { StatefulRNG rng = new StatefulRNG(new LightRNG(0xAAAA2D2)); DungeonGenerator dungeonGenerator = new DungeonGenerator(30, 240, rng); dungeonGenerator.addDoors(15, true); dungeonGenerator.addWater(25); dungeonGenerator.addTraps(2); char[][] map = dungeonGenerator.generate(TilesetType.DEFAULT_DUNGEON); double[][] resMap = DungeonUtility.generateResistances(map), seen; FOV fov = new FOV(FOV.RIPPLE); double[] packingLevels = generatePackingLevels(FOV_RANGE), lightLevels = generateLightLevels(FOV_RANGE); short[][] packed; int ramPacked = 0, ramFloat = 0, ramDouble = 0; Coord viewer; HashSet<Double> seenValues = new HashSet<>(FOV_RANGE * 2); /* System.out.println("Packing levels at range " + FOV_RANGE + ": "); for (Double d : packingLevels) { System.out.print(d + " "); } System.out.println(); System.out.println("Light levels at range " + FOV_RANGE + ": "); for (Double d : lightLevels) { System.out.print(d + " "); } */ for (int t = 0; t < 100; t++) { viewer = dungeonGenerator.utility.randomFloor(map); seen = fov.calculateFOV(resMap, viewer.x, viewer.y, FOV_RANGE, RADIUS); packed = packMulti(seen, packingLevels); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { seenValues.add(seen[i][j]); } } for (int ll = 0; ll < lightLevels.length; ll++) { boolean[][] unpackedB = unpack(packed[ll], seen.length, seen[0].length); for (int i = 0; i < unpackedB.length; i++) { for (int j = 0; j < unpackedB[i].length; j++) { assertTrue((seen[i][j] > packingLevels[ll]) == unpackedB[i][j]); } } if (ll + 1 == lightLevels.length) { assertTrue(packed[ll].length == 2); assertTrue(queryPacked(packed[ll], viewer.x, viewer.y)); } } double[][] unpacked2 = unpackMultiDouble(packed, seen.length, seen[0].length, lightLevels); for (int j = 0; j < seen[0].length; j++) { for (int i = 0; i < seen.length; i++) { /* if(Math.abs(seen[i][j] - unpacked2[i][j]) >= 0.75 / FOV_RANGE) { System.out.println( "seen " + seen[i][j] + ", unpacked " + unpacked2[i][j]); System.out.println(seen[i][j] - unpacked2[i][j]); System.out.println("Values present in seen at range " + FOV_RANGE + ": "); for (Double d : seenValues) { System.out.print(d + " "); } System.out.println(); } */ assertTrue(Math.abs(seen[i][j] - unpacked2[i][j]) < 0.75 / FOV_RANGE); } } ramPacked += arrayMemoryUsageJagged(packed); ramFloat += arrayMemoryUsage2D(seen.length, seen[0].length, 4); ramDouble += arrayMemoryUsage2D(seen.length, seen[0].length, 8); } //System.out.println(dungeonGenerator.toString()); /* System.out.println("Appropriate Parameter packed values " + FOV_RANGE); for (int p = 0; p < packed.length; p++) { if (packed[p].length == 0) continue; System.out.print(packed[p][0]); for (int i = 1; i < packed[p].length; i++) { System.out.print(", " + (packed[p][i] & 0xffff)); } System.out.println(); }*/ //assertEquals("Packed shorts", 19, packed.length); //assertEquals("Unpacked doubles: ", 57600, seen.length * seen[0].length); /* System.out.println("Memory used by multi-packed short[][] (Approaching Worst-Case " + FOV_RANGE + "):" + ramPacked / 100.0 + " bytes"); System.out.println("Memory used by double[][] (Approaching Worst-Case " + FOV_RANGE + "):" + ramDouble / 100.0 + " bytes"); System.out.println("Memory used by float[][] (Approaching Worst-Case " + FOV_RANGE + "):" + ramFloat / 100.0 + " bytes"); System.out.println("Compression vs. double[][] (Approaching Worst-Case " + FOV_RANGE + "):" + 100.0 * ramPacked / ramDouble + "%"); System.out.println("Compression vs. float[][] (Approaching Worst-Case " + FOV_RANGE + "):" + 100.0 * ramPacked / ramFloat + "%"); */ } } @Test public void testMorton() { assertEquals(0, mortonEncode(0, 0)); assertEquals(0x5555, mortonEncode(0xFF, 0)); assertEquals(0xAAAA, mortonEncode(0, 0xFF)); assertEquals(0xFFFF, mortonEncode(0xFF, 0xFF)); assertEquals(0x7AAD, mortonEncode(0xC3, 0x7E)); assertEquals(Coord.get(0xC3, 0x7E), mortonDecode(0x7AAD)); //generateHilbert(); } public static void generateHilbert() { int sideLength = (1 << 8); int capacity = sideLength * sideLength; short[] out = new short[capacity];// xOut = new short[capacity], yOut = new short[capacity]; /* Coord c; for (int i = 0; i < capacity; i++) { c = hilbertToCoord(i); xOut[i] = (short) c.x; yOut[i] = (short) c.y; } for (int y = 0; y < sideLength; y++) { for (int x = 0; x < sideLength; x++) { out[y * sideLength + x] = (short) posToHilbert(x, y); } } try { FileChannel channel = new FileOutputStream("target/distance").getChannel(); channel.write(shortsToBytes(out)); channel.close(); } catch (IOException e) { e.printStackTrace(); } */ /* try { FileChannel channel = new FileOutputStream("target/hilbertx").getChannel(); channel.write(shortsToBytes(xOut)); channel.close(); } catch (IOException e) { e.printStackTrace(); } try { FileChannel channel = new FileOutputStream("target/hilberty").getChannel(); channel.write(shortsToBytes(yOut)); channel.close(); } catch (IOException e) { e.printStackTrace(); } */ } /* StringBuilder text = new StringBuilder(0xffff * 11); text.append("private static final short[] hilbertX = new short[] {\n"); text.append(xOut[0]); for (int i = 1, ln = 0; i < capacity; i++, ln +=4) { text.append(','); if(ln > 75) { ln = 0; text.append('\n'); } text.append(xOut[i]); } text.append("\n},\n"); text.append("hilbertY = new short[] {\n"); text.append(yOut[0]); for (int i = 1, ln = 0; i < capacity; i++, ln +=4) { text.append(','); if(ln > 75) { ln = 0; text.append('\n'); } text.append(yOut[i]); } text.append("\n}\n\n"); */ public static ByteBuffer shortsToBytes(short[] arr) { java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(arr.length * 2); bb.asShortBuffer().put(arr); return bb; } }