алгоритм крошечного алмазного квадрата


12

Алмазный квадратный алгоритм - это алгоритм генерации фрактальной местности (карты высот). Вы можете найти хорошее описание того, как это работает здесь:

http://www.gameprogrammer.com/fractal.html (используется в качестве ссылки.)

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Отличная реализация JS, возможно, вы захотите украсть его средство визуализации. Посмотрите здесь, на что этот алгоритм способен http: // demos. playfuljs.com/terrain/ .)

Общая идея состоит в том, что у вас есть 4 угла в качестве начальных значений (a), и вы рассчитываете высоту центральной точки, усредняя эти четыре угла и добавляя случайное значение, например, между -0,5 и 0,5 (b). Если вы примените это к сетке, вы снова получите сетку алмазов (квадраты под углом 45 °), и вы повторите то же самое (c, d), но случайный диапазон станет меньше, например, от -0,125 до 0,125 и т. Д. введите описание изображения здесь

Ваша программа должна принимать несколько входов:

  • Целое число, l=1,2,3,...которое определяет размер квадратной сетки с длиной стороны 2^l+1. У l=10вас будет храниться около миллиона номеров.
  • Четыре семени (с плавающей точкой) для каждого угла
  • Параметр, 0<h<1который определяет шероховатость ( Hв ссылке), которая означает, насколько большой случайный диапазон изначально
  • Параметры, a,bкоторые представляют начальные нижнюю и верхнюю границы для случайного диапазона и умножаются на hкаждый шаг уточнения. (Случайное число равномерно выбирается между aи b.

Вывод должен состоять из готовой двумерной сетки.

Таким образом, грубый алгоритм будет выглядеть так:

Create a square grid with sidelength 2^l+1
Place seed values in the corners
Repeat:
  |  Perform square steps
  |  Refine Range: a = a*h; b=b*h;
  |  Perform diamond steps
  |  Refine Range

Есть одна деталь, о которой вы должны знать: на границе сетки у вас будет только три вершины алмаза , поэтому вам также следует рассчитать только среднее значение этих трех точек.

Визуализация некоторых примеров (пожалуйста, сообщите нам, какие параметры вы использовали) не является обязательной, но приветствуется и, конечно, не увеличивает количество байтов.

Небольшая вариация реализации этого алгоритма может быть найдена здесь: Параллельно-спроектированный воксельный генератор местности

Я создал небольшую функцию рисования в javascript для перемещения карт высот в 2d как изображение в градациях серого. http://jsfiddle.net/flawr/oy9kxpsx/

Если кто-то из вас увлекается 3d и может создать скрипт для просмотра карт в 3d, дайте мне знать! =)

Ответы:


8

Java, 1017 байт

Ввод разделенных пробелов списка следующим образом: l s1 s2 s3 s4 h a b.

Выход - это 2d-массив, содержащий числа.

Программа:

import java.util.*;import static java.lang.Math.*;class C{public static void main(String[]a){int b=a.length,d=0;float[]c=new float[b];for(;d<b;){c[d]=Float.parseFloat(a[d++]);}e=(int)(pow(2,c[0])+1);f=new float[e][e];f[0][0]=c[1];f[0][e-1]=c[2];f[e-1][0]=c[3];f[e-1][e-1]=c[4];g=c[5];float h=c[6],i=c[7];s(0,0,e-1,e-1,h,i);System.out.print(Arrays.deepToString(f));}static int e;static float[][]f;static float g;static void s(int q,int r,int s,int t,float h,float i){if(s-q<2|t-r<2|q<0|r<0|s>=e|t>=e)return;float o,p;int m=(q+s)/2,n=(r+t)/2;f[m][n]=(float)(a(q,r,s,r,q,t,s,t)+random()*(i-h)-h);d(m,r,m-q,o=h*g,p=i*g);d(q,n,m-q,o,p);d(m,t,m-q,o,p);d(s,n,m-q,o,p);}static void d(int x,int y,int e,float h,float i){float o,p;f[x][y]=(float)(a(x,y-e,x+e,y,x,y+e,x-e,y)+random()*(i-h)-h);s(x-e,y-e,x,y,o=h*g,p=i*g);s(x,y-e,x+e,y,o,p);s(x-e,y,x,y+e,o,p);s(x,y,x+e,y+e,o,p);}static float a(int...j){float k=0,l=0;for(int d=0;d<j.length;d+=2){if(j[d]<0|j[d+1]<0|j[d]>=e|j[d+1]>=e)continue;l++;k+=f[j[d]][j[d+1]];}return k/l;}}

Программа с отступом и отображающая карту:

import java.util.*;
import java.awt.image.*;
import java.awt.*;
import javax.swing.*;
import static java.lang.Math.*;

class D{

    public static void main(String[]a){
        int b=a.length,d=0;
        float[]c=new float[b];
        for(;d<b;){
            c[d]=Float.parseFloat(a[d++]);
        }
        e=(int)(pow(2,c[0])+1);
        f=new float[e][e];
        f[0][0]=c[1];
        f[0][e-1]=c[2];
        f[e-1][0]=c[3];
        f[e-1][e-1]=c[4];
        g=c[5];
        float h=c[6],i=c[7];
        s(0,0,e-1,e-1,h,i);
        showImage(f);
    }

    static int e;
    static float[][]f;
    static float g;

    static void s(int q,int r,int s,int t,float h,float i){
        if(s-q<2|t-r<2|q<0|r<0|s>=e|t>=e)
            return;
        float o,p;
        int m=(q+s)/2,n=(r+t)/2;
        f[m][n]=(float)(a(q,r,s,r,q,t,s,t)+random()*(i+h)-h);
        d(m,r,m-q,o=h*g,p=i*g);
        d(q,n,m-q,o,p);
        d(m,t,m-q,o,p);
        d(s,n,m-q,o,p);
    }

    static void d(int x,int y,int e,float h,float i){
        float o,p;
        f[x][y]=(float)(a(x,y-e,x+e,y,x,y+e,x-e,y)+random()*(i-h)+h);
        s(x-e,y-e,x,y,o=h*g,p=i*g);
        s(x,y-e,x+e,y,o,p);
        s(x-e,y,x,y+e,o,p);
        s(x,y,x+e,y+e,o,p);
    }

    static float a(int...j){
        float k=0,l=0;
        for(int d=0;d<j.length;d+=2){
            if(j[d]<0|j[d+1]<0|j[d]>=e|j[d+1]>=e)
                continue;
            l++;
            k+=f[j[d]][j[d+1]];
        }
        return k/l;
    }

    public static void showImage(float[][] f){
        float maxHeight = Float.MIN_VALUE;
        float minHeight = Float.MAX_VALUE;
        for (float[] row : f){
            for (float height : row){
                if (height > maxHeight){
                    maxHeight = height;
                }
                if (height < minHeight){
                    minHeight = height;
                }
            }
        }
        int e = f.length;
        BufferedImage image = new BufferedImage(e, e, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < e; x++){
            for (int y = 0; y < e; y++){
                Color color = Color.getHSBColor((float)((f[x][y] - minHeight)/(maxHeight - minHeight)), 1, 1);
                image.setRGB(x,y,color.getRGB());
            }
        }
        JFrame frame = new JFrame("Picture");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JComponent(){

            @Override
            public void paint(Graphics g){
                g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
            }

        });
        frame.setVisible(true);
        frame.setBounds(0,0,e,e);
    }

}

Вот функция в Java, чтобы показать карту:

public static void showImage(float[][] map){
    float maxHeight = Float.MIN_VALUE;
    float minHeight = Float.MAX_VALUE;
    for (float[] row : map){
        for (float height : row){
            if (height > maxHeight){
                maxHeight = height;
            }
            if (height < minHeight){
                minHeight = height;
            }
        }
    }
    int size = map.length;
    BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < size; x++){
        for (int y = 0; y < size; y++){
            Color color = Color.getHSBColor((float)((map[x][y] - minHeight)/(maxHeight - minHeight)), 1, 1);
            image.setRGB(x,y,color.getRGB());
        }
    }
    JFrame frame = new JFrame("Picture");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new JComponent(){

        @Override
        public void paint(Graphics g){
            g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        }

    });
    frame.setVisible(true);
    frame.setBounds(0,0,size,size);
}

Все эти изображения имеют размер 7. В 4 семена 5, 10, 15, и 20.

aи bесть -10и 10соответственно.

Шероховатость начинается с .1и увеличивается .1до 1.

ОдинДваТричетыре5ШестьСемьВосемь910

Скоро появится код для генерации ландшафта !!!

Изображения скоро!


Большое спасибо! Не могли бы вы предоставить класс вокруг этого со всем необходимым импортом, так что не нужно больших изменений? Это было бы круто!
flawr

@ Flawr Я работаю над этим.
TheNumberOne

Просто сделайте так, чтобы вы работали, если вы знаете, как это сделать, было бы здорово, если бы вы могли сделать так, чтобы окно отображалось как «не свернутое». По крайней мере, на моей машине вы должны открывать ее каждый раз, когда запускаете ее. Вот как я закончил урок: pastebin.com/pRAMst4d
flawr

Это выглядит потрясающе! Мне особенно нравится элегантный способ, которым вы имеете дело с границами, где отсутствует одна вершина =)
flawr

@flawr Окно не будет свернуто, когда вы откроете его сейчас.
TheNumberOne
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.