Terrain Generator for SimCity 4
Donald Booth
7/14/2010 (edited 3/22/2013)

Notes

Notes:
* r is the roughness factor. 0.5 gives rough terrain and 2 gives smooth terrain. 
* δ is the initial amplitude of the random factor. Larger values will result in higher mountains and deeper valleys.
* seedmatrix is the intial matrix. This specifies the elevations of the four corners of the map.
* iterations gives the number of times the matrix should be expanded. A larger value will give more realistic terrain, but values at 10 or greater yield very large matrices that cause memory issues.
* bitmapsize is the size in pixels of the bitmap to create. Per http://www.sc4ever.com/knowledge/showarticle.cfm?id=1103 , "Take the size of the region in kilometers, multiply it by 64, then add 1."
* forceaverage contains two parameters. The first determines whether the elevation of the terrain should be recentered (enabled if True), and the second parameter determines what elevation to recenter to (1 is maximum, 0 minimum). The lower the second parameter is, the more water there will be. 0.35 will usually give about 50% water.
* filename is the name of the file to output the bitmap to. The file will be placed in the same directory as the notebook, unless you change the directory with the SetDirectory[] command.
* If debugmode is set to True, contour plots of the map at various intervals are displayed. Otherwise, the maps are not shown. Do not set to True if iterations is 10 or greater, or if bitmapsize is significantly larger than 100.
* If showbitmap is set to True, the bitmap generated is shown in the last section of the notebook.

Once the bitmap has been created, create a config.bmp in Paint with the appropriate dimensions, create a new region in SimCity, copy the config.bmp to that region's directory in your My Documents folder, then enter SimCity and press Ctrl+Shift+Alt+R and load your bitmap. For more information, see http://www.sc4ever.com/knowledge/showarticle.cfm?id=1103 .

To do:
* Allow generation of non-square maps

Parameters

r=1.0;
δ=0.75;
seedmatrix=Table[Random[Real],{i,1,2},{j,1,2}];
iterations=7; (*10 is too many.*)
bitmapsize=15*64+1  ;
forceaverage={True,0.5};
filename="bitmap"<>DateString[{"Year","-","Month","-","Day","_","Hour","Minute"}]<>".bmp";
debugmode=False;
showbitmap=True;
showsealevel=True;

Calculate matrix

matrix=seedmatrix;
Do[
temp=Table[If[Mod[j,2]≠0 && Mod[k,2]≠0,   (*Allocate temp and add previous values*)matrix[[(j+1)/2,(k+1)/2]],0],{j,1,2*Length[matrix]-1},{k,1,2*Length[matrix]-1}];

Do[  (*Center elements*)
Do[
a=temp[[j-1,k-1]];
b=temp[[j-1,k+1]];
c=temp[[j+1,k-1]];
d=temp[[j+1,k+1]];
temp[[j,k]]=(a+b+c+d)/4+δ*(2*Random[Real]-1);
,{j,2,Length[temp]-1,2}]
,{k,2,Length[temp]-1,2}];

Do[  (*One set of side elements*)
Do[
factor=4;
a=temp[[j,k-1]];
b=temp[[j,k+1]];
If[j≠1,c=temp[[j-1,k]],c=0;factor=3];
If[j≠Length[temp],d=temp[[j+1,k]],d=0;factor=3];
temp[[j,k]]=(a+b+c+d)/factor+δ*(2*Random[Real]-1);
,{j,1,Length[temp],2}]
,{k,2,Length[temp]-1,2}];

Do[  (*Other set of side elements*)
Do[
factor=4;
a=temp[[j+1,k]];
b=temp[[j-1,k]];
If[k≠1,c=temp[[j,k-1]],c=0;factor=3];
If[k≠Length[temp],d=temp[[j,k+1]],d=0;factor=3];
temp[[j,k]]=(a+b+c+d)/factor+δ*(2*Random[Real]-1);
,{j,2,Length[temp]-1,2}]
,{k,1,Length[temp],2}];

δ=δ*(2^(-r));
matrix=temp;
,{i,1,iterations}]

Look at matrix

If[debugmode,matrix//MatrixForm]

If[debugmode,ListContourPlot[matrix]]

Set up interpolation

listtointerp={}; average=0;
Do[
Do[
listtointerp=Append[listtointerp,{{(i-1)/(Length[matrix]-1),(j-1)/(Length[matrix]-1)},matrix[[i,j]]}];
average=average+matrix[[i,j]];
,{i,1,Length[matrix]}]
,{j,1,Length[matrix]}];
average=average/((Length[matrix])^2)
If[forceaverage[[1]],
finalaverage=0;
Do[
listtointerp[[m,2]]=listtointerp[[m,2]]+forceaverage[[2]]-average;
finalaverage=finalaverage+listtointerp[[m,2]];
,{m,1,Length[listtointerp]}];
finalaverage=finalaverage/((Length[matrix])^2)

]

interp=Interpolation[listtointerp];

If[debugmode,ContourPlot[interp[y,x],{x,0,1},{y,0,1}]]

Prepare bitmap and export

bitmap=Table[
a=interp[i/bitmapsize,j/bitmapsize];
If[a≤1,
If[a≥0,
Round[255*a],
0
]
,255
]

,{i,1,bitmapsize},{j,1,bitmapsize}];

If[debugmode,ListContourPlot[bitmap]]

bitmapimage=Image[bitmap,"Byte"];

Export[filename,bitmapimage];

Display map

If[showsealevel,colors=Join[Table[Lighter[Blue,i/5],{i,0,4}],Table[Lighter[Green,i/8],{i,0,7,1}]];ContourPlot[interp[-y,x],{x,0,1},{y,-1,0},Contours->{0,0.1,0.2,0.3,0.325,0.4,0.5,0.6,0.7,0.8,0.9,1.0},ContourShading->colors]]

If[showbitmap,colors=Join[Table[Lighter[Blue,i/5],{i,0,4}],Table[Lighter[Green,i/8],{i,0,7,1}]];ReliefPlot[bitmap,ColorFunction->"DarkTerrain",DataReversed->True]]

If[showbitmap,bitmapimage]