Parallel projected voxel terrain generator

Your job is to generate a heightmap and show it as a parallel projected, voxel landscape. The rules are the following:

• The (heightmap of the) landscape has to be randomly generated
• You also have to describe how the algorithm you are using works, so everyone can learn something new here
• You have to also either generate an image or display the generated landscape on the screen
• The resulting image has to be paralell projected (so not perspective), and it can only contain voxels (so it has to be made out of small boxes)
• The winner is the most upvoted valid answer 7 days after the last valid submission. All valid submissions need to follow the rules, including the description of the used algorithm. You can add additional features which do not follow some of the rules (like adding a perspective mode), but in this case they have to be optional features (e.g. when turning them off the result should follow all of the rules)
• My submission doesn't count as valid.

An example result image is the following:

Image taken from here

If you need some algorithms check here

• Minecraft esque rendered cubes does not equal voxels. Also is true isometric projection required, or is the the word used loosely as is common in games en.wikipedia.org/wiki/Video_games_with_isometric_graphics – shiona Mar 2 '14 at 21:34
• @shiona: The description of the topic was changed a few days ago to say paralell projected, so anything non-perspective should count. As for voxels: I think minecraftesqe cubes are valid in terms of being voxels: they can be considered huge pixels on a large 3D grid. – SztupY Mar 2 '14 at 22:45
• No, Minecraftesque cubes are not voxels, because voxels are not cubes, just like how pixels are not squares. citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.79.9093 – Pseudonym Mar 3 '14 at 3:18
• I agree with @Pseudonym sort of. I think it is valid though if you want them to be cubes. It does eliminate pretty much every other voxel rasterization technique though. – Tim Seguine Mar 7 '14 at 10:26

Python2 3D Function Plotter Voxel Edition

This is my entry in this competition:

import math
import random
import Image

terrain=""
randA=(random.random()*4+5)
randB=(random.random()*4+10)
randC=(random.random()*4+1)
randD=(random.random()*4+1)
im = Image.new("RGBA", (1248, 1000), "black")
tile=[Image.open("voxel/1.png"),Image.open("voxel/2.png"),Image.open("voxel/3.png"),Image.open("voxel/4.png"),Image.open("voxel/5.png"),Image.open("voxel/6.png"),Image.open("voxel/7.png"),Image.open("voxel/8.png"),Image.open("voxel/9.png")]

for y in range (-40,40):
for x in range (-10, 10):
val=int(1+abs(4+2.5*(math.sin(1/randA*x+randC)+math.sin(1/randB*y+randD))))
if (val<9):
terrain+=str(val)
else:
terrain+="9"
print terrain

for i in range (0,80*20):
if((i/20)%2==0):
shift=0
else:
shift=-32
im.paste(tile[int(terrain[i])-1],((i%20)*64+shift,((i/20)*16-(32*(int(terrain[i])-1)))-32),tile[int(terrain[i])-1])

im.show()


As clearly stated in the title it works as a 3D function plotter, but since this competition requires the terrain to be randomly generated it this random sine function 1.5*(math.sin(1/randA*x+randC)+math.sin(1/randB*y+randD)) That depends on 4 random variables. This creates terrains like this:

We can ofcourse replace this random function by any 2 variable function, for example sin(sqrt((x/2)²+(y/2)²))*3 gives this terrain:

and -x*y*e^(-x^2-y^2) gives this:
(the plots on the right are computed by wolfram alpha)

And while we're at it, Riemann zeta along the critical strip:

For the people who aren't familiar with it, as you can see these pools of water (wich represent the zero's of the function) all lie on a straight line (real part = 0.5). If you can prove this, you will get $1000000! See this link. I hope you like it! • Hi Jens, nice plots! I was wondering where you got the voxel images from ? – Willem Apr 4 '15 at 19:34 • I don't exactly remember where, I did a gogle images search and edited with paint – Jens Renders Apr 26 '15 at 12:29 C#, WPF I have experimented with a random walk, which works better than I had anticipated. I start somewhere on the map, walk to a random adjacent tile and increment its height value, then move to the next and so on. This is repeated thousands of times and eventually leads to a height map like this (100 x 100): Then, I "discretize" the map, reduce the number of values to the given height levels and assign terrain/color based on that height: More similar archipelago-like terrains: Increased number of random steps and height levels to get more mountainous terrain: Code Features: Recreate terrain with a button. Show 3D terrain and 2D map. Zooming (mouse wheel) and 3D scrolling (arrow keys). But it's not very performant - after all, this is written purely in WPF, not DirectX or OpenGL. MainWindow.xaml: <Window x:Class="VoxelTerrainGenerator.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Voxel Terrain Generator" Width="550" Height="280" KeyUp="Window_KeyUp"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Viewport3D x:Name="ViewPort" MouseWheel="ViewPort_MouseWheel"> <Viewport3D.Camera> <OrthographicCamera x:Name="Camera" Position="-100,-100,150" LookDirection="1,1,-1" UpDirection="0,0,1" Width="150" /> <!--<PerspectiveCamera x:Name="Camera" Position="-100,-100,150" LookDirection="1,1,-1" UpDirection="0,0,1" />--> </Viewport3D.Camera> </Viewport3D> <Grid Grid.Column="1" Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Image Grid.Row="0" x:Name="TopViewImage"/> <Button Grid.Row="1" Margin="0 10 0 0" Click="Button_Click" Content="Generate Terrain" /> </Grid> </Grid> </Window>  MainWindow.xaml.cs using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Input; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Media.Media3D; namespace VoxelTerrainGenerator { public partial class MainWindow : Window { const int RandomSteps = 20000; const int MapLengthX = 100; const int MapLengthY = 100; const int MaxX = MapLengthX - 1; const int MaxY = MapLengthY - 1; const bool ForceIntoBounds = true; readonly Random Random = new Random(); readonly List<Color> ColorsByHeight = new List<Color> { Color.FromArgb(0, 0, 50), Color.FromArgb(170, 170, 20), Color.FromArgb(0, 150, 0), Color.FromArgb(0, 140, 0), Color.FromArgb(0, 130, 0), Color.FromArgb(0, 120, 0), Color.FromArgb(0, 110, 0), Color.FromArgb(100, 100, 100), }; public MainWindow() { InitializeComponent(); TopViewImage.Width = MapLengthX; TopViewImage.Height = MapLengthY; } public int[,] CreateRandomHeightMap() { var map = new int[MapLengthX, MapLengthY]; int x = MapLengthX/2; int y = MapLengthY/2; for (int i = 0; i < RandomSteps; i++) { x += Random.Next(-1, 2); y += Random.Next(-1, 2); if (ForceIntoBounds) { if (x < 0) x = 0; if (x > MaxX) x = MaxX; if (y < 0) y = 0; if (y > MaxY) y = MaxY; } if (x >= 0 && x < MapLengthX && y >= 0 && y < MapLengthY) { map[x, y]++; } } return map; } public int[,] Normalized(int[,] map, int newMax) { int max = map.Cast<int>().Max(); float f = (float)newMax / (float)max; int[,] newMap = new int[MapLengthX, MapLengthY]; for (int x = 0; x < MapLengthX; x++) { for (int y = 0; y < MapLengthY; y++) { newMap[x, y] = (int)(map[x, y] * f); } } return newMap; } public Bitmap ToBitmap(int[,] map) { var bitmap = new Bitmap(MapLengthX, MapLengthY); for (int x = 0; x < MapLengthX; x++) { for (int y = 0; y < MapLengthY; y++) { int height = map[x, y]; if (height > 255) { height = 255; } var color = Color.FromArgb(255, height, height, height); bitmap.SetPixel(x, y, color); } } return bitmap; } public Bitmap ToColorcodedBitmap(int[,] map) { int maxHeight = ColorsByHeight.Count-1; var bitmap = new Bitmap(MapLengthX, MapLengthY); for (int x = 0; x < MapLengthX; x++) { for (int y = 0; y < MapLengthY; y++) { int height = map[x, y]; if (height > maxHeight) { height = maxHeight; } bitmap.SetPixel(x, y, ColorsByHeight[height]); } } return bitmap; } private void ShowTopView(int[,] map) { using (var memory = new System.IO.MemoryStream()) { ToColorcodedBitmap(map).Save(memory, ImageFormat.Png); memory.Position = 0; var bitmapImage = new System.Windows.Media.Imaging.BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = memory; bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad; bitmapImage.EndInit(); TopViewImage.Source = bitmapImage; } } private void Show3DView(int[,] map) { ViewPort.Children.Clear(); var light1 = new AmbientLight(System.Windows.Media.Color.FromArgb(255, 75, 75, 75)); var lightElement1 = new ModelUIElement3D(); lightElement1.Model = light1; ViewPort.Children.Add(lightElement1); var light2 = new DirectionalLight( System.Windows.Media.Color.FromArgb(255, 200, 200, 200), new Vector3D(0, 1, -0.1)); var lightElement2 = new ModelUIElement3D(); lightElement2.Model = light2; ViewPort.Children.Add(lightElement2); for (int x = 0; x < MapLengthX; x++) { for (int y = 0; y < MapLengthY; y++) { int height = map[x, MapLengthY-y-1]; for (int h = 0; h <= height; h++) { Color color = ColorsByHeight[h]; if (height > 0 && h == 0) { // No water under sand color = ColorsByHeight[1]; } ViewPort.Children.Add(CreateCube(x, y, h, 1, System.Windows.Media.Color.FromArgb(255, color.R, color.G, color.B))); } } } } private ModelVisual3D CreateCube(int x, int y, int z, int length, System.Windows.Media.Color color) { List<Point3D> positions = new List<Point3D>() { new Point3D(x, y, z), new Point3D(x + length, y, z), new Point3D(x + length, y + length, z), new Point3D(x, y + length, z), new Point3D(x, y, z + length), new Point3D(x + length, y, z + length), new Point3D(x + length, y + length, z + length), new Point3D(x, y + length, z + length), }; List<List<int>> quads = new List<List<int>> { new List<int> {3,2,1,0}, new List<int> {0,1,5,4}, new List<int> {2,6,5,1}, new List<int> {3,7,6,2}, new List<int> {3,0,4,7}, new List<int> {4,5,6,7}, }; double halfLength = (double)length / 2.0; Point3D cubeCenter = new Point3D(x + halfLength, y + halfLength, z + halfLength); var mesh = new MeshGeometry3D(); foreach (List<int> quad in quads) { int indexOffset = mesh.Positions.Count; mesh.Positions.Add(positions[quad[0]]); mesh.Positions.Add(positions[quad[1]]); mesh.Positions.Add(positions[quad[2]]); mesh.Positions.Add(positions[quad[3]]); mesh.TriangleIndices.Add(indexOffset); mesh.TriangleIndices.Add(indexOffset+1); mesh.TriangleIndices.Add(indexOffset+2); mesh.TriangleIndices.Add(indexOffset+2); mesh.TriangleIndices.Add(indexOffset+3); mesh.TriangleIndices.Add(indexOffset); double centroidX = quad.Select(v => mesh.Positions[v].X).Sum() / 4.0; double centroidY = quad.Select(v => mesh.Positions[v].Y).Sum() / 4.0; double centroidZ = quad.Select(v => mesh.Positions[v].Z).Sum() / 4.0; Vector3D normal = new Vector3D( centroidX - cubeCenter.X, centroidY - cubeCenter.Y, centroidZ - cubeCenter.Z); for (int i = 0; i < 4; i++) { mesh.Normals.Add(normal); } } Material material = new DiffuseMaterial(new System.Windows.Media.SolidColorBrush(color)); GeometryModel3D model = new GeometryModel3D(mesh, material); ModelVisual3D visual = new ModelVisual3D(); visual.Content = model; return visual; } private void Button_Click(object sender, RoutedEventArgs e) { int[,] map = CreateRandomHeightMap(); int[,] normalizedMap = (Normalized(map, ColorsByHeight.Count-1)); ShowTopView(normalizedMap); Show3DView(normalizedMap); ToBitmap(Normalized(map, 255)).Save("heightmap-original.png"); ToBitmap(Normalized(normalizedMap, 255)).Save("heightmap.png"); ToColorcodedBitmap(normalizedMap).Save("terrainmap.png"); } private void ViewPort_MouseWheel(object sender, MouseWheelEventArgs e) { // Zoom in or out Camera.Width -= (double)e.Delta / 100; } private void Window_KeyUp(object sender, KeyEventArgs e) { // Scrolling by moving the 3D camera double x = 0; double y = 0; if (e.Key == Key.Left) { x = +10; y = -10; } else if (e.Key == Key.Up) { x = -10; y = -10; } else if (e.Key == Key.Right) { x = -10; y = +10; } else if (e.Key == Key.Down) { x = +10; y = +10; } Point3D cameraPosition = new Point3D( Camera.Position.X + x, Camera.Position.Y + y, Camera.Position.Z); Camera.Position = cameraPosition; } } }  • Neat, but it might look better when you 'discretize' to include more buckets. Maybe only one or two more groupings? (Not necessary by any means! Still +1 from me.) – Gaffi Mar 5 '14 at 16:37 • @Gaffi I have added more results, including more mountainous ones – Sebastian Negraszus Mar 7 '14 at 11:23 JavaScript and Crafty.JS, to be much improved Here's a sample output: And here's the code (full webpage): <!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script> <script type="text/javascript" src="http://craftyjs.com/release/0.4.2/crafty-min.js"></script> <script type="text/javascript">$(document).ready(function() {
Crafty.init();

var tilesize = 20
Crafty.sprite(20, "sprite.png#UPDATE", {
grass1: [0,0,1,3],
grass2: [1,0,1,3],
grass3: [2,0,1,3],
stone1: [3,0,1,3],
stone2: [4,0,1,3]
});

genTerrainInit()
while(1) {
try { stepTerrainGen() }
catch(e) { break }
}

iso = Crafty.isometric.init(20);
var z = 0;
for(var i = tdata.length - 1; i >= 0; i--) {
for(var y = 0; y < tdata[i].length; y++) {
var which = Math.max(0, Math.round(tdata[i][y]))
var tile = Crafty.e("2D, DOM, "+["grass1", "grass2", "grass3", "stone1", "stone2"][which])
.attr('z',i+1 * y+1)

iso.place(i,y,0, tile);
}
}

if(e.button > 1) return;
var base = {x: e.clientX, y: e.clientY};

function scroll(e) {
var dx = base.x - e.clientX,
dy = base.y - e.clientY;
base = {x: e.clientX, y: e.clientY};
Crafty.viewport.x -= dx;
Crafty.viewport.y -= dy;
};

Crafty.removeEvent(this, Crafty.stage.elem, "mousemove", scroll);
});
});
});

function genTerrainInit() {
//Variables
size = Math.pow(2, 6) + 1; //MUST be a power of 2 plus 1!
initHeight = 2;
rndRange = 4;
smoothSpeed = 0.5; // lower is faster

tdata = new Array(size);
toAverage = new Array(size);
for (var i = 0; i < size; i ++) {
tdata[i] = new Array(size);
toAverage[i] = new Array(size);
for (var i2 = 0; i2 < size; i2 ++) {
tdata[i][i2] = null;
toAverage[i][i2] = false;
}
}

//Generate corners
tdata[0][0] = initHeight;
tdata[size-1][0] = initHeight;
tdata[0][size-1] = initHeight;
tdata[size-1][size-1] = initHeight;
}

function stepTerrainGen() {
//The square step - for each square, take the center point and set it to the average of its corners plus a random amount
oldi = 0;
for (var i = 1; i < size; i ++) {
if (tdata[0][i] != null) {
oldi2 = 0;
for (var i2 = 1; i2 < size; i2 ++) {
if (tdata[i2][i] != null) {
pointDistance = (i - oldi)/2;
tdata[(oldi2 + i2)/2][(oldi + i)/2] =
((tdata[oldi2][oldi] + tdata[i2][oldi] + tdata[oldi2][i] + tdata[i2][i])/4) // average of 4 corners
+ Math.random() * rndRange - (rndRange/2.0);                                // plus a random amount

// Now mark the squares for the diamond step
toAverage[(oldi2 + i2)/2][oldi] = true;
toAverage[oldi2][(oldi + i)/2] = true;
toAverage[(oldi2 + i2)/2][i] = true;
toAverage[i2][(oldi + i)/2] = true;
oldi2 = i2;
}
}
oldi = i;
}
}

//The diamond step - same as the square step but with newly formed diamonds
for (var i = 0; i < size; i ++) {
for (var i2 = 0; i2 < size; i2 ++) {
if (toAverage[i][i2]) {
diamondArray = [];
if (i-pointDistance >= 0) diamondArray = diamondArray.concat(tdata[i-pointDistance][i2]);
if (i+pointDistance < size) diamondArray = diamondArray.concat(tdata[i+pointDistance][i2]);
if (i2-pointDistance >= 0) diamondArray = diamondArray.concat(tdata[i][i2-pointDistance]);
if (i2+pointDistance < size) diamondArray = diamondArray.concat(tdata[i][i2+pointDistance]);
for (var i3 = 0; i3 < diamondArray.length; i3 ++) addedPoints += diamondArray[i3];
tdata[i][i2] = addedPoints/diamondArray.length + Math.floor(Math.random() * rndRange - (rndRange/2.0));
}
}
}
rndRange *= smoothSpeed;
resetToAverage();
}

function resetToAverage() {
for (var i = 0; i < size; i ++) {
for (var i2 = 0; i2 < size; i2 ++) {
toAverage[i][i2] = false;
}
}
}

</script>
<title>Iso</title>
<style>
body, html { margin:0; padding: 0; overflow:hidden }
</style>
<body>
</body>
</html>


Here is sprite.png:

Now, I have a few things to say.

1. Don't judge me for that terrible code! :P I wrote it many years ago when I was a terrible programming. In fact, it's from the old days of the website I had that I didn't even remember I had! http://oddllama.cu.cc/terrain/

2. I kind of sort of copied lots of code from the Crafty.JS Isometric demo. :P

3. Explanation will come soon! I have to go to sleep now since it's late here. (That's also why the sprite is so terrible!)

Basically, it's really unpolished and it will be vastly improved later!

It uses the same diamond-square algorithm mentioned in the OP's answer.

• Can we borrow those sprites for use in other languages? – PyRulez Mar 3 '14 at 14:08
• @PyRulez Well, I, uh, kind of stole them (and edited them) from the Crafty.JS site, so I have no idea :P maybe I should have mentioned that – Doorknob Mar 3 '14 at 21:47

Ruby + RMagick

I'm using the Diamond-Square algorithm to generate the heightmap.

The algorithm in short:

• Use a wrapping array matrix, with a size of 2^n
• Wrapping means that any index outside of the bounds wrap around, e.g. if the array's size is 4 [0,0] == [4,0] == [0,4] == [4,4]. Also [-2,0] == [2,0], etc.
• Set [0,0] to a random color
• Follow the steps shown in the image.

• Note, that since the array wraps around, when you have to index something outside of the bounds, you can use the data from the other side of the array.
• Also note, that in the very first step the four corners mean exactly the same value (as [0,0] == [4,0] == [0,4] == [4,4])
• To calculate the value of the black dot, you have to average the four points surrounding it
• As this will result in a boring, gray image, you have to add a random number to this value at each step. It is preferred that this random value spans the whole range at the first iteration, but decreases over time when you are addressing smaller and smaller subsets of the array. The less this randomness decreases over time, the more noisy the image will be.

• After I'm done I'm simply assigning a color for each height value.

Code:

generate.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)

class Numeric
def clamp min, max
[[self, max].min, min].max
end
end

class WrappedArray
def initialize(size)
@size = size
@points = Array.new(size){Array.new(SIZE)}
end
def [](y,x)
@points[(@size+y) % @size][(@size+x) % @size]
end
def []=(y,x,value)
@points[(@size+y) % @size][(@size+x) % @size] = value.clamp(0,@size*@size-1)
end
end

SIZE = 256
MAXHEIGHT = 256*256

points = WrappedArray.new(SIZE)

points[0,0] = 0

s = SIZE
d = []
sq = []
r = MAXHEIGHT
while s>1
(0...SIZE).step(s) do |x|
(0...SIZE).step(s) do |y|
d << [y,x]
end
end
while !d.empty?
y,x = *d.shift
mx = x+s/2
my = y+s/2

points[my,mx]  = (points[y,x]   + points[y,x+s]      + points[y+s,x] + points[y+s,x+s])/4 + rand(r)-r/2
sq << [my,x]
sq << [my,x+s]
sq << [y,mx]
sq << [y+s,mx]
end
while !sq.empty?
y,x = *sq.shift
points[y,x]    = (points[y-s/2,x] + points[y+s/2,x] + points[y,x-s/2] + points[y,x+s/2])/4 + rand(r)-r/2
end
s = s / 2
r = r * 2 / 3
end

def get_color(height)
val = height.to_f/MAXHEIGHT*3-1
r = 0
g = 0
b = 0
if val<=-0.25
Magick::Pixel.new(0,0,128*256)
elsif val<=0
Magick::Pixel.new(0,0,255*256)
elsif val<=0.0625
Magick::Pixel.new(0,128*256,255*256)
elsif val<=0.1250
Magick::Pixel.new(240*256,240*256,64*256)
elsif val<=0.3750
Magick::Pixel.new(32*256,160*256,0)
elsif val<=0.7500
Magick::Pixel.new(224*256,224*256,0)
else
Magick::Pixel.new(128*256,128*256,128*256)
end
end

canvas = Magick::ImageList.new
canvas.new_image(SIZE+1, SIZE+1)
0.upto(SIZE) do |y|
0.upto(SIZE) do |x|
canvas.pixel_color(x,y,get_color(points[y,x]))
end
end
canvas.write('result.png')


Gemfile

source "https://rubygems.org"
gem 'rmagick'


Note: The Imagemagick I'm using is 16bit

Result image:

Note: this image is a top-down, isometric representation, where the size of one voxel is exactly one pixel, so it's valid according to the rules (except one: that my answer is not considered valid)

• Is the quality of your one-pixel top-down isometric solution meant as an indicator of the seriousness with which you wish people to approach your question? – Jonathan Van Matre Feb 28 '14 at 20:07
• I don't think top down counts as isometric? en.wikipedia.org/wiki/Isometric_projection – mattnewport Feb 28 '14 at 20:55
• @JonathanVanMatre: In the question I showed the desired result. In the answer I showed the minimum you should do for the answer to be valid. As this is a popularity-contest you can choose what you want to do, but of course you should thrive to do the desired result. – SztupY Feb 28 '14 at 21:18
• @mattnewport: good point, I was mistakenly using it for all kinds of paralell projections. Fixed. – SztupY Feb 28 '14 at 21:19

Java (using @fejesjoco's color-image as base algorithm)

After playing a bit around with the FullRGB color images from @fejesjoco i noticed that they could be used as a base for interesting cliffy voxel landscapes. Instead of reimplementing the algorithm i used his code as a external executable (download it from http://joco.name/2014/03/02/all-rgb-colors-in-one-image/ and place it named as artgen.exe in same directory )

Preview:

heightmap used (stored in blue channel)

Input image:

The subalgorithm i use from it works in that way:
1. Sorting
3. Until all colors are used: place the current color at the closest fitting spot and add the unused neighbors as new usable spots When it finished i mangle it to get it reduced to 256 different values red&(green|blue) 4. then i use pregenerated sprites and generate the image layer by layer

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

/**
*
* @author LH
*/
public class Voxelizer2
{
static final String zipembeddedsprites =
"UEsDBAoAAAAAAJy4Y0RIepnubQEAAG0BAAAJAAAAZ3Jhc3MucG5niVBORw0KGgoAAAANSUhEUgAAABgAAA"+
"AB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAA0UlEQVRIx9XVsRHCMAyFYYnLBsksWSD0jMFsnBv"+
"oYQG28AAUqVOIJvZdZMSTwRS8isL83wUOzCJCnvGFNwflIOx6HwJ0WA9BJoDCXqgAasMIysC3YQtiOlPTsF5H9/XV2LgcEpDW"+
"Cgr6CfQ+hYL1EVnzQgH80Ka+FyKi2/Hx/uRYF55O3RZIg1D0hYsn0DOh6AtDwISiL+wGCij6wtVA3jxXHd/Rj/f/QP673g+Dt"+
"PwOrsvCLy8cCAEgheGVaUIGoMPuS7+AFGCF3UABrQAKpz0BwAN2ISfnFZcAAAAASUVORK5CYIJQSwMECgAAAAAAwbhjRGZ6lp"+
"AAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeAwMWBgGIA0oTAAAAHWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNU"+
"GQuZQcAAACvSURBVEjH7dXBDcMgDIVhU3U2luDAVGwASzAASzAMPURGqhPrmYbe4mNE/k9BCrgxBlmmlPK1MITgLO85BMiwHASpA"+
"ApboROwGkbQBO6GNcjlnLeG5bxrrURE5L3fGk4pHQA/2AVxeH6BXPArJMMqsAppYQggCIXNgIR670tb96I/zwM8wP2Zx3WM0XSqWv"+
"+D1pq7vHAQhAAOwytTgzRAhs2XvoQkoIXNgIQYQGGeD4QxdHmEfUlXAAAAAElFTkSuQmCCUEsDBAoAAAAAAEl9Y0Q2U8gdJwEAACcBA"+
"AAALEwEAmpwYAAAAB3RJTUUH3gMDDioRvrDDEQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAi0lEQV"+
"RIx+2VQQ6AMAgEwd/Kg/juerEaUQJt8dY515nUJsAAKAMzPQ4CxKnvooAVW6KQG4jE2dAr0CuOQldgVuyFmAil4tcvItrPgBarxQYaW"+
"ABABgAjxW2wyw3zwGyVc6t7jbPAbJVzq3uNs8BUEsBAj8ACgAAAAAASX1jRDZTyB0nAQAAJwEAAAkAJAAAAAAAAAAgAAAABgMAAHdhdG"+
public static void main(String[] args) throws Exception
{
//embedded zip idea borrowed from over here:
//http://codegolf.stackexchange.com/a/22262/10801

//algorithm and embedded executable borrowed from
//http://joco.name/2014/03/02/all-rgb-colors-in-one-image/

//256 8192 2048 4096 1024 1000 9263 11111111 hue-0 one
/**/
ProcessBuilder p = new ProcessBuilder("artgen","64","512","512","256","256","1",((int)(Math.random()*(2<<32)))+"","11111111","hue-0","one");
Process po = p.start();
while(!xl.startsWith("Press ENTER to exit"))
{
System.out.println(xl);
}
System.out.println(xl);
po.destroy();/**/
BufferedImage heightmap = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < source.getWidth(); i++)
{
for (int j = 0; j < source.getHeight(); j++)
{
int basecolor=source.getRGB(i, j)&0x00FFFFFF;
int r = (basecolor&0x00FF0000)>>16;
int g = (basecolor&0x0000FF00)>>8;
int b = (basecolor&0x000000FF);
int color = r&(g|b);//Math.max(r,Math.max(g,b));
heightmap.setRGB(i, j, color);

}
}/**/
ImageIO.write(heightmap, "png", new File("heightmap.png"));

//generate sizedata for Sprites....

ZipInputStream zippedSprites = new ZipInputStream(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(zipembeddedsprites)));
ZipEntry z = zippedSprites.getNextEntry();
BufferedImage water=null,grass=null,stone=null,air = new BufferedImage(24,24, BufferedImage.TYPE_INT_ARGB);
while(z!=null)
{
String name = z.getName();
switch(name)
{
case "water.png":
System.out.println("water");
break;
case "stone.png":
System.out.println("stone");
break;
case "grass.png":
System.out.println("grass");
break;
}
z=zippedSprites.getNextEntry();
}

//int height = heightmap.getHeight()*12+12;
int width16 = heightmap.getWidth()/16;
int height16=heightmap.getHeight()/16;
int widthtemp1 = 384+(height16-1)*(384/2);
int width = (width16-1)*(384/2)+widthtemp1;
//int heightt1=height16*(12*16)+12*16;
int height = (width16-1)*(12*16)+(12*16);
System.out.println(width*height);
//if(true)return;

int StartPos =heightmap.getHeight()*12;

//BufferedImage[] layers = new BufferedImage[256];

BufferedImage complete = new BufferedImage(width, height+(255*12), BufferedImage.TYPE_INT_ARGB);
int mergeOffset=255*12;
for (int i = 0; i < 256; i++)
{
System.out.println("Rendering layer"+i);
BufferedImage layer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int basePointerX = StartPos-12;
int basePointerY=0;
Graphics g = layer.getGraphics();
for (int k = 0; k < heightmap.getHeight(); k++)
{
//System.out.println("Processing line"+k);
int pointerX = basePointerX;
int pointerY = basePointerY;
for (int j = 0; j < heightmap.getWidth(); j++)
{

Image tile = air;
int pxheight =heightmap.getRGB(j, k)&0x00FFFFFF;
if(pxheight>i)
{
tile=stone;
}
if(pxheight==i)
{
if(i<64)
{
tile=stone;
}
else
{
tile=grass;
}
}
if(pxheight<i)
{
if(i<64)
{
tile=water;
}
else
{
tile=air;
}
}
g.drawImage(tile, pointerX, pointerY, null);
pointerX+=12;
pointerY+=6;
}

basePointerX-=12;
basePointerY+=6;

}

//

complete.getGraphics().drawImage(layer, 0, mergeOffset, null);

mergeOffset-=12;
}
ImageIO.write(complete, "png", new File("landscape.png"));
}
}


HTML + JavaScript

Here is my attempt at the competition:

<html>
<script type='text/javascript' language='JavaScript'>
function create() {
var con = document.getElementById("can").getContext("2d"),
map = new Array(),
p = new Array(15 + Math.floor(Math.random() * 10)),
tc = ["#000040", "#000070", "#0000a0", "#5050ff", "#f0f000", "#007000", "#00aa00", "#00c000", "#00e000", "#00ff00", "#90ff90", "#a0ffa0", "#c0ffc0", "#e0ffe0", "#f0fff0"],
sc = ["#000020", "#000050", "#000085", "#3030df", "#d0d000", "#005000", "#008000", "#008000", "#00b500", "#00d000", "#00ea00", "#80ff80", "#a0ffa0", "#c0ffc0", "#d0ffd0"];
for (var n = 0; n < p.length; n++) {
p[n] = [15 + Math.floor(Math.random() * 70), 15 + Math.floor(Math.random() * 70)];
}
for (var x = 0; x < 100; x++) {
map[x] = new Array();
for (var y = 0; y < 100; y++) {
map[x][y] = 0;
for (var n = 0; n < p.length; n++) {
if (20 - Math.sqrt(Math.pow(x - p[n][0], 2) + Math.pow(y - p[n][1], 2)) > map[x][y]) {
map[x][y] = 20 - Math.sqrt(Math.pow(x - p[n][0], 2) + Math.pow(y - p[n][2], 2));
}
}
}
}
for (var x = 0; x < 100; x++) {
for (var y = 0; y < 100; y++) {
if (map[x][y] < 0) {
map[x][y] = 0;
}
map[x][y] = Math.floor(map[x][y] / 2);
con.fillStyle = tc[map[x][y]];
con.fillRect(x * 10, y * 10 - map[x][y] * 4, 10, 10);
con.fillStyle = sc[map[x][y]];
con.fillRect(x * 10, y * 10 - map[x][y] * 4 + 10, 10, map[x][y] * 4);
}
}
}
</script>
<body>
<canvas id='can' width='1000' height='1000' style='border: 1px solid #000000;'></canvas>
<button onclick='create();'>Create</button>
</body>
</html>


I use the Euclidean F1 Cell Noise algorithm to generate a heightmap which I then transform into an image by taking the appropriate colour from an array and drawing a square at 10x,10y-height so higher pixels are raised up. I then draw a rectangle as the side using the same colour from a different array.

Here is the same code using a 10,000-step random walk algorithm:

<html>
<script type='text/javascript' language='JavaScript'>
function create() {
var con = document.getElementById("can").getContext("2d"),
map = new Array(),
l = 10000,
tc = ["#000040", "#000070", "#0000a0", "#5050ff", "#f0f000", "#007000", "#00aa00", "#00c000", "#00e000", "#00ff00", "#90ff90", "#a0ffa0", "#c0ffc0", "#e0ffe0", "#f0fff0"],
sc = ["#000020", "#000050", "#000085", "#3030df", "#d0d000", "#005000", "#008000", "#008000", "#00b500", "#00d000", "#00ea00", "#80ff80", "#a0ffa0", "#c0ffc0", "#d0ffd0"];
for (var x = 0; x < 100; x++) {
map[x] = new Array();
for (var y = 0; y < 100; y++) {
map[x][y] = 0;
}
}
x = 49;
y = 49;
for (var n = 0; n < l; n++) {
var d = Math.floor(Math.random() * 4);
if (d == 0) {
x++
}
else if (d == 1) {
y++
}
else if (d == 2) {
x--
}
else if (d == 3) {
y--
}
map[(x % 100 + 100) % 100][(y % 100 + 100) % 100]++;
}
for (var x = 0; x < 100; x++) {
for (var y = 0; y < 100; y++) {
if (map[x][y] < 0) {
map[x][y] = 0;
}
map[x][y] = Math.floor(map[x][y] / 2);
con.fillStyle = tc[map[x][y]];
con.fillRect(x * 10, y * 10 - map[x][y] * 4, 10, 10);
con.fillStyle = sc[map[x][y]];
con.fillRect(x * 10, y * 10 - map[x][y] * 4 + 10, 10, map[x][y] * 4);
}
}
}
</script>