1

I am trying rewrite code from JS to Java. The code is Diamond square algorithm.

Source is: http://www.playfuljs.com/realistic-terrain-in-130-lines/

I rewrite code, but my code not working...

Output is bad.

My code in Java is:

public class MapGenerator {

    public static void main(String[] args) {
        MapGenerator mg = new MapGenerator(9);
        mg.generate();
        mg.printMap();
    }

    private int size, max;
    double[] map;
    int[][] matrix;

    public MapGenerator(int detail) {
        this.size = (int) Math.pow(2, detail) + 1;
        this.max = this.size - 1;
        this.map = new double[this.size * this.size];
    }

    private double get(int x, int y) {
        if (x < 0 || x > this.max || y < 0 || y > this.max) {
            return -1;
        }
        return this.map[x + this.size * y];
    }

    private void set(int x, int y, double val) {
        this.map[x + this.size * y] = val;
    }

    public void generate() {
        set(0, 0, max);
        set(this.max, 0, max / 2);
        set(this.max, this.max, 0);
        set(0, this.max, max / 2);
        divide(this.max);

        buildMatrix();
        saveTerrain(0, 0, 0, 0, matrix, "vystup.ter");
    }

    private void buildMatrix() {
        matrix = new int[size][size];

        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                matrix[i][j] = (int) map[i + j];
            }
        }

    }

    private void divide(int size) {
        //? 
        double roughness = 0.7;

        int x, y, half = size / 2;
        double scale = roughness * size;

        if (half < 1) {
            return;
        }
        for (y = half; y < max; y += size) {
            for (x = half; x < max; x += size) {
                square(x, y, half, Library.randInt(0, 100) * scale * 2 - scale);
            }
        }
        for (y = 0; y <= max; y += half) {
            for (x = (y + half) % size; x <= max; x += size) {
                diamond(x, y, half, Library.randInt(0, 100) * scale * 2 - scale);
            }
        }
        divide(size / 2);
    }

    private void square(int x, int y, int size, double offset) {

        double tmp_1 = get(x, y - size);   // top
        double tmp_2 = get(x + size, y);      // right
        double tmp_3 = get(x, y + size);     // bottom
        double tmp_4 = get(x - size, y);       // left

        set(x, y, ((tmp_1 + tmp_2 + tmp_3 + tmp_4) / 4.0) + offset);
    }

    private void diamond(int x, int y, int size, double offset) {
        double tmp_1 = get(x, y - size);      // top
        double tmp_2 = get(x + size, y);      // right
        double tmp_3 = get(x, y + size);      // bottom
        double tmp_4 = get(x - size, y);      // left

        set(x, y, ((tmp_1 + tmp_2 + tmp_3 + tmp_4) / 4.0) + offset);
    }

    public void printMap() {
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println("");
        }
    }

    public void saveTerrain(int canonX, int canonY, int targetX, int targetY,
            int[][] terrain, String fName) {
        int height = terrain.length;
        int width = terrain[0].length;

        DataOutputStream fout = null;
        try {
            // Samotný zápis dat
            fout = new DataOutputStream(new FileOutputStream(fName));

            fout.writeInt(width);
            fout.writeInt(height);
            fout.writeInt(canonX);
            fout.writeInt(canonY);
            fout.writeInt(targetX);
            fout.writeInt(targetY);

            for (int y = 0; y < height; ++y) {
                for (int x = 0; x < width; ++x) {
                    fout.writeInt(terrain[y][x]);
                }
            }
        } /*
         * Následuje pouze zavření souboru a ošetrení výjimek
         */ catch (FileNotFoundException e) {
            System.err.println("Nepovedlo se otevrit vystupni soubor.");
        } catch (IOException e) {
            System.err.println("Nepovedlo se zapsat vystupni soubor.");
        } finally {
            try {
                if (fout != null) {
                    fout.close();
                }
            } catch (IOException e) {
                System.err.println("Nepovedlo se uzavrit vystupni soubor.");
            }
        }
    }
}

Can anyone help me?

Output of algo is int[][] which i visualise using another program to image..

Visualise of output:

OUTPUT IMAGE LINK

And this is how it should look

OUTPUT IMAGE LINK

I am not getting error, but the output is wrong. Thanks for help.

Spektre
  • 49,595
  • 11
  • 110
  • 380
drefraew
  • 21
  • 3
  • Are you getting any compilation errors? What is the expected output and what you are getting? Include everything in your question. Nobody will debug 100s of lines of code just to understand what it is suppose to do. – user2004685 Mar 27 '16 at 10:57
  • I am not getting error, but the output is wrong – drefraew Mar 27 '16 at 11:00
  • Can you give us the expected and actual output? – Benjamin Lowry Mar 27 '16 at 11:03
  • Expected output is: [http://i.stack.imgur.com/po8b4.png](http://i.stack.imgur.com/po8b4.png) and real output of my algo is in question. – drefraew Mar 27 '16 at 11:08
  • @Spektre I test with resolution 513x513 but still same problem. – drefraew Mar 28 '16 at 07:48
  • Finished editing of answer you can try to use/port my approach to compare what is wrong with yours. You can also debug yours by setting specific color instead avg+random and stop at certain recursion layer so you see if diamond or square do what they should especially near corners. – Spektre Mar 28 '16 at 09:01
  • see [simple island map generator in C++](http://stackoverflow.com/a/36647622/2521214) was tweaking the code a bit there (especially randomness,added features,island like output). – Spektre Apr 15 '16 at 13:11

1 Answers1

0

I was coding this same thing yesterday (from the same source) and the recursive approach is really tricky due to square step overlaps of the subdivided areas and the irregularities in the same step. So I decided to do this from scratch the iterative way (which is much faster due to no heap/stack trashing in my programing environment) as you can see I am down from 130 lines to around 50 with comments.

This is how I do it (non recursively) in C++:

void diamond_square(int size)
    {
    picture pic;
    int x,y,xx,yy,xs,ys,d,d2,r;
    for (xs=1;xs<size;xs<<=1); xs>>=1; ys=xs;   // align  to power of 2
    pic.resize(xs+1,ys+1); pic.pf=_pf_u;        // resize image to power of 2 +1
    d=xs; d2=d>>1; r=128;                       // init step,half step and randomness
    Randomize();
    pic.p[ 0][ 0].dd=r;                         // set corners values (should be random but I want this)
    pic.p[ 0][xs].dd=r;
    pic.p[ys][ 0].dd=r;
    pic.p[ys][xs].dd=r;
    for (;d2;d=d2,d2>>=1)                       // subdivide step until full image is filled
        {
        // diamond
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
         for (x=d2,xx=xs-d2;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y-d2][x-d2].dd+pic.p[y-d2][x+d2].dd+pic.p[y+d2][x-d2].dd+pic.p[y+d2][x+d2].dd)>>2)+Random(r);
        // square
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
         for (x=d ,xx=xs-d ;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)>>2)+Random(r);
        for (y=d ,yy=ys-d ;y<=yy;y+=d)
         for (x=d2,xx=xs-d2;x<=xx;x+=d)
          pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)>>2)+Random(r);
        for (x=d2,xx=xs-d2;x<=xx;x+=d)
            {
            y= 0; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            y=ys; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y][x+d2].dd+pic.p[y-d2][x].dd)/3)+Random(r);
            }
        for (y=d2,yy=ys-d2;y<=yy;y+=d)
            {
            x= 0; pic.p[y][x].dd=((pic.p[y][x+d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            x=xs; pic.p[y][x].dd=((pic.p[y][x-d2].dd+pic.p[y-d2][x].dd+pic.p[y+d2][x].dd)/3)+Random(r);
            }
        // adjust randomness
        r=(r*220)>>8; if (r<2) r=2;
        }
    // here pic holds the terrain map
    }

I use my own picture class so here some members:

  • resize(xs,ys) resize image to new resolution
  • p[ys][xs].dd is pixel access in form of 32 unsigned ints DWORD
  • pf is pixel format (you can ignore this)

This is the result for diamond_square(513);

example

You can play with the r randomnes initial and adjustment values to change behavior. Also you can change the initial corner values.

Beware the local int xs,ys variables in my program holds the power of 2 values not the power of 2 +1 !!!

Spektre
  • 49,595
  • 11
  • 110
  • 380