Created
August 24, 2016 16:50
-
-
Save FlorianCassayre/009f056ed1f6a7849c01d01e90ca5035 to your computer and use it in GitHub Desktop.
Random fractal generator. Customizable & scalable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.imageio.ImageIO; | |
import java.awt.*; | |
import java.awt.image.BufferedImage; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.Random; | |
/** | |
* Random fractal generator that looks like terrain. | |
* Since this is just an example, it doesn't keep track of the 'window' location. | |
* Inspired by Minecraft. | |
* @author Florian Cassayre | |
*/ | |
public class RandomFractalGenerator | |
{ | |
/** | |
* One good seed, one good p-RNG | |
*/ | |
private static Random random = new Random(42L); | |
/** | |
* Test method | |
* @param args no params | |
*/ | |
public static void main(String[] args) | |
{ | |
System.out.println("Generating..."); | |
long t1 = System.nanoTime(); | |
int[][] ints = generate(); | |
long t2 = System.nanoTime(); | |
System.out.println("Done in " + (t2 - t1) + "ns."); | |
System.out.println("Saving..."); | |
Utils.save(ints); | |
long t3 = System.nanoTime(); | |
System.out.println("Done in " + (t3 - t2) + "ns."); | |
} | |
/** | |
* Generates a custom fractal | |
* @return the map | |
*/ | |
public static int[][] generate() | |
{ | |
// Dirty example, can be much more cleaner | |
int[][] ints = getFirstIslands(16, 16, 3); | |
ints = zoom(zoom(zoom(ints))); | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
if(ints[x][y] == 0 && random.nextInt(10) == 0) | |
ints[x][y] = 1; | |
ints = zoom(zoom(zoom(ints))); | |
for(int i = 0; i < 4; i++) | |
ints = smooth(ints); | |
// In case you're wondering, this code just creates a junction between two terrains, here it's the beach | |
int[][] copy = Utils.copy(ints); | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
{ | |
int top = y > 1 ? ints[x][y - 1] : -1, | |
bottom = y < ints[0].length - 1 ? ints[x][y + 1] : -1, | |
left = x > 1 ? ints[x - 1][y] : -1, | |
right = x < ints.length - 1 ? ints[x + 1][y] : -1; | |
if((top == 0 || bottom == 0 || left == 0 || right == 0) && (top == 1 || bottom == 1 || left == 1 || right == 1)) | |
copy[x][y] = 3; | |
} | |
ints = copy; | |
ints = smooth(ints); | |
ints = zoom(ints); | |
for(int i = 0; i < 4; i++) | |
ints = smooth(ints); | |
int[][] biomes = getFirstIslands(31, 31, 2); | |
biomes = smooth(zoom(biomes)); | |
biomes = zoom(biomes); | |
biomes = zoom(biomes); | |
for(int i = 0; i < 2; i++) | |
{ | |
biomes = zoom(biomes); | |
biomes = smooth(biomes); | |
} | |
for(int i = 0; i < 2; i++) | |
biomes = zoom(biomes); | |
for(int i = 0; i < 10; i++) | |
biomes = smooth(biomes); | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
if(ints[x][y] == 1) | |
if(biomes[x][y] == 0) | |
ints[x][y] = 1; | |
else | |
ints[x][y] = 2; | |
return ints; | |
} | |
/** | |
* Generates first islands into a new map | |
* @param width the map width | |
* @param height the map height | |
* @param frequency the island frequency | |
* @return a new map | |
*/ | |
public static int[][] getFirstIslands(int width, int height, int frequency) | |
{ | |
int[][] ints = new int[width][height]; | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
ints[x][y] = random.nextInt(frequency) == 0 ? 0 : 1; | |
return ints; | |
} | |
/** | |
* Magnifies the map, initial array size <code>n</code> becomes <code>2n-1</code> | |
* @param ints the map | |
* @return a copy of the map | |
*/ | |
public static int[][] zoom(int[][] ints) | |
{ | |
int[][] copy = new int[ints.length * 2 - 1][ints[0].length * 2 - 1]; | |
for(int x = 0; x < copy.length; x++) | |
for(int y = 0; y < copy[0].length; y++) | |
{ | |
int value = 0; | |
if((x & 0xfe) == x && (y & 0xfe) == y) | |
{ | |
value = ints[x >> 1][y >> 1]; | |
} | |
else if((x & 0xfe) + 1 == x && x < copy.length - 1) | |
{ | |
value = random.nextBoolean() ? ints[x >> 1][y >> 1] : ints[(x >> 1) + 1][y >> 1]; | |
} | |
else if((y & 0xfe) + 1 == y && y < copy[0].length - 1) | |
{ | |
value = random.nextBoolean() ? ints[x >> 1][y >> 1] : ints[x >> 1][(y >> 1) + 1]; | |
} | |
else if(x > 1 && y > 1 && x < copy.length - 1 && y < copy[0].length - 1) | |
{ | |
switch(random.nextInt(4)) | |
{ | |
case 0: | |
value = ints[x >> 1][y >> 1]; | |
break; | |
case 1: | |
value = ints[(x >> 1) + 1][y >> 1]; | |
break; | |
case 2: | |
value = ints[x >> 1][(y >> 1) + 1]; | |
break; | |
case 3: | |
value = ints[(x >> 1) + 1][(y >> 1) + 1]; | |
break; | |
} | |
} | |
copy[x][y] = value; | |
} | |
return copy; | |
} | |
/** | |
* Add more smoothness to the map | |
* @param ints the map | |
* @return a smoothed version of the map | |
*/ | |
public static int[][] smooth(int[][] ints) | |
{ | |
int[][] copy = Utils.copy(ints); | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
{ | |
if(x > 0 && y > 0 && x < ints.length - 1 && y < ints.length - 1) | |
{ | |
int top = ints[x][y - 1], bottom = ints[x][y + 1], left = ints[x - 1][y], right = ints[x + 1][y]; | |
int value = ints[x][y]; | |
if(top == bottom && left == right) | |
{ | |
value = random.nextBoolean() ? top : left; | |
} | |
else if(top == bottom) | |
{ | |
value = top; | |
} | |
else if(left == right) | |
{ | |
value = left; | |
} | |
copy[x][y] = value; | |
} | |
} | |
return copy; | |
} | |
} | |
/** | |
* Useful methods than does not affect generation | |
*/ | |
final class Utils | |
{ | |
private Utils() {} | |
/** | |
* Creates a copy of the map | |
* @param ints the map | |
* @return a copy | |
*/ | |
public static int[][] copy(int[][] ints) | |
{ | |
int[][] copy = new int[ints.length][ints[0].length]; | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
copy[x][y] = ints[x][y]; | |
return copy; | |
} | |
/** | |
* Prints the map in some kind of human-readable format | |
* @param ints the map | |
*/ | |
public static void print(int[][] ints) | |
{ | |
for(int x = 0; x < ints.length; x++) | |
{ | |
for(int y = 0; y < ints[0].length; y++) | |
{ | |
System.out.print(ints[x][y]); | |
} | |
System.out.println(); | |
} | |
System.out.println(); | |
} | |
/** | |
* Saves the map into an image file. | |
* @param ints | |
*/ | |
public static void save(int[][] ints) | |
{ | |
BufferedImage off_Image = new BufferedImage(ints.length, ints[0].length, BufferedImage.TYPE_INT_ARGB); | |
Graphics2D g = off_Image.createGraphics(); | |
Color[] colors = {Color.CYAN, Color.GREEN, new Color(38, 182, 44), Color.YELLOW, new Color(40, 67, 250)}; // Static color array | |
for(int x = 0; x < ints.length; x++) | |
for(int y = 0; y < ints[0].length; y++) | |
{ | |
g.setColor(colors[ints[x][y]]); | |
g.fillRect(x, y, 1, 1); | |
} | |
try | |
{ | |
ImageIO.write(off_Image, "png", new File("")); | |
} catch(IOException e) | |
{ | |
System.out.println("Exception while saving!"); | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment