algoritmo quadrado pequeno diamante


12

O algoritmo do quadrado do diamante é um algoritmo de geração de terreno fractal (mapa de altura). Você pode encontrar uma boa descrição de como funciona aqui:

http://www.gameprogrammer.com/fractal.html (Usado como referência.)

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Ótima implementação de JS, talvez você queira roubar seu renderizador. Dê uma olhada aqui do que esse algoritmo é capaz de http: // demos. playfuljs.com/terrain/ .)

A idéia geral é que você tenha 4 cantos como sementes (a) e calcule a altura do ponto central calculando a média desses quatro cantos e adicionando um valor aleatório, por exemplo, entre -0,5 e 0,5 (b). Se você aplicar isso à grade, obtém novamente uma grade de diamantes (os quadrados dobram 45 °) e repete o mesmo (c, d), mas o intervalo aleatório fica menor, por exemplo, -0,125 a 0,125 etc. insira a descrição da imagem aqui

Seu programa deve aceitar várias entradas:

  • Um número inteiro l=1,2,3,...que determina o tamanho da grade quadrada com comprimento lateral 2^l+1. Em l=10você terá que armazenar cerca de um milhão de números.
  • Quatro sementes (ponto flutuante) para cada canto
  • Um parâmetro 0<h<1que determina a rugosidade ( Hno link) que significa o tamanho inicial do intervalo aleatório
  • Parâmetros a,bque representam os limites inferior e superior iniciais para o intervalo aleatório e são multiplicados hem cada etapa de refinamento. (O número aleatório é escolhido uniformemente entre ae b.

A saída deve consistir na 2d grade finalizada.

Portanto, o algoritmo aproximado seria assim:

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

Há um detalhe que você deve estar ciente: No limite da grade, você terá apenas três vértices do diamante ; portanto, você também deve calcular apenas a média desses três pontos.

Uma visualização de alguns exemplos (por favor, diga-nos quais parâmetros você usou) é opcional, mas apreciada e, é claro, não aumenta a contagem de bytes.

Uma pequena implementação variada desse algoritmo pode ser encontrada aqui: Gerador de terreno voxel projetado em paralelo

Criei uma pequena função de desenho em javascript para exibir mapas de altura em 2D como imagem em escala de cinza. http://jsfiddle.net/flawr/oy9kxpsx/

Se alguém de vocês gosta de 3d e pode fazer um script para visualizar mapas em 3d, avise-me! =)

Respostas:


8

Java, 1017 bytes

A entrada é um espaço lista separada assim: l s1 s2 s3 s4 h a b.

A saída é uma matriz 2D que contém os 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 é recuado e exibe o 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);
    }

}

Aqui está uma função em Java para mostrar um 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 essas imagens têm tamanho de 7. Os 4 sementes são 5, 10, 15, e 20.

ae bsão -10e 10respectivamente.

A rugosidade começa em .1e aumenta em .1até 1.

1DoisTrêsQuatroCincoSeisSeteOitoNoveDez

Código gerador de terreno em breve !!!

Imagens em breve !!!


Muito obrigado! Você poderia talvez fornecer uma classe em torno disso com todas as importações necessárias para que nenhuma modificação seja necessária? Isso seria demais!
flawr

@ flawr Estou trabalhando nisso.
TheNumberOne

Apenas comecei a trabalhar, se você souber como fazê-lo, seria ótimo se você pudesse fazer a janela aparecer 'sem colapso'. Pelo menos na minha máquina, você deve abri-la toda vez que a iniciar. Aqui está como eu completei a classe: pastebin.com/pRAMst4d
flawr

Isso parece incrível! Eu gosto especialmente a maneira elegante você está lidando com os limites onde um vértice está faltando =)
flawr

@flawr A janela não será fechada quando você a abrir agora.
TheNumberOne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.