pequeño algoritmo de diamante cuadrado


12

El algoritmo de diamante cuadrado es un algoritmo generador de terreno fractal (mapa de altura). Puede encontrar una buena descripción de cómo funciona aquí:

http://www.gameprogrammer.com/fractal.html (Usado como referencia).

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Gran implementación de JS, tal vez quieras robar su procesador. Mira aquí lo que este algoritmo es capaz de hacer en http: // demos. playfuljs.com/terrain/ .)

La idea general es que tiene 4 esquinas como semillas (a), y calcule la altura del punto central promediando esas cuatro esquinas y agregando un valor aleatorio, por ejemplo, entre -0.5 y 0.5 (b). Si aplica esto a la cuadrícula, obtiene nuevamente una cuadrícula de diamantes (cuadrados hasta 45 °) y repite lo mismo (c, d), pero el rango aleatorio se vuelve más pequeño, por ejemplo, -0.125 a 0.125, etc. ingrese la descripción de la imagen aquí

Su programa debe aceptar una cantidad de entradas:

  • Un entero l=1,2,3,...que determina el tamaño de la cuadrícula cuadrada con la longitud del lado 2^l+1. En l=10tendrá que almacenar alrededor de un millón de números.
  • Cuatro semillas (punto flotante) para cada esquina
  • Un parámetro 0<h<1que determina la rugosidad ( Hen el enlace) que significa qué tan grande es inicialmente el rango aleatorio
  • Parámetros a,bque representan los límites inferior y superior iniciales para el rango aleatorio y se multiplican por hcada paso de refinamiento. (El número aleatorio se elige uniformemente entre ay b.

La salida debe consistir en la cuadrícula 2D terminada.

Entonces el algoritmo aproximado se vería así:

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

Hay un detalle que debe tener en cuenta: en el límite de la cuadrícula, solo tendrá tres vértices del diamante , por lo que también debe calcular el promedio de esos tres puntos.

La visualización de algunos ejemplos (por favor díganos qué parámetros utilizó) es opcional pero apreciada y, por supuesto, no se suma al recuento de bytes.

Aquí se puede encontrar una implementación ligeramente variada de este algoritmo: generador de terreno voxel proyectado en paralelo

Creé una pequeña función de dibujo en javascript para desplazar mapas de altura en 2d como imagen en escala de grises. http://jsfiddle.net/flawr/oy9kxpsx/

Si alguno de ustedes está en 3D sofisticado y puede hacer un script para ver mapas en 3D, ¡hágamelo saber! =)

Respuestas:


8

Java, 1017 bytes

Entrada es una lista separada por espacios de esta manera: l s1 s2 s3 s4 h a b.

La salida es una matriz 2d que contiene los números.

Programa:

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;}}

Programa que está sangrado y muestra el mapa:

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);
    }

}

Aquí hay una función en Java para mostrar un mapa:

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);
}

Todas estas imágenes tienen un tamaño de 7. Las 4 semillas son 5, 10, 15, y 20.

ay bson -10y 10respectivamente.

La aspereza comienza .1e incrementa en .1hasta 1.

UnoDosTresCuatroCincoSeisSieteOchoNueveDiez

Código generador de terreno próximamente !!!

¡¡¡Imágenes próximamente !!!


¡Muchas gracias! ¿Quizás podría proporcionar una clase sobre eso con todas las importaciones necesarias para que no se necesite una gran modificación? ¡Que sería increíble!
flawr

@flawr Estoy trabajando en eso.
TheNumberOne

Acabo de hacerlo funcionar, si sabes cómo hacerlo, sería genial si pudieras hacer que la ventana se muestre "sin colapsar". Al menos en mi máquina tienes que abrirlo cada vez que lo inicias. Así es como
completé

¡Esto se ve increíble! Me gusta especialmente la forma elegante en la que estás tratando con los límites donde falta un vértice =)
error

@flawr La ventana no se colapsará cuando la abras ahora.
TheNumberOne
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.