10

For a cellular automata project I'm working on I need to generate two dimensional boolean arrays randomly using different algorithms and techniques. At the moment I have just one type of randomization in the application - looping through every cell in the array and generating a random double variable, then if the random number is higher than 0.5 then I set that cell to true, if not it gets set to false.

I would like to look into generating these boolean matrices using more interesting algorithms such as Perlin Noise or something like that. Noise generators that are used in terrain generation or something like that might be good if you know of any other than Perlin Noise (Minecraft's world generation gave me this idea).

The only problem is I have no idea where to start (any ideas?) :)

tshepang
  • 12,111
  • 21
  • 91
  • 136
jt78
  • 906
  • 2
  • 10
  • 22

2 Answers2

11

The first thing I thought of was a random displacement fractal. It is also used to generate terrain and is easier than Perlin Noise.

package so;

import java.util.Random;

public class Noise {
    /** Source of entropy */
    private Random rand_;

    /** Amount of roughness */
    float roughness_;

    /** Plasma fractal grid */
    private float[][] grid_;


    /** Generate a noise source based upon the midpoint displacement fractal.
     * 
     * @param rand The random number generator
     * @param roughness a roughness parameter
     * @param width the width of the grid
     * @param height the height of the grid
     */
    public Noise(Random rand, float roughness, int width, int height) {
        roughness_ = roughness / width;
        grid_ = new float[width][height];
        rand_ = (rand == null) ? new Random() : rand;
    }


    public void initialise() {
        int xh = grid_.length - 1;
        int yh = grid_[0].length - 1;

        // set the corner points
        grid_[0][0] = rand_.nextFloat() - 0.5f;
        grid_[0][yh] = rand_.nextFloat() - 0.5f;
        grid_[xh][0] = rand_.nextFloat() - 0.5f;
        grid_[xh][yh] = rand_.nextFloat() - 0.5f;

        // generate the fractal
        generate(0, 0, xh, yh);
    }


    // Add a suitable amount of random displacement to a point
    private float roughen(float v, int l, int h) {
        return v + roughness_ * (float) (rand_.nextGaussian() * (h - l));
    }


    // generate the fractal
    private void generate(int xl, int yl, int xh, int yh) {
        int xm = (xl + xh) / 2;
        int ym = (yl + yh) / 2;
        if ((xl == xm) && (yl == ym)) return;

        grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]);
        grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]);
        grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]);
        grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]);

        float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh
                + xh);
        grid_[xm][ym] = v;
        grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh);
        grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh);
        grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh);
        grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh);

        generate(xl, yl, xm, ym);
        generate(xm, yl, xh, ym);
        generate(xl, ym, xm, yh);
        generate(xm, ym, xh, yh);
    }


    /**
     * Dump out as a CSV
     */
    public void printAsCSV() {
        for(int i = 0;i < grid_.length;i++) {
            for(int j = 0;j < grid_[0].length;j++) {
                System.out.print(grid_[i][j]);
                System.out.print(",");
            }
            System.out.println();
        }
    }


    /**
     * Convert to a Boolean array
     * @return the boolean array
     */
    public boolean[][] toBooleans() {
        int w = grid_.length;
        int h = grid_[0].length;
        boolean[][] ret = new boolean[w][h];
        for(int i = 0;i < w;i++) {
            for(int j = 0;j < h;j++) {
                ret[i][j] = grid_[i][j] < 0;
            }
        }
        return ret;
    }


    /** For testing */
    public static void main(String[] args) {
        Noise n = new Noise(null, 1.0f, 250, 250);
        n.initialise();
        n.printAsCSV();
    }
}

random displacement fractal plot 1 random displacement fractal plot 2 random displacement fractal plot 3

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Simon G.
  • 6,587
  • 25
  • 30
  • I altered (butchered) your source to produce a plot of the noise, with blue being lowest, & yellow highest values. There seem to be distinct lines on the image, most noticeably at the 'mid points' but to a lesser extent, each 'child' midpoint. Is there any way to reduce or eradicate those discontinuities? I could add the altered source, if anyone is interested. – Andrew Thompson Apr 05 '11 at 12:43
  • 2
    This fractal is easy to code but produces these lines. There is an improvement on it known as the diamond square fractal which is supposed to minimize these artifacts. – Simon G. Apr 05 '11 at 13:10
  • BTW I think there is also a problem with my implementation. The code sets the heights of each side midpoints twice. That makes for discontinuities. If the grid is initialized to Float.NaN and each point only set once by testing for this, I think the output will be improved. – Simon G. Apr 05 '11 at 13:22
  • Thanks, this is exactly what I was looking for. I've implemented it and is producing some interesting results. Also, for this application of the technique the lines you're mentioning really don't matter and are hardly visible because it's being used at such a low resolution and only has boolean values instead of integers. Works great, so thanks again :) – jt78 Apr 05 '11 at 17:58
  • @Andrew Thompson If any of you are interested, I've got a **very** early build of the project up at [link](http://workbench.jamesthornton.me.uk/) – jt78 Apr 05 '11 at 21:17
  • @SimonG. why do you put underscores after the names of field variables? Is this a good practice? Just wondering – Kartik Chugh Nov 28 '16 at 05:06
3

I have some perlin noise implementations and some other noise generation functions in my library code:

http://code.google.com/p/mikeralib/source/browse/#svn%2Ftrunk%2FMikera%2Fsrc%2Fmain%2Fjava%2Fmikera%2Fmath

Feel free to explore / use (code is open source GPL, based on the J3D code).

mikera
  • 105,238
  • 25
  • 256
  • 415
  • I can't seem to get anything other than negative or positive 0 floating point numbers from your perlin functions ; ` PerlinNoise perlin = new PerlinNoise(409623546); for(float x=0; x < 100; x++) { for(float y=0; y < 100; y++) { System.out.println(perlin.noise1(y)*100000); } }` – Timothy Groote Dec 20 '11 at 17:44
  • @TimothyGroote Try this, it worked for me: double grid[][] = new double[width][height]; for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { double v = 0; for(int i = 2; i <= 32; i = i * i) { double n = perlin.noise2(i * x / (float) width, i * y / (float) height); v += n / i; } grid[x][y] = v; } } – Ed_le_fou Jun 13 '12 at 16:06