From fda4a9584be4570bbf98e24d6fa71053a5838ce5 Mon Sep 17 00:00:00 2001 From: austin Date: Sun, 28 May 2023 13:07:29 -0400 Subject: [PATCH] Terrain generation improvements --- src/main/java/electrosphere/engine/Main.java | 3 +- .../server/terrain/generation/Continent.java | 4 +- .../server/terrain/generation/Hotspot.java | 73 +- .../generation/InterpolationDisplay.java | 140 +-- .../server/terrain/generation/Region.java | 5 +- .../server/terrain/generation/TerrainGen.java | 831 ++++++++++-------- .../terrain/generation/TerrainGenerator.java | 748 +++++++++++----- .../server/terrain/generation/Utilities.java | 8 +- .../server/terrain/generation/Vector.java | 3 +- .../util/worldviewer/TerrainViewer.java | 17 - 10 files changed, 1106 insertions(+), 726 deletions(-) diff --git a/src/main/java/electrosphere/engine/Main.java b/src/main/java/electrosphere/engine/Main.java index 250103ad..ab9a85ab 100644 --- a/src/main/java/electrosphere/engine/Main.java +++ b/src/main/java/electrosphere/engine/Main.java @@ -15,6 +15,7 @@ import electrosphere.game.config.UserSettings; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.Model; import electrosphere.renderer.RenderingEngine; +import electrosphere.util.worldviewer.TerrainViewer; @@ -127,7 +128,7 @@ public class Main { //debug: create terrain/world viewer -// TerrainViewer.runViewer(); + // TerrainViewer.runViewer(); //create the drawing context if(Globals.RUN_CLIENT && !Globals.HEADLESS){ diff --git a/src/main/java/electrosphere/game/server/terrain/generation/Continent.java b/src/main/java/electrosphere/game/server/terrain/generation/Continent.java index 1207aca2..d3fdea6f 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/Continent.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/Continent.java @@ -1,10 +1,10 @@ package electrosphere.game.server.terrain.generation; /** - * - * @author satellite + * Contains information about a continent */ class Continent { + //dimensions of the condinent public int dim_x; public int dim_y; public int size = 0; diff --git a/src/main/java/electrosphere/game/server/terrain/generation/Hotspot.java b/src/main/java/electrosphere/game/server/terrain/generation/Hotspot.java index 40c8a27a..2671db25 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/Hotspot.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/Hotspot.java @@ -15,7 +15,7 @@ class Hotspot { TerrainGenerator parent; - public Hotspot(int x, int y, int life_max, int magnitude, TerrainGenerator parent) { + protected Hotspot(int x, int y, int life_max, int magnitude, TerrainGenerator parent) { this.x = x; this.y = y; this.life_current = 0; @@ -25,7 +25,7 @@ class Hotspot { this.parent = parent; } - public void simulate() { + protected void simulate() { if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.8f) { magnitude_current = magnitude_max; } else if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.6f) { @@ -39,103 +39,104 @@ class Hotspot { } //affect asthenosphere heat if (magnitude_current == 1) { - parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } else if (magnitude_current == 2) { - parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (y + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (y - 1 >= 0) { - parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } else if (magnitude_current == 3) { - parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (y + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } if (y - 1 >= 0) { - parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } } else if (magnitude_current == 4) { - parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (y + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } if (y - 1 >= 0) { - parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } } else if (magnitude_current == 5) { - parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (y + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } if (y - 1 >= 0) { - parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); if (x + 1 < parent.DIMENSION) { - parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } if (x - 1 >= 0) { - parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); + parent.asthenosphereHeat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2)); } } } life_current++; } - public void add_to_elevation(int x, int y, int magnitude){ + + protected void add_to_elevation(int x, int y, int magnitude){ parent.elevation[x][y] = parent.elevation[x][y] + magnitude; if(parent.elevation[x][y] > 100){ parent.elevation[x][y] = 100; diff --git a/src/main/java/electrosphere/game/server/terrain/generation/InterpolationDisplay.java b/src/main/java/electrosphere/game/server/terrain/generation/InterpolationDisplay.java index c2e54f3f..dee8ec5e 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/InterpolationDisplay.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/InterpolationDisplay.java @@ -9,52 +9,60 @@ import javax.swing.JPanel; * @author satellite */ class InterpolationDisplay extends JPanel{ + + TerrainGen parent; + + protected InterpolationDisplay(TerrainGen parent){ + this.parent = parent; + } + @Override public void paint(Graphics g) { - if(TerrainGen.display_toggle == 0) { - for (int x = 0; x < TerrainGen.DIMENSION; x++) { - for (int y = 0; y < TerrainGen.DIMENSION; y++) { - if (TerrainGen.mountainParsed[x][y] > TerrainGen.MOUNTAIN_THRESHOLD - 1) { - g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1)); - } else if (TerrainGen.oceanParsed[x][y] > TerrainGen.OCEAN_THRESHOLD - 1) { + int width = parent.continentPhaseDimension; + if(parent.displayToggle == 0) { + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + if (parent.mountainParsed[x][y] > TerrainGen.MOUNTAIN_THRESHOLD - 1) { + g.setColor(new Color((int) (parent.elevation[x][y] / 100.0 * 254 * (parent.brightness / 100.0)), 1, 1)); + } else if (parent.oceanParsed[x][y] > TerrainGen.OCEAN_THRESHOLD - 1) { g.setColor( new Color( 1, - (int) ((TerrainGen.elevation[x][y] + 50) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y] + 50) / 100.0 * 254 * (TerrainGen.brightness / 100.0)) + (int) ((parent.elevation[x][y] + 50) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y] + 50) / 100.0 * 254 * (parent.brightness / 100.0)) ) ); } else { - g.setColor(new Color(1, (int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1)); + g.setColor(new Color(1, (int) (parent.elevation[x][y] / 100.0 * 254 * (parent.brightness / 100.0)), 1)); } g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2); } } - } else if(TerrainGen.display_toggle == 1){ - for (int x = 0; x < TerrainGen.DIMENSION; x++) { - for (int y = 0; y < TerrainGen.DIMENSION; y++) { - if (TerrainGen.precipitationChart[x][y] > 0) { + } else if(parent.displayToggle == 1){ + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + if (parent.precipitationChart[x][y] > 0) { g.setColor( new Color( 1, - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)) + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)) ) ); } else { - g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1)); + g.setColor(new Color((int) (parent.elevation[x][y] / 100.0 * 254 * (parent.brightness / 100.0)), 1, 1)); } g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2); } } - } else if(TerrainGen.display_toggle == 2){ - for (int x = 0; x < TerrainGen.DIMENSION; x++) { - for (int y = 0; y < TerrainGen.DIMENSION; y++) { + } else if(parent.displayToggle == 2){ + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { // if (TerrainInterpolator.precipitation_Chart[x][y] > 0) { g.setColor( new Color( - (int) ((TerrainGen.temperatureChart[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), + (int) ((parent.temperatureChart[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), 1 ) ); @@ -64,10 +72,10 @@ class InterpolationDisplay extends JPanel{ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2); } } - } else if(TerrainGen.display_toggle == 3){ - for (int x = 0; x < TerrainGen.DIMENSION; x++) { - for (int y = 0; y < TerrainGen.DIMENSION; y++) { - if (TerrainGen.climateCategory[x][y] == 0) { + } else if(parent.displayToggle == 3){ + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + if (parent.climateCategory[x][y] == 0) { g.setColor(Color.BLUE); // g.setColor( // new Color( @@ -76,7 +84,7 @@ class InterpolationDisplay extends JPanel{ // (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)) // ) // ); - } else if(TerrainGen.climateCategory[x][y] == 1){ + } else if(parent.climateCategory[x][y] == 1){ g.setColor(Color.RED); // g.setColor( // new Color( @@ -85,7 +93,7 @@ class InterpolationDisplay extends JPanel{ // 1 // ) // ); - } else if(TerrainGen.climateCategory[x][y] == 2){ + } else if(parent.climateCategory[x][y] == 2){ g.setColor(Color.GREEN); // g.setColor( // new Color( @@ -94,7 +102,7 @@ class InterpolationDisplay extends JPanel{ // 1 // ) // ); - } else if(TerrainGen.climateCategory[x][y] == 3){ + } else if(parent.climateCategory[x][y] == 3){ g.setColor(Color.YELLOW); // g.setColor( // new Color( @@ -103,58 +111,58 @@ class InterpolationDisplay extends JPanel{ // (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)) // ) // ); - } else if(TerrainGen.climateCategory[x][y] == 4){ + } else if(parent.climateCategory[x][y] == 4){ g.setColor( new Color( - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), 1 ) ); g.setColor(Color.ORANGE); - } else if(TerrainGen.climateCategory[x][y] == 5){ + } else if(parent.climateCategory[x][y] == 5){ g.setColor( new Color( - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), 1, - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)) + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)) ) ); g.setColor(Color.BLACK); - } else if(TerrainGen.climateCategory[x][y] == 6){ + } else if(parent.climateCategory[x][y] == 6){ g.setColor( new Color( - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)), - (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)) + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)), + (int) ((parent.elevation[x][y]) / 100.0 * 254 * (parent.brightness / 100.0)) ) ); } else { - g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1)); + g.setColor(new Color((int) (parent.elevation[x][y] / 100.0 * 254 * (parent.brightness / 100.0)), 1, 1)); } g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2); } } - } else if(TerrainGen.display_toggle == 4){ - for (int x = 0; x < TerrainGen.DIMENSION; x++) { - for (int y = 0; y < TerrainGen.DIMENSION; y++) { - if (TerrainGen.continentIdField[x][y] > 8) { + } else if(parent.displayToggle == 4){ + for (int x = 0; x < width; x++) { + for (int y = 0; y < width; y++) { + if (parent.continentIdField[x][y] > 8) { g.setColor(Color.PINK); - } else if (TerrainGen.continentIdField[x][y] > 7) { + } else if (parent.continentIdField[x][y] > 7) { g.setColor(Color.DARK_GRAY); - } else if (TerrainGen.continentIdField[x][y] > 6) { + } else if (parent.continentIdField[x][y] > 6) { g.setColor(Color.CYAN); - } else if (TerrainGen.continentIdField[x][y] > 5) { + } else if (parent.continentIdField[x][y] > 5) { g.setColor(Color.GRAY); - } else if (TerrainGen.continentIdField[x][y] > 4) { + } else if (parent.continentIdField[x][y] > 4) { g.setColor(Color.orange); - } else if (TerrainGen.continentIdField[x][y] > 3) { + } else if (parent.continentIdField[x][y] > 3) { g.setColor(Color.green); - } else if (TerrainGen.continentIdField[x][y] > 2) { + } else if (parent.continentIdField[x][y] > 2) { g.setColor(Color.yellow); - } else if (TerrainGen.continentIdField[x][y] > 1) { + } else if (parent.continentIdField[x][y] > 1) { g.setColor(Color.blue); - } else if (TerrainGen.continentIdField[x][y] > 0) { + } else if (parent.continentIdField[x][y] > 0) { g.setColor(Color.red); } else { g.setColor(Color.BLACK); @@ -162,30 +170,30 @@ class InterpolationDisplay extends JPanel{ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2); } } - } else if (TerrainGen.display_toggle == 5) { - Continent current = TerrainGen.continents.get(TerrainGen.current_Continent); + } else if (parent.displayToggle == 5) { + Continent current = parent.continents.get(parent.current_Continent); g.drawString("dim_x: " + current.dim_x, 20, 20); g.drawString("dim_y: " + current.dim_y, 20, 30); for (int x = 0; x < current.dim_x; x++) { for (int y = 0; y < current.dim_y; y++) { if (current.elevation[x][y] > 10) { - g.setColor(new Color(1, (int) (current.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1)); + g.setColor(new Color(1, (int) (current.elevation[x][y] / 100.0 * 254 * (parent.brightness / 100.0)), 1)); g.fillRect(50 + x * 2, 50 + y * 2, 2, 2); } } } - } else if (TerrainGen.display_toggle == 6){ - Continent current = TerrainGen.continents.get(TerrainGen.current_Continent); - for(int x = 0; x < Region.REGION_DIMENSION; x++){ - for(int y = 0; y < Region.REGION_DIMENSION; y++){ - if(current.regions[TerrainGen.current_Region_X][TerrainGen.current_Region_Y].chart_Drainage[x][y] > 0){ - g.setColor(Color.BLUE); - } else { - g.setColor(Color.BLACK); - } - g.fillRect(50 + x * 2, 50 + y * 2, 2, 2); - } - } + } else if (parent.displayToggle == 6){ + // Continent current = parent.continents.get(parent.current_Continent); + // for(int x = 0; x < Region.REGION_DIMENSION; x++){ + // for(int y = 0; y < Region.REGION_DIMENSION; y++){ + // if(current.regions[parent.current_Region_X][parent.current_Region_Y].chart_Drainage[x][y] > 0){ + // g.setColor(Color.BLUE); + // } else { + // g.setColor(Color.BLACK); + // } + // g.fillRect(50 + x * 2, 50 + y * 2, 2, 2); + // } + // } } // if(TerrainInterpolator.display_toggle == 0) { // g.drawString("Elevation Raws", 10, 10); diff --git a/src/main/java/electrosphere/game/server/terrain/generation/Region.java b/src/main/java/electrosphere/game/server/terrain/generation/Region.java index 052a9f6e..e2d5f857 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/Region.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/Region.java @@ -5,6 +5,7 @@ package electrosphere.game.server.terrain.generation; * @author satellite */ class Region { + public static int REGION_DIMENSION = 100; int chart_Elevation[][]; int chart_Drainage[][]; @@ -12,8 +13,10 @@ class Region { int elevation_Goal; Region neighbors[][]; public boolean finished_Drainage_Simulation = false; - public Region(){ + + protected Region(){ neighbors = new Region[3][3]; neighbors[1][1] = null; } + } diff --git a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java index 584c19b1..f4c76fa3 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Random; import javax.swing.JFrame; @@ -19,37 +20,41 @@ import electrosphere.game.server.terrain.models.TerrainModel; * @author satellite */ public class TerrainGen { - public static int elevation[][]; - public static int DIMENSION = 100; + int elevation[][]; + int continentPhaseDimension = 128; //the interpolation ratio applied to the statically generated terrain - static int interpolationRatio = 10; + int interpolationRatio = 10; + //the interpolated phase dimension + int interpolationPhaseDimension = continentPhaseDimension * interpolationRatio; //vertical static interpolation ratio - static int verticalInterpolationRatio = 10; + int verticalInterpolationRatio = 10; //the interpolation ratio applied to the dynamically generated terrain per chunk - static int dynamicInterpRatio = 1000; - static JFrame frame; - static InterpolationDisplay graphics; - public static int brightness = 0; - static int brightness_hold_incrementer = 0; - static boolean brightness_increasing = true; - public static int display_toggle = 0; - static final int max_Display_Toggle = 6; + int dynamicInterpRatio = 1000; + JFrame frame; + InterpolationDisplay graphics; + int brightness = 0; + int brightnessHoldIncrementer = 0; + boolean brightnessIncreasing = true; + int displayToggle = 0; + int max_Display_Toggle = 6; + + static final int MAX_HEIGHT = 100; - public static int[][] mountainParsed; + int[][] mountainParsed; static final int MOUNTAIN_THRESHOLD = 75; static final int MOUNTAIN_RANGE_SIZE_MINIMUM = 10; - public static int[][] oceanParsed; + int[][] oceanParsed; static final int OCEAN_THRESHOLD = 25; - static Vector wind_field[][]; + Vector wind_field[][]; - public static int[][] precipitationChart; + int[][] precipitationChart; static final int RAIN_SHADOW_BLOCKER_HEIGHT = 80; - public static int[][] temperatureChart; + int[][] temperatureChart; - public static long[][] chunkRandomizer; + long[][] chunkRandomizer; /* 0 - ocean @@ -60,16 +65,18 @@ public class TerrainGen { 5 - polar 6 - mountainous */ - public static int[][] climateCategory; + public int[][] climateCategory; - public static int numberContinents = 0; - public static int[][] continentIdField; + public int numberContinents = 0; + public int[][] continentIdField; - public static List continents = new ArrayList(); + public List continents = new ArrayList(); - public static int current_Continent = 1; - public static int current_Region_X = 0; - public static int current_Region_Y = 0; + public int current_Continent = 1; + public int current_Region_X = 0; + public int current_Region_Y = 0; + + Random rand = new Random(); // public static void main(String args[]){ @@ -148,70 +155,109 @@ public class TerrainGen { // } // } + /** + * Generates a new TerrainModel + * @return The TerrainModel + */ public TerrainModel generateModel(){ TerrainModel rVal; - TerrainGenerator tergen = new TerrainGenerator(); - tergen.set_Dimension(DIMENSION); - tergen.set_Lifespan(15000); + //generate continent-phase terrain + TerrainGenerator tergen = new TerrainGenerator(1); + tergen.setDimension(continentPhaseDimension); + tergen.setLifespan(15000); tergen.run(); - elevation = tergen.get_Terrain(); + elevation = tergen.getTerrain(); + //interpolate terrain to smooth what has been received from TerrainGenerator + elevation = interpolateElevationRaws(elevation); - elevation = interpolate_Elevation_Raws(elevation); - DIMENSION = DIMENSION * 2; - - elevation = compression_filter(elevation); - elevation = three_halves_filter(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = small_Kernel_Sharpen(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = three_halves_filter(elevation); - elevation = small_Kernel_Smooth(elevation); - elevation = small_Kernel_Sharpen(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); + //While the TerrainGenerator does a great job of outlining a rough sketch of how the terrain should look, + //a lot of filters are applied to give the terrain a much cleaner and realistic look. This is arguably + //where the real magic of the terrain generation happens - mountainParsed = new int[DIMENSION][DIMENSION]; - oceanParsed = new int[DIMENSION][DIMENSION]; - continentIdField = new int[DIMENSION][DIMENSION]; + //flatten the terrain and raise it above sealevel + elevation = compressionFilter(elevation); + elevation = threeHalvesFilter(elevation); + + //knead the terrain + elevation = smoothTerrainFurther(elevation); + elevation = smallKernelSharpen(elevation); + elevation = smoothTerrainFurther(elevation); + + //raise terrain + elevation = threeHalvesFilter(elevation); + + //knead terrain mode + elevation = smallKernelSmooth(elevation); + elevation = smallKernelSharpen(elevation); + elevation = smoothTerrainFurther(elevation); + elevation = smoothTerrainFurther(elevation); + + //Make the land part of the heightmap scale exponentially instead of linearly + //Basically makes the terrain sharper + elevation = landExponentialFilter(elevation); + elevation = landExponentialFilter(elevation); + elevation = landExponentialFilter(elevation); + elevation = landExponentialFilter(elevation); + elevation = landExponentialFilter(elevation); + elevation = landExponentialFilter(elevation); + + mountainParsed = new int[continentPhaseDimension][continentPhaseDimension]; + oceanParsed = new int[continentPhaseDimension][continentPhaseDimension]; + continentIdField = new int[continentPhaseDimension][continentPhaseDimension]; - mountainParsed = parse_Mountainscapes(elevation); + //generate designation arrays for features about the terrain + mountainParsed = parseMountainscapes(elevation); + oceanParsed = parseOceans(elevation); + wind_field = mapWindField(); + precipitationChart = calculateRainShadows(elevation,oceanParsed,wind_field); + temperatureChart = generateTemperatureChart(); + climateCategory = inferClimateCategory(); + determineContinents(); - oceanParsed = parse_Oceans(elevation); - - wind_field = map_Wind_Field(); - - precipitationChart = calculate_Rain_Shadows(elevation,oceanParsed,wind_field); - - temperatureChart = generate_Temperature_Chart(); - - climateCategory = infer_Climate_Category(); - - determine_Continents(); - - fill_Continents(); + //generate continent objects + fillContinents(); float[][] modelInput = interpolateIntegerElevations(elevation); modelInput = applyRandomizationFilter(modelInput); - chunkRandomizer = getChunkRandomizer(modelInput, DIMENSION); + chunkRandomizer = getChunkRandomizer(modelInput, interpolationPhaseDimension); rVal = new TerrainModel( - DIMENSION, + interpolationPhaseDimension, modelInput, chunkRandomizer, OCEAN_THRESHOLD * verticalInterpolationRatio, MOUNTAIN_THRESHOLD * verticalInterpolationRatio, dynamicInterpRatio ); + + //create internal renderer + createRenderer(); + + boolean test = true; + while(test){ + if(brightnessIncreasing){ + if(brightness < 100){ + brightness++; + } else { + } + } else { + if(brightness > 0){ + brightness--; + } else { + brightnessIncreasing = true; + displayToggle++; + if(displayToggle > 1){ + displayToggle = 0; + } + } + } + frame.repaint(); + Utilities.sleep(10); + } return rVal; } @@ -251,21 +297,21 @@ public class TerrainGen { return rVal; } - static float[][] applyRandomizationFilter(float[][] elevation){ + float[][] applyRandomizationFilter(float[][] elevation){ float[][] rVal = new float[elevation.length][elevation[0].length]; - for(int x = 0; x < DIMENSION-1; x++){ - for(int y = 0; y < DIMENSION-1; y++){ - rVal[x][y] = elevation[x][y] + Utilities.random_Integer(0, (int)(elevation[x][y] / verticalInterpolationRatio)); + for(int x = 0; x < continentPhaseDimension-1; x++){ + for(int y = 0; y < continentPhaseDimension-1; y++){ + rVal[x][y] = elevation[x][y] + Utilities.random_Integer(0, (int)(elevation[x][y] / verticalInterpolationRatio), rand); } } return rVal; } - static float[][] interpolateIntegerElevations(int[][] elevation){ + float[][] interpolateIntegerElevations(int[][] elevation){ int interpRatio = interpolationRatio; - float[][] rVal = new float[DIMENSION * interpRatio][DIMENSION * interpRatio]; - for(int x = 0; x < DIMENSION-1; x++){ - for(int y = 0; y < DIMENSION-1; y++){ + float[][] rVal = new float[continentPhaseDimension * interpRatio][continentPhaseDimension * interpRatio]; + for(int x = 0; x < continentPhaseDimension-1; x++){ + for(int y = 0; y < continentPhaseDimension-1; y++){ for(int i = 0; i < interpRatio; i++){ for(int j = 0; j < interpRatio; j++){ float ratio1 = (i*j) * 1.0f / (interpRatio*interpRatio); @@ -283,11 +329,11 @@ public class TerrainGen { } } } - DIMENSION = DIMENSION * interpRatio; + interpolationPhaseDimension = continentPhaseDimension * interpRatio; return rVal; } - public static void anchor_To_Real_Region(){ + public void anchor_To_Real_Region(){ //current_Region_X //continents //current_Continent @@ -306,7 +352,7 @@ public class TerrainGen { } } - static int[][] simulate_Drainage(int[][] water_level, int[][] elevation, int dim_x, int dim_y){ + int[][] simulate_Drainage(int[][] water_level, int[][] elevation, int dim_x, int dim_y){ int[][] rVal = new int[dim_x][dim_y]; for(int x = 0; x < dim_x; x++){ for(int y = 0; y < dim_y; y++){ @@ -345,7 +391,7 @@ public class TerrainGen { for(int i = 0; i < num_Water_Particles; i++){ done = false; rand_Incrementer = 0; - rand_num = Utilities.random_Integer(0, rand_Space); + rand_num = Utilities.random_Integer(0, rand_Space, rand); for(int j = 0; j < offset_kernel_size; j++){ rand_Incrementer = rand_Incrementer + attractor_Values[j]; if(rand_num < rand_Incrementer){ @@ -366,7 +412,7 @@ public class TerrainGen { return rVal; } - static int sumIntegerArray(int[][] arr, int dim_x, int dim_y){ + int sumIntegerArray(int[][] arr, int dim_x, int dim_y){ int sum = 0; for(int x = 0; x < dim_x; x++){ for(int y = 0; y < dim_y; y++){ @@ -376,11 +422,15 @@ public class TerrainGen { return sum; } - static void generate_Region_Elevation_Maps(Continent c){ - int neighbor_offset_x[] = { + /** + * Generates an elevation map of a given continent + * @param c The continent to generate off of + */ + void generateRegionElevationMaps(Continent c){ + int neighborOffsetX[] = { 1,0,-1,1,-1,1,0,-1 }; - int neighbor_offset_y[] = { + int neighborOffsetY[] = { 1,1,1,0,0,-1,-1,-1 }; //generate neighbor links @@ -388,18 +438,18 @@ public class TerrainGen { for(int y = 0; y < c.dim_y; y++){ if(c.regions[x][y]!=null){ for(int i = 0; i < 8; i++){ - if(x + neighbor_offset_x[i] >= 0 && x + neighbor_offset_x[i] < c.dim_x && y + neighbor_offset_y[i] >= 0 && y + neighbor_offset_y[i] < c.dim_y){ + if(x + neighborOffsetX[i] >= 0 && x + neighborOffsetX[i] < c.dim_x && y + neighborOffsetY[i] >= 0 && y + neighborOffsetY[i] < c.dim_y){ //+1 comes from getting the center of the kernel //ie kernel is 3x3 therefore the center position is at 1,1 array-wise - c.regions[x][y].neighbors[neighbor_offset_x[i]+1][neighbor_offset_y[i]+1] = c.regions[x + neighbor_offset_x[i]][y + neighbor_offset_y[i]]; + c.regions[x][y].neighbors[neighborOffsetX[i]+1][neighborOffsetY[i]+1] = c.regions[x + neighborOffsetX[i]][y + neighborOffsetY[i]]; } else { - c.regions[x][y].neighbors[neighbor_offset_x[i]+1][neighbor_offset_y[i]+1] = null; + c.regions[x][y].neighbors[neighborOffsetX[i]+1][neighborOffsetY[i]+1] = null; } } } } } - int region_Dim = Region.REGION_DIMENSION; + int regionDim = Region.REGION_DIMENSION; //set elevation goals for(int x = 0; x < c.dim_x; x++){ for(int y = 0; y < c.dim_y; y++){ @@ -536,41 +586,41 @@ public class TerrainGen { open_Set.add(region_Current); if(simulate_Drainage){ while(!open_Set.isEmpty()){ - region_Current.chart_Drainage = new int[region_Dim][region_Dim]; - for(int x = 0; x < region_Dim; x++){ - for(int y = 0; y < region_Dim; y++){ + region_Current.chart_Drainage = new int[regionDim][regionDim]; + for(int x = 0; x < regionDim; x++){ + for(int y = 0; y < regionDim; y++){ region_Current.chart_Drainage[x][y] = 1; } } if (region_Current.neighbors[1][0] != null) { if (region_Current.neighbors[1][0].finished_Drainage_Simulation == true) { - for(int x = 0; x < region_Dim; x++){ - region_Current.chart_Drainage[x][0] = 1 + region_Current.neighbors[1][0].chart_Drainage[x][region_Dim-1]; + for(int x = 0; x < regionDim; x++){ + region_Current.chart_Drainage[x][0] = 1 + region_Current.neighbors[1][0].chart_Drainage[x][regionDim-1]; } } } if (region_Current.neighbors[0][1] != null) { if (region_Current.neighbors[0][1].finished_Drainage_Simulation == true) { - for(int x = 0; x < region_Dim; x++){ - region_Current.chart_Drainage[0][x] = 1 + region_Current.neighbors[0][1].chart_Drainage[region_Dim-1][x]; + for(int x = 0; x < regionDim; x++){ + region_Current.chart_Drainage[0][x] = 1 + region_Current.neighbors[0][1].chart_Drainage[regionDim-1][x]; } } } if (region_Current.neighbors[1][2] != null) { if (region_Current.neighbors[1][2].finished_Drainage_Simulation == true) { - for(int x = 0; x < region_Dim; x++){ - region_Current.chart_Drainage[x][region_Dim-1] = 1 + region_Current.neighbors[1][2].chart_Drainage[x][0]; + for(int x = 0; x < regionDim; x++){ + region_Current.chart_Drainage[x][regionDim-1] = 1 + region_Current.neighbors[1][2].chart_Drainage[x][0]; } } } if (region_Current.neighbors[2][1] != null) { if (region_Current.neighbors[2][1].finished_Drainage_Simulation == true) { - for(int x = 0; x < region_Dim; x++){ - region_Current.chart_Drainage[region_Dim-1][x] = 1 + region_Current.neighbors[2][1].chart_Drainage[0][x]; + for(int x = 0; x < regionDim; x++){ + region_Current.chart_Drainage[regionDim-1][x] = 1 + region_Current.neighbors[2][1].chart_Drainage[0][x]; } } } - region_Current.chart_Max_Water_Flow = new int[region_Dim][region_Dim]; + region_Current.chart_Max_Water_Flow = new int[regionDim][regionDim]; // while(sum_Array(region_Current.chart_Drainage,region_Dim,region_Dim)>0){ // region_Current.chart_Drainage = simulate_Drainage(region_Current.chart_Drainage,region_Current.chart_Elevation,Region.REGION_DIMENSION,Region.REGION_DIMENSION); // for(int x = 0; x < region_Dim; x++){ @@ -612,11 +662,15 @@ public class TerrainGen { } } - static void create_Frame(){ + /** + * Creates the internal renderer for displaying data + */ + void createRenderer(){ frame = new JFrame(); - graphics = new InterpolationDisplay(); - frame.setBounds(25, 25, 300 + DIMENSION, 300 + DIMENSION); + graphics = new InterpolationDisplay(this); + frame.setBounds(25, 25, 300 + continentPhaseDimension, 300 + continentPhaseDimension); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH); frame.add(graphics); frame.setVisible(true); frame.addKeyListener(new KeyListener(){ @@ -628,7 +682,7 @@ public class TerrainGen { if(ke.getKeyCode() == KeyEvent.VK_C){ increment_Current_Continent(); } else if(ke.getKeyCode() == KeyEvent.VK_V){ - increment_Display_Toggle(); + incrementDisplayToggle(); } } @@ -639,52 +693,56 @@ public class TerrainGen { ); } - static void fill_Continents(){ + /** + * Generates continent objects from the raw designation arrays + */ + void fillContinents(){ for(int i = 1; i < numberContinents + 1; i++){ Continent current = new Continent(); continents.add(current); //find dimensions - int min_x = -1; - int min_y = -1; - int max_x = -1; - int max_y = -1; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + int minX = -1; + int minY = -1; + int maxX = -1; + int maxY = -1; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(continentIdField[x][y] == i){ - if(min_x == -1){ - min_x = x; - min_y = y; - max_x = x; - max_y = y; + if(minX == -1){ + minX = x; + minY = y; + maxX = x; + maxY = y; } else { - if (x < min_x) { - min_x = x; + if (x < minX) { + minX = x; } - if (x > max_x) { - max_x = x; + if (x > maxX) { + maxX = x; } - if (y < min_y) { - min_y = y; + if (y < minY) { + minY = y; } - if (y > max_y) { - max_y = y; + if (y > maxY) { + maxY = y; } } } } } - int dim_x = max_x - min_x + 1; - int dim_y = max_y - min_y + 1; - current.dim_x = dim_x; - current.dim_y = dim_y; - current.chart_Climate = new int[dim_x][dim_y]; - current.chart_Precipitation = new int[dim_x][dim_y]; - current.chart_Temperature = new int[dim_x][dim_y]; - current.chart_Wind_Macro = new int[dim_x][dim_y]; - current.elevation = new int[dim_x][dim_y]; + //The dimensions of the continent + int dimX = maxX - minX + 1; + int dimY = maxY - minY + 1; + current.dim_x = dimX; + current.dim_y = dimY; + current.chart_Climate = new int[dimX][dimY]; + current.chart_Precipitation = new int[dimX][dimY]; + current.chart_Temperature = new int[dimX][dimY]; + current.chart_Wind_Macro = new int[dimX][dimY]; + current.elevation = new int[dimX][dimY]; //zero out arrays - for(int x = 0; x < dim_x; x++){ - for(int y = 0; y < dim_y; y++){ + for(int x = 0; x < dimX; x++){ + for(int y = 0; y < dimY; y++){ current.elevation[x][y] = 0; current.chart_Climate[x][y] = 0; current.chart_Precipitation[x][y] = 0; @@ -693,23 +751,23 @@ public class TerrainGen { } } //fill continent level arrays - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(continentIdField[x][y] == i){ current.size++; - current.elevation[x-min_x][y-min_y] = elevation[x][y]; - current.chart_Climate[x-min_x][y-min_y] = climateCategory[x][y]; - current.chart_Precipitation[x-min_x][y-min_y] = precipitationChart[x][y]; - current.chart_Temperature[x-min_x][y-min_y] = temperatureChart[x][y]; - current.chart_Wind_Macro[x-min_x][y-min_y] = wind_field[x][y].x; + current.elevation[x-minX][y-minY] = elevation[x][y]; + current.chart_Climate[x-minX][y-minY] = climateCategory[x][y]; + current.chart_Precipitation[x-minX][y-minY] = precipitationChart[x][y]; + current.chart_Temperature[x-minX][y-minY] = temperatureChart[x][y]; + current.chart_Wind_Macro[x-minX][y-minY] = wind_field[x][y].x; } } } //create regions - current.regions = new Region[dim_x][dim_y]; - for(int x = 0; x < dim_x; x++){ - for(int y = 0; y < dim_y; y++){ - if(continentIdField[x+min_x][y+min_y] == i){ + current.regions = new Region[dimX][dimY]; + for(int x = 0; x < dimX; x++){ + for(int y = 0; y < dimY; y++){ + if(continentIdField[x+minX][y+minY] == i){ current.regions[x][y] = new Region(); current.regions[x][y].elevation_Goal = current.elevation[x][y]; } else { @@ -717,20 +775,26 @@ public class TerrainGen { } } } - generate_Region_Elevation_Maps(current); + generateRegionElevationMaps(current); } } - static void floodfill_Continent_Number(int x, int y, int number){ + /** + * Recursive function to floodfill designations of a continent + * @param x The x position to check + * @param y The y position to check + * @param number The continent id of the continent currently being floodfilled + */ + void floodfillContinentNumber(int x, int y, int number){ continentIdField[x][y] = number; int offset_X[] = {0,-1,0,1}; int offset_Y[] = {1,0,-1,0}; for(int i = 0; i < 4; i++){ - if(x + offset_X[i] >= 0 && x + offset_Y[i] < DIMENSION){ - if(y + offset_Y[i] >= 0 && y + offset_Y[i] < DIMENSION){ + if(x + offset_X[i] >= 0 && x + offset_Y[i] < continentPhaseDimension){ + if(y + offset_Y[i] >= 0 && y + offset_Y[i] < continentPhaseDimension){ if(oceanParsed[x + offset_X[i]][y + offset_Y[i]] < 25){ if(continentIdField[x + offset_X[i]][y + offset_Y[i]] == 0){ - floodfill_Continent_Number(x + offset_X[i], y + offset_Y[i], number); + floodfillContinentNumber(x + offset_X[i], y + offset_Y[i], number); } } } @@ -738,32 +802,39 @@ public class TerrainGen { } } - static void determine_Continents(){ - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Uses flood fill to determine continents + */ + void determineContinents(){ + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(oceanParsed[x][y] < 25){ if(continentIdField[x][y] == 0){ numberContinents++; - floodfill_Continent_Number(x,y,numberContinents); + floodfillContinentNumber(x,y,numberContinents); } } } } } - /* - 0 - ocean - 1 - tropical - 2 - subtropical - 3 - temperate - 4 - dry - 5 - polar - 6 - mountainous + /** + * Generates a map tagging each position into a climate classification + * + * 0 - ocean + * 1 - tropical + * 2 - subtropical + * 3 - temperate + * 4 - dry + * 5 - polar + * 6 - mountainous + * + * @return The classification map */ - static int[][] infer_Climate_Category(){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++) { + int[][] inferClimateCategory(){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++) { if (elevation[x][y] > OCEAN_THRESHOLD) { if (elevation[x][y] > MOUNTAIN_THRESHOLD) { rVal[x][y] = 6; @@ -806,54 +877,65 @@ public class TerrainGen { return rVal; } - static int[][] generate_Temperature_Chart(){ - int rVal[][] = new int[DIMENSION][DIMENSION]; + /** + * Generates a map representing average temperature + * @return The map + */ + int[][] generateTemperatureChart(){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; int temp = 0; - for(int x = 0; x < DIMENSION; x++){ - temp = (int)(100 - (Math.abs(x - DIMENSION/2.0) / (DIMENSION/2.0) * 100.0)); + for(int x = 0; x < continentPhaseDimension; x++){ + temp = (int)(100 - (Math.abs(x - continentPhaseDimension/2.0) / (continentPhaseDimension/2.0) * 100.0)); temp = (int)(Math.sin(temp/100.0 * Math.PI / 2.0) * 100.0); - for(int y = 0; y < DIMENSION; y++){ + for(int y = 0; y < continentPhaseDimension; y++){ rVal[y][x] = temp; } } return rVal; } - static int[][] calculate_Rain_Shadows(int[][] elevation_raws, int[][] ocean_parsed, Vector[][] wind_field){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - int rain_Particles[][] = new int[DIMENSION][DIMENSION]; - int num_rain_particles = 0; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Calculates rain shadowing across the heightmap + * @param elevation_raws The elevation data + * @param ocean_parsed The ocean marking map + * @param wind_field The field of average wind flow map + * @return The map marking rain shadows + */ + int[][] calculateRainShadows(int[][] elevation_raws, int[][] ocean_parsed, Vector[][] wind_field){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + int rainParticles[][] = new int[continentPhaseDimension][continentPhaseDimension]; + int numRainParticles = 0; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(ocean_parsed[x][y] > 1){ - rain_Particles[x][y] = 1; + rainParticles[x][y] = 1; rVal[x][y] = 1; - num_rain_particles++; + numRainParticles++; } } } - while(num_rain_particles > DIMENSION * 2) { - for (int x = 0; x < DIMENSION; x++) { - for (int y = 0; y < DIMENSION; y++) { - if (rain_Particles[x][y] >= 1) { + while(numRainParticles > continentPhaseDimension * 2) { + for (int x = 0; x < continentPhaseDimension; x++) { + for (int y = 0; y < continentPhaseDimension; y++) { + if (rainParticles[x][y] >= 1) { if (wind_field[x][y].x == -1) { if (x > 0) { if (elevation_raws[x - 1][y] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x - 1][y] = 1; + rainParticles[x - 1][y] = 1; rVal[x - 1][y] = 1; } else { } if (wind_field[x][y].y == -1) { if (y > 0) { if (elevation_raws[x - 1][y - 1] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x - 1][y - 1] = 1; + rainParticles[x - 1][y - 1] = 1; rVal[x - 1][y - 1] = 1; } } } else if (wind_field[x][y].y == 1) { - if (y < DIMENSION - 1) { + if (y < continentPhaseDimension - 1) { if (elevation_raws[x - 1][y + 1] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x - 1][y + 1] = 1; + rainParticles[x - 1][y + 1] = 1; rVal[x - 1][y + 1] = 1; } } @@ -861,23 +943,23 @@ public class TerrainGen { } else { } } else { - if (x < DIMENSION - 1) { + if (x < continentPhaseDimension - 1) { if (elevation_raws[x + 1][y] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x + 1][y] = 1; + rainParticles[x + 1][y] = 1; rVal[x + 1][y] = 1; } else { } if (wind_field[x][y].y == -1) { if (y > 0) { if (elevation_raws[x + 1][y - 1] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x + 1][y - 1] = 1; + rainParticles[x + 1][y - 1] = 1; rVal[x + 1][y - 1] = 1; } } } else if (wind_field[x][y].y == 1) { - if (y < DIMENSION - 1) { + if (y < continentPhaseDimension - 1) { if (elevation_raws[x + 1][y + 1] < RAIN_SHADOW_BLOCKER_HEIGHT) { - rain_Particles[x + 1][y + 1] = 1; + rainParticles[x + 1][y + 1] = 1; rVal[x + 1][y + 1] = 1; } } @@ -885,15 +967,15 @@ public class TerrainGen { } else { } } - rain_Particles[x][y] = 0; + rainParticles[x][y] = 0; } } } - num_rain_particles = 0; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ - if(rain_Particles[x][y] == 1){ - num_rain_particles++; + numRainParticles = 0; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ + if(rainParticles[x][y] == 1){ + numRainParticles++; } } } @@ -901,11 +983,16 @@ public class TerrainGen { return rVal; } - static Vector[][] map_Wind_Field(){ - Vector rVal[][] = new Vector[DIMENSION][DIMENSION]; - int sixth = (int)(DIMENSION / 6.0); - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Calculates a vector field representing average wind flow across the heightmap + * @return The vector field representing average wind flow + */ + Vector[][] mapWindField(){ + Vector rVal[][] = new Vector[continentPhaseDimension][continentPhaseDimension]; + //One sixth of the dimension of the heightmap + int sixth = (int)(continentPhaseDimension / 6.0); + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(x < sixth){ rVal[x][y] = new Vector(); rVal[x][y].x = -1; @@ -936,10 +1023,15 @@ public class TerrainGen { return rVal; } - static int[][] parse_Oceans(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Fills out an array that marks positions in the heightmap as oceans or not oceans + * @param data The heightmap + * @return A new array that contains the designations + */ + int[][] parseOceans(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(data[x][y] < OCEAN_THRESHOLD){ rVal[x][y] = OCEAN_THRESHOLD; } else { @@ -950,10 +1042,15 @@ public class TerrainGen { return rVal; } - static int[][] parse_Mountainscapes(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Fills out an array that marks positions in the heightmap as mountains or not mountains + * @param data The heightmap + * @return A new array that contains the designations + */ + int[][] parseMountainscapes(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(data[x][y] > MOUNTAIN_THRESHOLD){ rVal[x][y] = MOUNTAIN_THRESHOLD; } else { @@ -964,9 +1061,9 @@ public class TerrainGen { return rVal; } - static int[][] closed_Set; + int[][] closed_Set; - static int floodfill_Reach_Threshold(int[][] data, int[][] closed_Set, int x, int y, int min_val, int max_val){ + int floodfill_Reach_Threshold(int[][] data, int[][] closed_Set, int x, int y, int min_val, int max_val){ int rVal = 0; int num_hits; int offset_X[] = {-1,-1,-1,0,0,0,1,1,1}; @@ -975,9 +1072,9 @@ public class TerrainGen { closed_Set[x][y] = 1; for(int i = 0; i < 9; i++){ if(x + offset_X[i] >= 0 && - x + offset_X[i] < DIMENSION && + x + offset_X[i] < continentPhaseDimension && y + offset_Y[i] >= 0 && - y + offset_Y[i] < DIMENSION){ + y + offset_Y[i] < continentPhaseDimension){ if(closed_Set[x + offset_X[i]][y+offset_Y[i]] == 0){ rVal = rVal + floodfill_Reach_Threshold(data,closed_Set,x + offset_X[i],y + offset_Y[i], min_val, max_val); } @@ -987,8 +1084,8 @@ public class TerrainGen { return rVal; } - static int[][] remove_Small_Mountain_Ranged(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; + int[][] remove_Small_Mountain_Ranged(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; boolean removed_Something = false; // for (int x = 0; x < DIMENSION; x++) { // for (int y = 0; y < DIMENSION; y++) { @@ -996,8 +1093,8 @@ public class TerrainGen { // } // } // while (true) { - for (int x = 0; x < DIMENSION; x++) { - for (int y = 0; y < DIMENSION; y++) { + for (int x = 0; x < continentPhaseDimension; x++) { + for (int y = 0; y < continentPhaseDimension; y++) { rVal[x][y] = data[x][y]; if (data[x][y] > MOUNTAIN_THRESHOLD) { rVal[x][y] = rVal[x][y] - 5; @@ -1018,10 +1115,17 @@ public class TerrainGen { return rVal; } - static int[][] compression_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Compresses the extremes of the map towards the center half. + * IE: + * values less than 25 -> Center 50 <- values greater than 75 + * @param data The heightmap to apply the compression filter to + * @return A new heightmap containing the compressed data + */ + int[][] compressionFilter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(data[x][y] < 25){ rVal[x][y] = (int)(data[x][y] * 3.0 / 2.0); } else if(data[x][y] > 75){ @@ -1034,10 +1138,15 @@ public class TerrainGen { return rVal; } - static int[][] three_halves_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Applies a filter that pushes the terrain upwards by making all values "Three halves" of their original values. + * @param data The heightmap to apply the filter to + * @return A new array containing the data with filter applied + */ + int[][] threeHalvesFilter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ rVal[x][y] = (int)(data[x][y] * 3.0 / 2.0); if(rVal[x][y] > 100){ rVal[x][y] = 100; @@ -1047,10 +1156,10 @@ public class TerrainGen { return rVal; } - static int[][] two_third_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + int[][] two_third_filter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ rVal[x][y] = (int)(data[x][y] * 2.0 / 3.0); if(rVal[x][y] < 0){ rVal[x][y] = 0; @@ -1060,10 +1169,10 @@ public class TerrainGen { return rVal; } - static int[][] high_end_two_third_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++) { + int[][] high_end_two_third_filter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++) { if (data[x][y] > 50) { rVal[x][y] = (int) (data[x][y] * 2.0 / 3.0); if (rVal[x][y] < 0) { @@ -1077,10 +1186,10 @@ public class TerrainGen { return rVal; } - static int[][] reduce_mid_high_end_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++) { + int[][] reduce_mid_high_end_filter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++) { if (data[x][y] > 50 && data[x][y] < 75) { rVal[x][y] = (int) (data[x][y] * 2.0 / 3.0); if (rVal[x][y] < 0) { @@ -1094,28 +1203,33 @@ public class TerrainGen { return rVal; } - static int[][] small_Kernel_Smooth(int elevation_Map[][]){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - int kernel_offset_x[] = { + /** + * Applies a small radius vertical, horizontal, and radial smoothing kernel to the data + * @param elevationMap The heightmap to apply the filter to + * @return A new array containing the data with filter applied + */ + int[][] smallKernelSmooth(int elevationMap[][]){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + int kernelOffsetX[] = { -1,0,1, -1,0,1, -1,0,1 }; - int kernel_offset_y[] = { + int kernelOffsetY[] = { -1,-1,-1, 0,0,0, 1,1,1 }; - int kernle_modifier[] = { + int kernelModifier[] = { 1,2,1, 2,4,2, 1,2,1 }; - for(int x = 1; x < DIMENSION - 1; x++){ - for(int y = 1; y < DIMENSION - 1; y++){ + for(int x = 1; x < continentPhaseDimension - 1; x++){ + for(int y = 1; y < continentPhaseDimension - 1; y++){ int sum = 0; for(int i = 0; i < 9; i++){ - sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernle_modifier[i]; + sum = sum + elevationMap[x+kernelOffsetX[i]][y+kernelOffsetY[i]] * kernelModifier[i]; } sum = (int)(sum/13.0); if(sum > 100){ @@ -1127,28 +1241,33 @@ public class TerrainGen { return rVal; } - static int[][] small_Kernel_Sharpen(int elevation_Map[][]){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - int kernel_offset_x[] = { + /** + * Applies a small horizontal, vertical, and radial sharpen filter to the data + * @param elevationMap The heightmap to apply the filter to + * @return A new array containing the data with filter applied + */ + int[][] smallKernelSharpen(int elevationMap[][]){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + int kernelOffsetX[] = { -1,0,1, -1,0,1, -1,0,1 }; - int kernel_offset_y[] = { + int kernelOffsetY[] = { -1,-1,-1, 0,0,0, 1,1,1 }; - int kernel_modifier[] = { + int kernelModifier[] = { 0,-1,0, -1,5,-1, 0,-1,0 }; - for(int x = 1; x < DIMENSION - 1; x++){ - for(int y = 1; y < DIMENSION - 1; y++){ + for(int x = 1; x < continentPhaseDimension - 1; x++){ + for(int y = 1; y < continentPhaseDimension - 1; y++){ int sum = 0; for(int i = 0; i < 9; i++){ - sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernel_modifier[i]; + sum = sum + elevationMap[x+kernelOffsetX[i]][y+kernelOffsetY[i]] * kernelModifier[i]; } // sum = (int)(sum/13.0); if(sum > 100){ @@ -1163,31 +1282,37 @@ public class TerrainGen { return rVal; } - static int[][] smooth_Terrain_Further(int elevation_Map[][]){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - int kernel_offset_x[] = {-2,-1,0,1,2, + + /** + * Applies a vertical, horizontal, and radial smoothing kernel to the heightmap data. + * @param elevationMap The heightmap to apply the filter to + * @return A new array containing the data with filter applied + */ + int[][] smoothTerrainFurther(int elevationMap[][]){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + int kernelOffsetX[] = {-2,-1,0,1,2, -2,-1,0,1,2, -2,-1,0,1,2, -2,-1,0,1,2, -2,-1,0,1,2, }; - int kernel_offset_y[] = {-2,-2,-2,-2,-2, + int kernelOffsetY[] = {-2,-2,-2,-2,-2, -1,-1,-1,-1,-1, 0,0,0,0,0, 1,1,1,1,1, 2,2,2,2,2}; - int kernel_modifier[] = { + int kernelModifier[] = { 1,4,6,4,1, 4,16,24,16,4, 6,24,36,24,6, 4,16,24,16,4, 1,4,6,4,1 }; - for(int x = 2; x < DIMENSION - 2; x++){ - for(int y = 2; y < DIMENSION - 2; y++){ + for(int x = 2; x < continentPhaseDimension - 2; x++){ + for(int y = 2; y < continentPhaseDimension - 2; y++){ int sum = 0; for(int i = 0; i < 25; i++){ - sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernel_modifier[i]; + sum = sum + elevationMap[x+kernelOffsetX[i]][y+kernelOffsetY[i]] * kernelModifier[i]; } sum = (int)(sum/256.0); if(sum > 100){ @@ -1199,20 +1324,43 @@ public class TerrainGen { return rVal; } - static int[][] land_exponential_filter(int[][] data){ - int rVal[][] = new int[DIMENSION][DIMENSION]; - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ + /** + * Applies a filter that makes the land height scale exponentially + * IE Terrain that looks like: + * ^ + * / \ + * / \ + * Becomes + * ^ + * | | + * __ __ + * @param data The data to apply the filter to + * @return A new array containing the data with the filter applied + */ + int[][] landExponentialFilter(int[][] data){ + int rVal[][] = new int[continentPhaseDimension][continentPhaseDimension]; + for(int x = 0; x < continentPhaseDimension; x++){ + for(int y = 0; y < continentPhaseDimension; y++){ if(data[x][y] > TerrainGen.OCEAN_THRESHOLD && data[x][y] < 90){ - -// System.out.print((data[x][y] - ocean_Threshold) + "/" + (100.0 - ocean_Threshold) + "=" + ((data[x][y] - ocean_Threshold) / (100.0 - ocean_Threshold)) + " "); -// System.out.print(data[x][y] + "->"); - rVal[x][y] = (int)(data[x][y] * Math.exp(-(1.0 - ((data[x][y] - OCEAN_THRESHOLD) / (100.0 - OCEAN_THRESHOLD)))) * 0.2f + data[x][y] * 0.8f); + //This is the total height that can be above land + //eg if ocean level is 25, and the maximum possible height is 100, the maximum height relative to sea level would be 75 + int maxHeightAboveLand = MAX_HEIGHT - OCEAN_THRESHOLD; + //This is the current height above sea level + int currentHeightAboveLand = data[x][y] - OCEAN_THRESHOLD; + //This is the percentage of the total height above sea level that the current height is + //In other words if max is 75 and current is 25, it would be 33% of the total height that it COULD be, relative to sea level + float percentageAboveLand = (float)currentHeightAboveLand / (float)currentHeightAboveLand; + //The weight for the exponential component of the calculation + float exponentialComponentWeight = 0.2f; + //The weight for the existing data + float existingComponentWeight = 0.8f; + //calculate rVal and make sure stays above sealevel as it's terrain after all + rVal[x][y] = (int)(data[x][y] * Math.exp(-(1.0f - percentageAboveLand)) * exponentialComponentWeight + data[x][y] * existingComponentWeight); if(rVal[x][y] < TerrainGen.OCEAN_THRESHOLD){ rVal[x][y] = TerrainGen.OCEAN_THRESHOLD + 1; } -// System.out.println(rVal[x][y]); - if(Math.exp(-(1.0 - ((data[x][y] - OCEAN_THRESHOLD) / (100.0 - OCEAN_THRESHOLD)))) > 1.0){ + //Because of how exponentials work, this check should never pass + if(Math.exp(-(1.0 - percentageAboveLand)) > 1.0){ System.out.println("WARNING!!"); } } else { @@ -1233,130 +1381,34 @@ public class TerrainGen { return rVal; } - static int[][] interpolate_Elevation_Raws(int[][] raw){ - int rVal[][] = new int[DIMENSION * 2][DIMENSION * 2]; - for(int x = 0; x < DIMENSION - 1; x++){ - for(int y = 0; y < DIMENSION - 1; y++){ + /** + * Doubles the dimensions of the map so that the new space can be interpolated linearly using existing values + * @param raw The original input map + * @return The new, interpolated output map + */ + int[][] interpolateElevationRaws(int[][] raw){ + int rVal[][] = new int[continentPhaseDimension * 2][continentPhaseDimension * 2]; + //perform interpolation + for(int x = 0; x < continentPhaseDimension - 1; x++){ + for(int y = 0; y < continentPhaseDimension - 1; y++){ rVal[x*2][y*2] = raw[x][y]; rVal[x*2+1][y*2] = (raw[x][y] + raw[x+1][y])/2; rVal[x*2][y*2+1] = (raw[x][y] + raw[x][y+1])/2; rVal[x*2+1][y*2+1] = (raw[x][y] + raw[x+1][y+1])/2; } } + //double dimension to account for new array size + continentPhaseDimension = continentPhaseDimension * 2; return rVal; } - static int[][] get_Pregened_Data(){ - int rVal[][] = {{0, 0, 0, 0, 0, 0, 0, 0, 2, 10, 11, 24, 19, 99, 99, 70, 39, 11, 10, 0, 0, 2, 8, 0, 0, 0, 0, 0, 28, 2, 9, 17, 30, 51, 58, 4, 57, 36, 13, 22, 13, 14, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 1, 12, 1, 15, 4, 57, 39, 6, 15, 23, 22, 5, 17, 3, 0, 10, 0, 10, 0, 0, 1, 3, 1, 9, 5, 12, 6, 13, 6, 38, 33, 78, 30, 36, 55, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 23, 47, 1, 27, 30, 12, 9, 2, 0, 5, 12, 0, 10, 0, 0, 3, 0, 3, 11, 32, 16, 1, 4, 21, 5, 3, 29, 6, 3, 11, 8, 26, 11, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 34, 13, 26, 0, 99, 1, 29, 68, 13, 0, 3, 0, 0, 0, 0, 5, 23, 3, 4, 38, 13, 26, 0, 20, 3, 25, 16, 42, 6, 55, 19, 8, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 36, 21, 0, 48, 7, 40, 22, 25, 1, 16, 2, 0, 13, 5, 0, 0, 2, 6, 27, 20, 12, 19, 32, 30, 27, 29, 14, 1, 31, 46, 12, 50, 32, 21, 13, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 31, 28, 19, 14, 17, 20, 7, 1, 1, 64, 4, 15, 4, 10, 32, 0, 0, 0, 1, 1, 3, 0, 16, 20, 9, 23, 7, 9, 20, 4, 0, 2, 6, 2, 18, 14, 13, 42, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 15, 5, 26, 12, 27, 7, 19, 28, 4, 36, 39, 30, 28, 12, 12, 5, 0, 9, 18, 4, 6, 1, 29, 11, 12, 4, 1, 4, 22, 3, 10, 1, 0, 2, 1, 34, 1, 0, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 2, 13, 16, 3, 19, 27, 0, 25, 69, 38, 21, 33, 44, 3, 1, 7, 11, 0, 6, 2, 20, 23, 6, 3, 8, 21, 15, 27, 5, 0, 5, 1, 45, 1, 19, 16, 40, 0, 0, 14, 11, 12, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 5, 23, 21, 35, 9, 39, 58, 28, 7, 21, 30, 33, 3, 7, 16, 11, 9, 14, 5, 19, 14, 16, 21, 41, 5, 14, 22, 13, 17, 20, 17, 6, 25, 18, 14, 23, 10, 15, 20, 3, 7, 4, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 7, 60, 13, 5, 35, 33, 7, 21, 35, 25, 28, 24, 3, 38, 17, 30, 3, 4, 21, 4, 21, 37, 24, 2, 0, 13, 22, 0, 3, 15, 2, 24, 0, 13, 27, 8, 34, 3, 11, 0, 18, 22, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 9, 0, 3, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 4, 5, 1, 49, 26, 28, 11, 5, 4, 15, 17, 5, 34, 25, 40, 13, 35, 10, 81, 20, 15, 21, 21, 18, 19, 10, 0, 17, 5, 1, 10, 10, 20, 11, 15, 10, 30, 23, 45, 24, 30, 35, 21, 36, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 14, 27, 17, 10, 26, 12, 19, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 1, 0, 46, 12, 17, 0, 1, 24, 11, 10, 9, 3, 25, 45, 36, 45, 1, 52, 14, 0, 24, 24, 33, 37, 7, 22, 3, 2, 6, 18, 11, 0, 16, 5, 7, 19, 5, 0, 15, 39, 31, 4, 24, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 41, 99, 1, 36, 32, 1, 11, 11, 33, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 2, 11, 6, 1, 0, 19, 14, 0, 0, 0, 34, 26, 63, 20, 46, 34, 9, 24, 37, 53, 25, 20, 2, 14, 2, 2, 0, 5, 8, 1, 21, 11, 3, 28, 2, 4, 36, 8, 34, 31, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 23, 43, 23, 24, 31, 62, 24, 2, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 14, 20, 16, 0, 0, 0, 0, 35, 58, 60, 77, 29, 24, 44, 11, 0, 5, 1, 4, 0, 4, 3, 0, 0, 0, 2, 34, 12, 0, 52, 15, 22, 37, 2, 14, 26, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 32, 31, 10, 42, 32, 21, 29, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 27, 47, 82, 33, 22, 28, 20, 22, 21, 7, 6, 1, 0, 0, 0, 2, 0, 0, 0, 10, 15, 9, 27, 0, 1, 0, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 74, 19, 31, 0, 9, 4, 27, 22, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 58, 13, 13, 46, 47, 4, 47, 14, 35, 3, 5, 4, 18, 4, 0, 0, 0, 0, 1, 1, 10, 0, 4, 0, 0, 0, 8, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 89, 20, 13, 5, 4, 3, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 38, 30, 39, 18, 24, 8, 6, 4, 0, 0, 1, 1, 4, 1, 2, 1, 0, 0, 6, 6, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 31, 2, 45, 30, 72, 68, 9, 27, 2, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 6, 8, 2, 6, 15, 7, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 99, 21, 23, 0, 2, 33, 1, 22, 44, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 29, 4, 1, 1, 1, 4, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 13, 9, 31, 7, 29, 30, 23, 2, 36, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 13, 4, 5, 2, 5, 2, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 47, 39, 11, 16, 41, 40, 56, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 12, 13, 11, 13, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 45, 16, 24, 14, 3, 27, 84, 23, 23, 11, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 1, 4, 0, 1, 8, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 18, 9, 1, 22, 31, 57, 9, 46, 33, 19, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 4, 2, 1, 10, 8, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 9, 11, 14, 45, 46, 34, 31, 27, 43, 16, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0, 3, 1, 2, 7, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 2, 30, 23, 30, 7, 30, 14, 20, 49, 79, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 35, 10, 14, 33, 54, 30, 61, 38, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 22, 24, 46, 7, 30, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 5, 0, 0, 0, 5, 17, 20, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 2, 2, 3, 0, 13, 23, 11, 10, 14, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 11, 1, 0, 27, 11, 10, 5, 21, 7, 14, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 41, 29, 9, 1, 8, 2, 12, 72, 16, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 6, 17, 4, 10, 25, 13, 15, 16, 12, 1, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 22, 10, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 21, 0, 0, 0, 1, 3, 45, 31, 1, 91, 73, 2, 50, 0, 19, 2, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 17, 15, 87, 9, 30, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 9, 17, 0, 0, 0, 0, 0, 36, 6, 19, 46, 8, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 34, 38, 48, 15, 39, 1, 2, 13, 5, 9, 35, 24, 36, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 23, 0, 0, 0, 0, 0, 0, 37, 27, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 28, 27, 54, 21, 3, 8, 36, 2, 0, 8, 18, 37, 11, 75, 20, 9, 5, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 29, 27, 1, 0, 0, 0, 0, 0, 99, 92, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 17, 81, 40, 45, 15, 42, 33, 5, 37, 55, 28, 14, 8, 8, 4, 20, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 14, 12, 43, 71, 19, 27, 59, 23, 61, 31, 23, 28, 48, 12, 27, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 99, 97, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 16, 29, 12, 7, 57, 46, 21, 4, 15, 56, 6, 46, 54, 0, 17, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 20, 40, 42, 35, 5, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 24, 8, 1, 48, 43, 20, 26, 8, 11, 7, 13, 25, 26, 23, 5, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 25, 50, 99, 19, 0, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 6, 11, 0, 3, 68, 3, 1, 32, 27, 23, 20, 6, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 1, 27, 99, 87, 43, 50, 5, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 2, 24, 45, 45, 15, 23, 71, 16, 24, 2, 25, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 11, 0, 1, 20, 99, 6, 20, 27, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 3, 41, 36, 14, 16, 30, 46, 59, 58, 32, 29, 32, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 11, 12, 0, 17, 11, 99, 99, 59, 22, 19, 21, 3, 3, 11, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 3, 99, 14, 6, 7, 37, 30, 8, 0, 37, 18, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 2, 2, 10, 11, 9, 31, 95, 99, 43, 5, 10, 12, 9, 7, 16, 24, 6, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 8, 18, 26, 2, 19, 23, 28, 20, 78, 8, 1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 14, 9, 15, 12, 2, 28, 59, 41, 28, 4, 2, 8, 19, 1, 3, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 8, 9, 2, 28, 20, 11, 31, 4, 26, 19, 18, 15, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 22, 12, 23, 7, 3, 6, 19, 78, 22, 10, 3, 5, 13, 21, 2, 10, 15, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 15, 1, 2, 9, 39, 14, 28, 27, 2, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 1, 9, 30, 15, 0, 4, 3, 17, 27, 2, 25, 40, 7, 13, 25, 6, 15, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 5, 23, 0, 1, 47, 17, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 15, 5, 4, 44, 10, 19, 2, 1, 0, 3, 9, 5, 9, 8, 13, 3, 21, 7, 19, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 3, 13, 23, 5, 7, 4, 17, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 2, 0, 24, 2, 4, 4, 2, 16, 0, 1, 21, 10, 2, 2, 2, 0, 26, 11, 3, 6, 2, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 27, 12, 0, 33, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 2, 18, 13, 11, 18, 4, 3, 2, 0, 3, 11, 18, 9, 5, 10, 8, 5, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 5, 19, 8, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 3, 4, 0, 1, 5, 1, 5, 2, 0, 2, 2, 1, 3, 2, 4, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 3, 18, 1, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 8, 1, 0, 0, 2, 5, 7, 3, 2, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 2, 0}, -{0, 0, 0, 0, 0, 0, 7, 1, 10, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 4, 2}, -{0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 5, 1, 3, 9, 0, 0, 0, 0, 0, 0, 0, 4, 2, 3, 1, 0, 1, 3, 0, 5}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 13, 2, 19, 10, 1, 0, 0, 0, 0, 1, 5, 7, 1, 3, 7, 1, 0, 5}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 10, 19, 14, 19, 11, 23, 16, 3, 6, 5, 0, 0, 0, 0, 1, 0, 0, 5, 1, 3, 1, 17, 2}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 15, 7, 6, 3, 10, 4, 21, 0, 3, 4, 10, 0, 0, 0, 2, 1, 0, 4, 2, 4, 7, 18}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 14, 3, 0, 11, 26, 2, 10, 20, 3, 12, 11, 30, 0, 0, 0, 0, 1, 1, 2, 0, 2, 1, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 33, 21, 7, 39, 29, 4, 13, 6, 4, 12, 7, 11, 0, 0, 0, 0, 0, 0, 1, 5, 1, 3, 0, 18, 26}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 16, 11, 11, 0, 18, 5, 4, 7, 7, 1, 14, 3, 0, 3, 1, 1, 1, 0, 0, 2, 1, 7, 4, 8, 11}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 21, 27, 9, 12, 10, 4, 14, 3, 3, 0, 13, 5, 2, 3, 3, 5, 14, 3, 19, 0, 3, 2, 8, 12}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 6, 2, 0, 4, 28, 4, 9, 20, 7, 23, 6, 0, 6, 7, 4, 4, 23, 8, 5, 7, 11, 9, 8, 5}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 6, 10, 51, 17, 32, 1, 11, 3, 5, 10, 0, 1, 6, 12, 0, 18, 8, 0, 0, 1, 14}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 9, 16, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, 1, 7, 0, 22, 4, 8, 3, 23, 5, 27, 6, 1, 24, 2, 2, 11, 10, 10, 1, 0, 5}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 20, 9, 3, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 8, 1, 8, 17, 0, 9, 1, 11, 2, 14, 10, 6, 25, 0, 10, 5, 14, 2, 8, 0, 1, 6, 5, 1}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 21, 7, 3, 0, 15, 11, 2, 25, 0, 1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 10, 26, 31, 17, 8, 11, 18, 10, 5, 0, 2, 1, 14, 8, 32, 8, 12, 10, 12, 5, 0, 9, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20, 2, 0, 0, 7, 13, 2, 0, 0, 15, 28, 9, 4, 19, 35, 10, 0, 12, 6, 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 12, 0, 11, 0, 4, 15, 18, 24, 10, 11, 35, 3, 1, 4, 17, 13, 2, 6, 0, 11, 2, 2}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 0, 10, 7, 25, 11, 5, 6, 0, 0, 10, 8, 7, 41, 17, 14, 1, 10, 20, 11, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 19, 2, 1, 12, 21, 4, 7, 4, 3, 1, 19, 0, 0, 14, 9, 21, 0, 1, 15, 0, 1, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 4, 9, 22, 10, 0, 46, 12, 3, 3, 2, 1, 0, 11, 5, 65, 7, 13, 14, 5, 5, 21, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10, 10, 0, 1, 6, 18, 1, 11, 3, 6, 24, 2, 1, 0, 24, 2, 4, 1, 1, 0, 3, 1}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 2, 7, 4, 18, 2, 0, 7, 11, 2, 5, 15, 20, 1, 6, 11, 6, 13, 3, 2, 17, 15, 6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 16, 7, 6, 22, 0, 7, 12, 16, 2, 10, 1, 7, 17, 3, 3, 12, 19, 2, 2, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 25, 15, 21, 4, 2, 0, 18, 1, 0, 2, 9, 9, 0, 3, 4, 27, 16, 38, 1, 11, 13, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 0, 9, 7, 12, 23, 0, 11, 32, 3, 20, 5, 2, 5, 1, 0, 5, 5, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 33, 11, 4, 4, 3, 1, 5, 5, 0, 0, 0, 2, 5, 5, 2, 10, 9, 15, 16, 28, 11, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 7, 1, 2, 0, 2, 9, 3, 2, 32, 30, 0, 3, 2, 3, 5, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 20, 23, 8, 22, 2, 3, 9, 3, 14, 6, 1, 0, 0, 0, 0, 0, 1, 2, 0, 48, 1, 26, 44, 1, 2, 8, 14, 6, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 10, 0, 0, 0, 0, 0, 1, 11, 3, 15, 7, 15, 11, 2, 9, 4, 4, 0, 7}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 6, 11, 6, 22, 9, 7, 5, 20, 18, 7, 1, 1, 1, 0, 0, 0, 2, 4, 10, 24, 1, 14, 14, 33, 8, 18, 4, 23, 32, 3, 2, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 28, 7, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 5, 12, 0, 9, 51, 0, 12, 0, 0, 1, 4, 6, 13, 4, 1, 4, 8, 5, 6, 14, 18, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 1, 23, 2, 26, 8, 8, 0, 24, 12, 48, 2, 39, 1, 20, 0, 1, 0, 0, 7, 28, 14, 14, 2, 8, 40, 20, 9, 16, 25, 9, 9, 6, 6, 1, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 4, 8, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 8, 1, 6, 5, 0, 0, 5, 0, 0, 0, 4, 6, 26, 11, 16, 1, 22, 1, 14, 25, 0, 6, 3}, -{0, 0, 0, 0, 0, 0, 2, 5, 11, 11, 10, 2, 21, 2, 4, 20, 18, 2, 22, 0, 23, 26, 1, 17, 2, 1, 22, 0, 8, 2, 13, 56, 14, 22, 47, 99, 39, 4, 11, 5, 3, 14, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 11, 2, 9, 16, 9, 4, 0, 0, 0, 0, 0, 9, 2, 0, 7, 6, 14, 9, 39, 13, 2, 0, 7, 1, 15, 3, 5, 46, 9, 13, 4, 0, 0, 10, 1}, -{0, 0, 0, 0, 0, 0, 0, 14, 13, 8, 12, 0, 5, 1, 4, 23, 14, 33, 0, 67, 9, 15, 5, 7, 6, 1, 8, 17, 37, 25, 6, 23, 16, 33, 37, 15, 4, 36, 30, 9, 20, 4, 25, 9, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 10, 1, 0, 23, 12, 6, 22, 15, 9, 4, 6, 0, 2, 0, 0, 0, 4, 0, 0, 10, 8, 6, 25, 22, 9, 36, 0, 1, 5, 5, 18, 11, 15, 19, 0, 32, 7, 0, 3, 0}, -{0, 0, 0, 0, 2, 15, 2, 3, 5, 11, 27, 0, 23, 8, 28, 9, 8, 3, 8, 16, 13, 28, 20, 7, 20, 1, 23, 42, 16, 6, 25, 41, 29, 43, 58, 2, 26, 27, 13, 21, 22, 22, 46, 7, 15, 6, 18, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 6, 11, 12, 3, 19, 19, 28, 5, 4, 19, 0, 0, 0, 0, 0, 6, 8, 8, 1, 10, 3, 4, 12, 1, 7, 14, 9, 0, 15, 4, 1, 17, 5, 2, 11, 8, 8, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 5, 0, 41, 11, 27, 12, 1, 13, 13, 10, 16, 4, 2, 17, 6, 4, 1, 1, 2, 25, 24, 42, 10, 15, 0, 26, 26, 29, 18, 99, 1, 40, 38, 19, 2, 24, 8, 4, 25, 41, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 12, 0, 99, 13, 6, 5, 27, 3, 16, 4, 23, 5, 0, 0, 0, 6, 7, 8, 2, 13, 1, 28, 7, 5, 19, 14, 14, 0, 1, 27, 15, 3, 3, 2, 9, 7, 5, 1}, -{0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 13, 7, 0, 6, 22, 4, 3, 10, 6, 40, 0, 6, 10, 40, 27, 17, 2, 1, 28, 0, 5, 28, 7, 10, 39, 6, 34, 52, 35, 8, 78, 6, 10, 41, 25, 33, 3, 36, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 4, 8, 32, 11, 15, 35, 30, 37, 19, 28, 30, 35, 14, 0, 0, 0, 10, 18, 4, 4, 54, 7, 21, 6, 6, 17, 5, 7, 0, 0, 1, 8, 7, 19, 8, 9, 0, 0, 0, 3}, -{0, 0, 0, 0, 0, 0, 3, 0, 21, 10, 4, 15, 22, 1, 1, 5, 8, 2, 29, 23, 21, 2, 30, 2, 1, 3, 13, 57, 5, 26, 5, 32, 44, 8, 22, 36, 46, 0, 10, 21, 10, 7, 10, 25, 3, 2, 14, 17, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 14, 12, 20, 8, 5, 1, 27, 0, 1, 19, 22, 25, 18, 2, 1, 16, 0, 2, 1, 0, 28, 2, 1, 1, 6, 15, 11, 0, 0, 0, 0, 12, 4, 10, 8, 3, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 10, 4, 22, 9, 2, 2, 6, 4, 8, 7, 7, 16, 16, 18, 11, 27, 32, 34, 49, 4, 99, 14, 4, 63, 34, 5, 32, 9, 3, 18, 48, 51, 12, 8, 41, 10, 7, 8, 30, 12, 1, 26, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 12, 7, 11, 34, 3, 23, 18, 32, 5, 3, 36, 11, 6, 2, 0, 30, 29, 25, 0, 4, 4, 12, 3, 16, 6, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 7, 6, 19, 13, 6, 0, 1, 3, 1, 0, 3, 20, 4, 13, 0, 3, 6, 26, 1, 59, 42, 99, 21, 17, 26, 69, 5, 2, 47, 36, 88, 9, 6, 23, 47, 18, 11, 4, 25, 33, 32, 3, 41, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 1, 8, 4, 12, 6, 30, 23, 1, 5, 18, 50, 19, 24, 8, 10, 8, 1, 6, 8, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 7, 0, 0, 0, 0, 0, 2, 1, 4, 8, 7, 1, 9, 40, 13, 68, 39, 18, 1, 27, 27, 23, 30, 13, 23, 12, 9, 20, 24, 68, 27, 45, 29, 34, 31, 22, 13, 4, 19, 8, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 7, 3, 6, 0, 1, 11, 5, 10, 11, 22, 10, 25, 17, 8, 7, 1, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 11, 1, 0, 0, 0, 0, 0, 0, 1, 6, 1, 13, 19, 2, 67, 99, 33, 7, 6, 1, 29, 46, 5, 17, 53, 5, 0, 41, 20, 17, 9, 52, 21, 19, 47, 19, 0, 26, 9, 0, 14, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 21, 11, 3, 8, 2, 27, 53, 36, 20, 50, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 9, 9, 11, 10, 6, 3, 50, 99, 82, 21, 31, 27, 15, 8, 6, 6, 28, 3, 66, 7, 1, 22, 9, 76, 4, 13, 46, 50, 6, 20, 6, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 13, 2, 15, 18, 7, 3, 8, 18, 3, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 2, 6, 2, 1, 21, 42, 99, 47, 16, 47, 12, 14, 3, 26, 3, 37, 51, 18, 1, 5, 13, 4, 40, 26, 45, 28, 1, 47, 16, 8, 2, 2, 2, 0, 0, 3, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 39, 32, 25, 9, 22, 3, 7, 14, 75, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 16, 11, 20, 13, 3, 68, 99, 20, 15, 10, 15, 0, 8, 15, 3, 3, 14, 27, 25, 27, 3, 0, 13, 12, 31, 8, 2, 18, 4, 13, 0, 0, 0, 5, 0, 2, 9, 0, 0, 1, 4, 1, 0, 0, 2, 3, 7, 2, 1, 11, 17, 2, 10, 11, 1, 32, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 5, 4, 3, 4, 7, 11, 9, 15, 43, 14, 17, 2, 18, 0, 12, 5, 26, 7, 11, 7, 42, 22, 19, 0, 5, 5, 5, 3, 9, 11, 0, 3, 0, 0, 2, 3, 17, 1, 3, 0, 0, 0, 11, 0, 7, 0, 0, 14, 6, 1, 36, 8, 5, 99, 2, 30, 21, 20, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 5, 0, 5, 8, 3, 4, 0, 6, 0, 4, 9, 3, 5, 3, 28, 21, 35, 20, 25, 35, 26, 12, 7, 41, 32, 22, 9, 25, 6, 0, 2, 0, 0, 6, 3, 6, 12, 1, 15, 4, 2, 1, 0, 2, 0, 30, 21, 2, 1, 15, 21, 1, 34, 12, 25, 21, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 9, 13, 1, 4, 11, 0, 2, 27, 3, 6, 6, 0, 0, 1, 0, 33, 31, 16, 22, 14, 20, 3, 0, 1, 54, 15, 3, 22, 2, 0, 0, 0, 0, 1, 4, 0, 3, 2, 4, 2, 0, 0, 2, 13, 5, 8, 11, 4, 4, 39, 23, 35, 27, 3, 10, 14, 21, 12, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, 0, 2, 0, 2, 1, 1, 19, 7, 4, 11, 10, 2, 0, 21, 0, 16, 65, 1, 20, 2, 2, 42, 30, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4, 3, 9, 4, 7, 0, 5, 17, 10, 1, 11, 4, 1, 7, 18, 0, 6, 22, 1, 15, 2, 12, 0, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 10, 13, 2, 1, 2, 0, 1, 8, 1, 6, 9, 6, 0, 10, 18, 37, 24, 12, 15, 4, 35, 4, 10, 18, 24, 20, 0, 0, 0, 0, 0, 3, 1, 4, 11, 0, 0, 0, 1, 7, 2, 1, 6, 5, 22, 34, 21, 12, 22, 24, 3, 50, 4, 15, 5, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 4, 1, 0, 4, 14, 0, 3, 3, 1, 0, 1, 5, 4, 17, 1, 13, 3, 24, 30, 25, 27, 4, 10, 21, 2, 2, 0, 6, 0, 0, 0, 0, 0, 3, 1, 2, 6, 11, 3, 22, 13, 1, 19, 8, 14, 1, 3, 4, 5, 8, 12, 2, 25, 1, 7, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 4, 0, 3, 0, 3, 1, 6, 2, 2, 0, 0, 8, 0, 2, 5, 1, 0, 42, 52, 8, 27, 24, 41, 12, 22, 7, 4, 10, 0, 0, 0, 0, 0, 0, 1, 2, 0, 4, 5, 15, 7, 7, 10, 0, 17, 11, 7, 25, 2, 84, 28, 13, 0, 3, 4, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 2, 7, 2, 2, 5, 28, 11, 5, 0, 2, 1, 8, 0, 0, 0, 0, 0, 0, 0, 1, 8, 3, 25, 7, 5, 35, 5, 25, 69, 22, 60, 53, 8, 11, 3, 4, 1, 1, 1, 8, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; - return rVal; - } - - static int[][] load_Data(String path){ + int[][] load_Data(String path){ int rVal[][] = null; try (BufferedReader br = new BufferedReader(new FileReader(path));){ String line; line = br.readLine(); int dim_x = Integer.parseInt(line); - DIMENSION = dim_x; + interpolationPhaseDimension = dim_x; line = br.readLine(); int dim_y = Integer.parseInt(line); rVal = new int[dim_x][dim_y]; @@ -1381,7 +1433,7 @@ public class TerrainGen { return rVal; } - public static void increment_Current_Continent(){ + public void increment_Current_Continent(){ current_Continent++; if (current_Continent > numberContinents - 1) { current_Continent = 0; @@ -1394,10 +1446,13 @@ public class TerrainGen { } } - public static void increment_Display_Toggle(){ - display_toggle++; - if(display_toggle > max_Display_Toggle){ - display_toggle = 0; + /** + * Increments the display mode of the built in data renderer + */ + public void incrementDisplayToggle(){ + displayToggle++; + if(displayToggle > max_Display_Toggle){ + displayToggle = 0; } } diff --git a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGenerator.java b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGenerator.java index c4699482..b376e0fb 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGenerator.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGenerator.java @@ -4,126 +4,157 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; /** - * - * @author satellite + * Core continent phase terrain generator */ class TerrainGenerator { - static int DIMENSION = 200; - static int[][] asthenosphere_Heat; - static int[][] rock_Hardness; - static int[][] elevation; - static int[][] smoothed_elevation; - static int new_Elevation[][]; - static Vector[][] currents; - static List spots = new ArrayList(); - static int Time = 0; - static final int ELEVATION_DATA_LENGTH = 50; - static int[] elevation_Data; - static int current_Max_Elevation_Data = 1; - static int lifespan = 75000; + + //size of a parallelized chunk + static final int PARALLEL_CHUNK_SIZE = 32; + //number of threads for threadpool + static final int THREAD_POOL_COUNT = 16; + + //the dimensions of the map + int DIMENSION = 200; + int[][] asthenosphereHeat; + int[][] rockHardness; + int[][] elevation; + int[][] smoothedElevation; + int currentElev[][]; + int newElevation[][]; + //currents used for pushing terrain elevation around the map + Vector[][] currents; + //hotspots that thrust rock up from the ocean floor + List spots = new ArrayList(); + int time = 0; + int lifespan = 75000; + + Random rand; + + //thread pool for parallelized force calculation + ThreadPoolExecutor threadPool; - public TerrainGenerator(){ + /** + * Constructor + * @param seed Seed for random + */ + protected TerrainGenerator(long seed){ + this.rand = new Random(seed); + threadPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(THREAD_POOL_COUNT); + } + + /** + * Sets the data width + * @param newDim The dimension of the data + */ + protected void setDimension(int newDim){ + DIMENSION = newDim; + if(DIMENSION % PARALLEL_CHUNK_SIZE != 0){ + //this requirement is for parallelization purposes + throw new Error("DIMENSION MUST BE A MULTIPLE OF 16!"); + } + } + + /** + * Sets the simulation lifespan for the Continent Phase + * @param newLifespan The lifespan in units of simulation frames + */ + protected void setLifespan(int newLifespan){ + lifespan = newLifespan; + } + + /** + * Runs the continent phase simulation. Blocks until completed + */ + protected void run(){ + allocateData(); + + + long lastTime = System.currentTimeMillis(); + + //construct convection cells prior to simulation + constructConvectionCells(); + + + //main simulation + while(true){ + time++; + simulateHotspots(); + heatToElevation(); + applyVectorsToElevationParallel(); + calculateSmoothedElevations(); + + // try { +// TimeUnit.MILLISECONDS.sleep(1); +// } catch (InterruptedException ex) { +// } + if(time % 500 == 0) { + long new_Time = System.currentTimeMillis(); + long time_Delta = new_Time - lastTime; + lastTime = new_Time; + System.out.println("Progress: " + time + "/" + lifespan + " ETA: " + (time_Delta * (lifespan - time) / 1000 / 500) + "S"); + } + if(time > lifespan){ + break; + } + } + + //TODO: + //next subphase is to find large areas without continents and place ones there + //the terrain added in this next phase will be made with a more quick and dirty implementation + + + //shutdown threadpool + threadPool.shutdown(); } - public void set_Dimension(int new_Dim){ - DIMENSION = new_Dim; + /** + * Gets the raw terrain + * @return The raw terrain + */ + protected int[][] getTerrain(){ + return elevation; } - public void set_Lifespan(int new_Lifespan){ - lifespan = new_Lifespan; + /** + * Gets the terrain smoothed + * @return The terrain smoothed + */ + protected int[][] getTerrainSmoothed(){ + return smoothedElevation; } - - - public void run(){ - asthenosphere_Heat = new int[DIMENSION][DIMENSION]; + + + /** + * Allocates all arrays generated based on the dimension provided + */ + private void allocateData(){ + asthenosphereHeat = new int[DIMENSION][DIMENSION]; elevation = new int[DIMENSION][DIMENSION]; - smoothed_elevation = new int[DIMENSION][DIMENSION]; - new_Elevation = new int[DIMENSION][DIMENSION]; + smoothedElevation = new int[DIMENSION][DIMENSION]; + newElevation = new int[DIMENSION][DIMENSION]; currents = new Vector[DIMENSION][DIMENSION]; + currentElev = new int[DIMENSION][DIMENSION]; for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ currents[x][y] = new Vector(); } } - elevation_Data = new int[ELEVATION_DATA_LENGTH]; - for(int x = 0; x < ELEVATION_DATA_LENGTH; x++){ - elevation_Data[x] = 0; - } - - - - - long last_Time = System.currentTimeMillis(); - - - while(true){ - Time++; - if(spots.size() >= 1){ - List to_Remove = new ArrayList(); - Iterator spot_Iterator = spots.iterator(); - while(spot_Iterator.hasNext()){ - Hotspot current_Spot = spot_Iterator.next(); - if(current_Spot.life_current >= current_Spot.life_max){ - to_Remove.add(current_Spot); - } - } - spot_Iterator = to_Remove.iterator(); - while(spot_Iterator.hasNext()){ - Hotspot current_Spot = spot_Iterator.next(); - spots.remove(current_Spot); - } - } - if(spots.size() < 5){ - spots.add(new Hotspot(electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.server.terrain.generation.Utilities.random_Integer(6000, 10000), electrosphere.game.server.terrain.generation.Utilities.random_Integer(3, 5), this)); - } - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ - asthenosphere_Heat[x][y] = 0; - } - } - if(spots.size() >= 1){ - Iterator spot_Iterator = spots.iterator(); - while(spot_Iterator.hasNext()){ - Hotspot current_Spot = spot_Iterator.next(); - current_Spot.simulate(); - } - } -// try { -// TimeUnit.MILLISECONDS.sleep(1); -// } catch (InterruptedException ex) { -// } - heat_To_Elevation(); - construct_Convection_Cells(); - apply_Vectors_To_Elevation(); - calculate_Smoothed_Elevations(); - if(Time % 500 == 0) { - long new_Time = System.currentTimeMillis(); - long time_Delta = new_Time - last_Time; - last_Time = new_Time; - System.out.println("Progress: " + Time + "/" + lifespan + " ETA: " + (time_Delta * (lifespan - Time) / 1000 / 500) + "S"); - } - if(Time > lifespan){ - break; - } - } } - public int[][] get_Terrain(){ - return elevation; - } - - public int[][] get_Terrain_Smoothed(){ - return smoothed_elevation; - } - - static void heat_To_Elevation(){ + /** + * If the asthenosphere is sufficiently hot, increases elevation of position + */ + private void heatToElevation(){ for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ - if(asthenosphere_Heat[x][y] > 25){ - if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 10) == 10){ + if(asthenosphereHeat[x][y] > 25){ + if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 10, rand) == 10){ elevation[x][y] = elevation[x][y] + 1; if(elevation[x][y] > 100){ elevation[x][y] = 100; @@ -134,160 +165,172 @@ class TerrainGenerator { } } - static void construct_Convection_Cells(){ - boolean is_cell_type_1 = false; + /** + * Constructs convection cells in the force vector field + */ + private void constructConvectionCells(){ + //controls whether the cell rotates clockwise or couterclockwise + boolean isCellType1 = false; + //one fourth of the width of the data set int fourth = DIMENSION / 4; for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ - int normalized_x = x; - int normalized_y = y; + //the current position RELATIVE to the center point of the current convection cell center + int normalizedX = x; + int normalizedY = y; + + //determine relative position and whether convection cell type one or two if(y < fourth || (y < fourth * 3 && y > (fourth * 2) - 1)){ - is_cell_type_1 = true; - if(normalized_y > fourth){ - normalized_y = normalized_y - fourth * 2; + isCellType1 = true; + if(normalizedY > fourth){ + normalizedY = normalizedY - fourth * 2; } } else { - is_cell_type_1 = false; - if(normalized_y > fourth * 2 + 1){ - normalized_y = normalized_y - fourth * 3; + isCellType1 = false; + if(normalizedY > fourth * 2 + 1){ + normalizedY = normalizedY - fourth * 3; } else { - normalized_y = normalized_y - fourth; + normalizedY = normalizedY - fourth; } } - while(normalized_x > fourth){ - normalized_x = normalized_x - fourth; + while(normalizedX > fourth){ + normalizedX = normalizedX - fourth; } - if(normalized_x < 0){ - normalized_x = 0; + if(normalizedX < 0){ + normalizedX = 0; } - if(normalized_y < 0){ - normalized_y = 0; + if(normalizedY < 0){ + normalizedY = 0; } + + //one eighth of the width of the data set int eigth = fourth / 2; - normalized_y = normalized_y - eigth; - normalized_x = normalized_x - eigth; - float magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2)); + //Moves the relative position to be in its correct eighth + normalizedY = normalizedY - eigth; + normalizedX = normalizedX - eigth; + + //calculates the distance from convection cell center to the relative position + float magnitude = (float)Math.sqrt(Math.pow(normalizedY, 2) + Math.pow(normalizedX, 2)); + + //If the distance is small enough we stretch it along the X axis ... ? if(magnitude < fourth / 10){ - normalized_x = normalized_x + fourth / 10; - magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2)); + normalizedX = normalizedX + fourth / 10; + magnitude = (float)Math.sqrt(Math.pow(normalizedY, 2) + Math.pow(normalizedX, 2)); } - double offset_angle = Math.atan2(normalized_y / magnitude, normalized_x / magnitude); - if(offset_angle < 0){ - offset_angle = offset_angle + Math.PI * 2; + + //calculates the angle of the point relative to convection cell center + double offsetAngle = Math.atan2(normalizedY / magnitude, normalizedX / magnitude); + if(offsetAngle < 0){ + offsetAngle = offsetAngle + Math.PI * 2; } - double vector_angle = offset_angle; - if(is_cell_type_1){ - offset_angle = offset_angle + Math.PI / 2; + + //rotate based on cell type + if(isCellType1){ + offsetAngle = offsetAngle + Math.PI / 2; } else { - offset_angle = offset_angle - Math.PI / 2; + offsetAngle = offsetAngle - Math.PI / 2; } - while(offset_angle > Math.PI * 2){ - offset_angle = offset_angle - Math.PI * 2; + //normalize + while(offsetAngle > Math.PI * 2){ + offsetAngle = offsetAngle - Math.PI * 2; } - while(offset_angle < 0){ - offset_angle = offset_angle + Math.PI * 2; + while(offsetAngle < 0){ + offsetAngle = offsetAngle + Math.PI * 2; } - currents[x][y].x = (int)(99 * Math.cos(offset_angle)); - currents[x][y].y = (int)(99 * Math.sin(offset_angle)); + //Lastly, actually set the force vector + currents[x][y].x = (int)(99 * Math.cos(offsetAngle)); + currents[x][y].y = (int)(99 * Math.sin(offsetAngle)); } } } - static void apply_Vectors_To_Elevation(){ - int current_Elev[][] = new int[DIMENSION][DIMENSION]; + /** + * Moves the terrain around based on the vector field + */ + private void applyVectorsToElevation(){ + //allocate new elevation array for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ - new_Elevation[x][y] = 0; - current_Elev[x][y] = elevation[x][y]; + newElevation[x][y] = 0; + currentElev[x][y] = elevation[x][y]; } } + //transfer terrain for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ - boolean transfer = false; - if (electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 50) == 1) { - transfer = true; - } - int transfer_goal; - if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 2)==1){ - transfer_goal = electrosphere.game.server.terrain.generation.Utilities.random_Integer(20, 60); - } else { - transfer_goal = electrosphere.game.server.terrain.generation.Utilities.random_Integer(0, 60); - } - if(electrosphere.game.server.terrain.generation.Utilities.random_Integer(1, 2)==1){ - if (currents[x][y].x >= 0) { - if (transfer) { - if (x + 1 < DIMENSION) { - while(new_Elevation[x + 1][y] + current_Elev[x + 1][y] < 99 && current_Elev[x][y] > transfer_goal){ - new_Elevation[x + 1][y]++; - current_Elev[x][y]--; - } - } else { - } - } - } else { - if (transfer) { - if (x - 1 >= 0) { - while(new_Elevation[x - 1][y] + current_Elev[x - 1][y] < 99 && current_Elev[x][y] > transfer_goal){ - new_Elevation[x - 1][y]++; - current_Elev[x][y]--; - } - } else { + boolean transfer = false; + if (Utilities.random_Integer(1, 50, rand) == 1) { + transfer = true; + } + int transfer_goal; + if(Utilities.random_Integer(1, 2, rand)==1){ + transfer_goal = Utilities.random_Integer(20, 60, rand); + } else { + transfer_goal = Utilities.random_Integer(0, 60, rand); + } + if(Utilities.random_Integer(1, 2, rand)==1){ + if (currents[x][y].x >= 0) { + if (transfer) { + if (x + 1 < DIMENSION) { + while(newElevation[x + 1][y] + currentElev[x + 1][y] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x + 1][y]++; + currentElev[x][y]--; } + } else { } } } else { - if (currents[x][y].y >= 0) { - if (transfer) { - if (y + 1 < DIMENSION) { // V REPLACE THIS WITH GOAL - while(new_Elevation[x][y + 1] + current_Elev[x][y + 1] < 99 && current_Elev[x][y] > transfer_goal){ - new_Elevation[x][y + 1]++; - current_Elev[x][y]--; - } - } else { - } - } - } else { - if (transfer) { - if (y - 1 >= 0) { - while(new_Elevation[x][y - 1] + current_Elev[x][y - 1] < 99 && current_Elev[x][y] > transfer_goal){ - new_Elevation[x][y - 1]++; - current_Elev[x][y]--; - } - } else { + if (transfer) { + if (x - 1 >= 0) { + while(newElevation[x - 1][y] + currentElev[x - 1][y] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x - 1][y]++; + currentElev[x][y]--; } + } else { + } + } + } + } else { + if (currents[x][y].y >= 0) { + if (transfer) { + if (y + 1 < DIMENSION) { // V REPLACE THIS WITH GOAL + while(newElevation[x][y + 1] + currentElev[x][y + 1] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x][y + 1]++; + currentElev[x][y]--; + } + } else { + } + } + } else { + if (transfer) { + if (y - 1 >= 0) { + while(newElevation[x][y - 1] + currentElev[x][y - 1] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x][y - 1]++; + currentElev[x][y]--; + } + } else { } } } - } - } - for(int x = 0; x < DIMENSION; x++){ - for(int y = 0; y < DIMENSION; y++){ - new_Elevation[x][y] = new_Elevation[x][y] + current_Elev[x][y]; - while(new_Elevation[x][y] > 99){ - new_Elevation[x][y] = 99; } - elevation[x][y] = new_Elevation[x][y]; } } - } - - static void grab_Elevation_Data(){ - int new_Elevation_Data_Val = 0; + //move data from temporary array to main array for(int x = 0; x < DIMENSION; x++){ for(int y = 0; y < DIMENSION; y++){ - new_Elevation_Data_Val = new_Elevation_Data_Val + elevation[x][y]; + newElevation[x][y] = newElevation[x][y] + currentElev[x][y]; + while(newElevation[x][y] > 99){ + newElevation[x][y] = 99; + } + elevation[x][y] = newElevation[x][y]; } } - for(int x = 1; x < ELEVATION_DATA_LENGTH; x++){ - elevation_Data[x-1] = elevation_Data[x]; - } - elevation_Data[ELEVATION_DATA_LENGTH - 1] = new_Elevation_Data_Val; - if(new_Elevation_Data_Val > current_Max_Elevation_Data){ - current_Max_Elevation_Data = new_Elevation_Data_Val; - } } - static void calculate_Smoothed_Elevations(){ + /** + * Applies a smooth kernel to the terrain data + */ + private void calculateSmoothedElevations(){ int[][] buffer = new int[DIMENSION][DIMENSION]; for(int x = 1; x < DIMENSION - 2; x++){ for(int y = 1; y < DIMENSION - 2; y++){ @@ -297,19 +340,306 @@ class TerrainGenerator { while(buffer[x][y] > 100){ buffer[x][y] = buffer[x][y]/2; } - smoothed_elevation[x][y] = buffer[x][y]; + smoothedElevation[x][y] = buffer[x][y]; } } for(int x = 1; x < DIMENSION - 2; x++){ for(int y = 1; y < DIMENSION - 2; y++){ - buffer[x][y] = smoothed_elevation[x][y] * 4 * smoothed_elevation[x+1][y] * 2 + smoothed_elevation[x-1][y] * 2 + smoothed_elevation[x][y+1] * 2 + - smoothed_elevation[x][y-1] * 2 + smoothed_elevation[x+1][y+1] + smoothed_elevation[x+1][y-1] + smoothed_elevation[x-1][y+1] + smoothed_elevation[x-1][y-1]; + buffer[x][y] = smoothedElevation[x][y] * 4 * smoothedElevation[x+1][y] * 2 + smoothedElevation[x-1][y] * 2 + smoothedElevation[x][y+1] * 2 + + smoothedElevation[x][y-1] * 2 + smoothedElevation[x+1][y+1] + smoothedElevation[x+1][y-1] + smoothedElevation[x-1][y+1] + smoothedElevation[x-1][y-1]; buffer[x][y] = (int)(buffer[x][y] / 16.0); while(buffer[x][y] > 100){ buffer[x][y] = buffer[x][y]/2; } - smoothed_elevation[x][y] = buffer[x][y]; + smoothedElevation[x][y] = buffer[x][y]; } } } + + /** + * simulates the hotspot logic + */ + private void simulateHotspots(){ + if(spots.size() >= 1){ + List to_Remove = new ArrayList(); + Iterator spot_Iterator = spots.iterator(); + while(spot_Iterator.hasNext()){ + Hotspot current_Spot = spot_Iterator.next(); + if(current_Spot.life_current >= current_Spot.life_max){ + to_Remove.add(current_Spot); + } + } + spot_Iterator = to_Remove.iterator(); + while(spot_Iterator.hasNext()){ + Hotspot current_Spot = spot_Iterator.next(); + spots.remove(current_Spot); + } + } + if(spots.size() < 5){ + spots.add(new Hotspot( + Utilities.random_Integer(0, DIMENSION - 1, rand), + Utilities.random_Integer(0, DIMENSION - 1, rand), + Utilities.random_Integer(6000, 10000, rand), + Utilities.random_Integer(3, 5, rand), + this)); + } + for(int x = 0; x < DIMENSION; x++){ + for(int y = 0; y < DIMENSION; y++){ + asthenosphereHeat[x][y] = 0; + } + } + if(spots.size() >= 1){ + Iterator spot_Iterator = spots.iterator(); + while(spot_Iterator.hasNext()){ + Hotspot current_Spot = spot_Iterator.next(); + current_Spot.simulate(); + } + } + } + + + /** + * Fills in the gaps not covered by the main chunks + */ + private void applyVectorToElevationGaps(){ + for(int x = 0; x < DIMENSION; x++){ + for(int y = 0; y < DIMENSION; y++){ + if(x % 16 == 0 || x % 16 == 1 || y % 16 == 0 || y % 16 == 1){ + boolean transfer = false; + if (Utilities.random_Integer(1, 50, rand) == 1) { + transfer = true; + } + int transfer_goal; + if(Utilities.random_Integer(1, 2, rand)==1){ + transfer_goal = Utilities.random_Integer(20, 60, rand); + } else { + transfer_goal = Utilities.random_Integer(0, 60, rand); + } + if(Utilities.random_Integer(1, 2, rand)==1){ + if (currents[x][y].x >= 0) { + if (transfer) { + if (x + 1 < DIMENSION) { + while(newElevation[x + 1][y] + currentElev[x + 1][y] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x + 1][y]++; + currentElev[x][y]--; + } + } else { + } + } + } else { + if (transfer) { + if (x - 1 >= 0) { + while(newElevation[x - 1][y] + currentElev[x - 1][y] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x - 1][y]++; + currentElev[x][y]--; + } + } else { + } + } + } + } else { + if (currents[x][y].y >= 0) { + if (transfer) { + if (y + 1 < DIMENSION) { // V REPLACE THIS WITH GOAL + while(newElevation[x][y + 1] + currentElev[x][y + 1] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x][y + 1]++; + currentElev[x][y]--; + } + } else { + } + } + } else { + if (transfer) { + if (y - 1 >= 0) { + while(newElevation[x][y - 1] + currentElev[x][y - 1] < 99 && currentElev[x][y] > transfer_goal){ + newElevation[x][y - 1]++; + currentElev[x][y]--; + } + } else { + } + } + } + } + } + } + } + } + + + + //latch for synchronizing parallel force vector computation + CountDownLatch latch; + /** + * Moves the terrain around based on the vector field, parallelized + */ + private void applyVectorsToElevationParallel(){ + //allocate new elevation array + for(int x = 0; x < DIMENSION; x++){ + for(int y = 0; y < DIMENSION; y++){ + newElevation[x][y] = 0; + currentElev[x][y] = elevation[x][y]; + } + } + latch = new CountDownLatch(DIMENSION / PARALLEL_CHUNK_SIZE * DIMENSION / PARALLEL_CHUNK_SIZE); + //transfer terrain in main chunks + for(int x = 0; x < DIMENSION / PARALLEL_CHUNK_SIZE; x++){ + for(int y = 0; y < DIMENSION / PARALLEL_CHUNK_SIZE; y++){ + threadPool.execute(new TerrainMovementWorker( + DIMENSION, + x, + y, + new Random(rand.nextLong()), + currents, + newElevation, + currentElev, + latch + )); + } + } + //await main chunks + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //fill in gaps + applyVectorToElevationGaps(); + //move data from temporary array to main array + for(int x = 0; x < DIMENSION; x++){ + for(int y = 0; y < DIMENSION; y++){ + newElevation[x][y] = newElevation[x][y] + currentElev[x][y]; + while(newElevation[x][y] > 99){ + newElevation[x][y] = 99; + } + elevation[x][y] = newElevation[x][y]; + } + } + } + + + /** + * A worker thread for simulating terrain moving due to force vector field + */ + static class TerrainMovementWorker implements Runnable { + + //size of data map + int continentPhaseDimension; + //The offsets into the data array + int offsetX; + int offsetY; + //random + Random rand; + //force vector field + Vector[][] currents; + //new elevation map to fill in + int[][] newElevation; + //reference elevation map to pull from + int[][] referenceElevation; + //latch to resynchronize threads + CountDownLatch latch; + + protected TerrainMovementWorker( + int continentPhaseDimension, + int offsetX, + int offsetY, + Random rand, + Vector[][] currents, + int[][] newElevation, + int[][] referenceElevation, + CountDownLatch latch + ){ + this.continentPhaseDimension = continentPhaseDimension; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.rand = rand; + this.currents = currents; + this.newElevation = newElevation; + this.referenceElevation = referenceElevation; + this.latch = latch; + } + + + /** + * Runs the terrain movement simulation for this worker + */ + @Override + public void run() { + for(int x = 0; x < PARALLEL_CHUNK_SIZE; x++){ + for(int y = 0; y < PARALLEL_CHUNK_SIZE; y++){ + if(x % PARALLEL_CHUNK_SIZE != 0 && x % PARALLEL_CHUNK_SIZE != 1 && y % PARALLEL_CHUNK_SIZE != 0 && y % PARALLEL_CHUNK_SIZE != 1){ + //current absolute position in data arrays + int currentX = x + offsetX * PARALLEL_CHUNK_SIZE; + int currentY = y + offsetY * PARALLEL_CHUNK_SIZE; + + //roll whether should transfer terrain or not + boolean transfer = false; + if (Utilities.random_Integer(1, 50, rand) == 1) { + transfer = true; + } + //sets the goal of how much elevation to transfer to neighbors + int transferGoal; + if(Utilities.random_Integer(1, 2, rand)==1){ + transferGoal = Utilities.random_Integer(20, 60, rand); + } else { + transferGoal = Utilities.random_Integer(0, 60, rand); + } + //roll whether to transfer horizontally or vertically + if(Utilities.random_Integer(1, 2, rand)==1){ + //transfers horizontally + if (currents[currentX][currentY].x >= 0) { + if (transfer) { + if (currentX + 1 < continentPhaseDimension) { + while( + newElevation[currentX + 1][currentY] + referenceElevation[currentX + 1][currentY] < 99 && + referenceElevation[currentX][currentY] > transferGoal){ + newElevation[currentX + 1][currentY]++; + referenceElevation[currentX][currentY]--; + } + } + } + } else { + if (transfer) { + if (currentX - 1 >= 0) { + while( + newElevation[currentX - 1][currentY] + referenceElevation[currentX - 1][currentY] < 99 && + referenceElevation[currentX][currentY] > transferGoal){ + newElevation[currentX - 1][currentY]++; + referenceElevation[currentX][currentY]--; + } + } + } + } + } else { + //transfer vertically + if (currents[currentX][currentY].y >= 0) { + if (transfer) { + if (currentY + 1 < continentPhaseDimension) { // V REPLACE THIS WITH GOAL + while( + newElevation[currentX][currentY + 1] + referenceElevation[currentX][currentY + 1] < 99 && + referenceElevation[currentX][currentY] > transferGoal){ + newElevation[currentX][currentY + 1]++; + referenceElevation[currentX][currentY]--; + } + } + } + } else { + if (transfer) { + if (currentY - 1 >= 0) { + while( + newElevation[currentX][currentY - 1] + referenceElevation[currentX][currentY - 1] < 99 && + referenceElevation[currentX][currentY] > transferGoal){ + newElevation[currentX][currentY - 1]++; + referenceElevation[currentX][currentY]--; + } + } + } + } + } + } + } + } + latch.countDown(); + } + + } } diff --git a/src/main/java/electrosphere/game/server/terrain/generation/Utilities.java b/src/main/java/electrosphere/game/server/terrain/generation/Utilities.java index b2aac1b3..c7335d45 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/Utilities.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/Utilities.java @@ -43,10 +43,10 @@ class Utilities { System.out.println("Sleep failed lol."); } } - public static int random_Integer(int Min, int Max){ + public static int random_Integer(int Min, int Max, Random rand){ return Min + (int)(rand.nextDouble() * ((Max - Min) + 1)); } - public static int random_Range_Distribution_Even(int ... range){ + public static int random_Range_Distribution_Even(Random rand, int ... range){ if(range.length % 2 != 0){ System.out.println("Invalid number of parameters for range in a function call to \"random_Range_Distribution_Even\"!"); return -1; @@ -57,7 +57,7 @@ class Utilities { total = total + range[i+1] - range[i] + 1; i=i+2; } - int temp = random_Integer(1,total); + int temp = random_Integer(1,total,rand); int incrementer = 0; i = 0; while(incrementer + range[i+1] - range[i] + 1 < temp){ @@ -113,7 +113,7 @@ class Utilities { String rVal = ""; int line_To_Go_To; try (BufferedReader reader = new BufferedReader(new FileReader(source));){ - line_To_Go_To = random_Integer(1,Integer.parseInt(reader.readLine())); + line_To_Go_To = random_Integer(1,Integer.parseInt(reader.readLine()),rand); int i = 0; while(i