petit algorithme carré de diamant

12

L'algorithme du carré de diamant est un algorithme de génération de terrain fractal (carte de hauteur). Vous pouvez trouver une belle description de son fonctionnement ici:

http://www.gameprogrammer.com/fractal.html (utilisé comme référence.)

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Excellente implémentation JS, vous voudrez peut-être voler son moteur de rendu. Jetez un œil ici ce que cet algorithme est capable de http: // démos. playfuljs.com/terrain/ .)

L'idée générale est que vous avez 4 coins comme graines (a), et calculez la hauteur du point central en faisant la moyenne de ces quatre coins et en ajoutant une valeur aléatoire, par exemple entre -0,5 et 0,5 (b). Si vous appliquez cela à la grille, vous obtenez à nouveau une grille de diamants (carrés tournant 45 °) et vous répétez la même chose (c, d), mais la plage aléatoire devient plus petite, par exemple -0,125 à 0,125, etc. entrez la description de l'image ici

Votre programme doit accepter un certain nombre d'entrées:

  • Un entier l=1,2,3,...qui détermine la taille de la grille carrée avec la longueur du côté 2^l+1. À l=10vous devrez stocker environ un million de numéros.
  • Quatre graines (virgule flottante) pour chaque coin
  • Un paramètre 0<h<1qui détermine la rugosité ( Hdans le lien) qui signifie la taille initiale de la plage aléatoire
  • Paramètres a,bqui représentent les limites inférieures et supérieures initiales de la plage aléatoire et sont multipliés par hà chaque étape de raffinement. (Le nombre aléatoire est uniformément choisi entre aet b.

La sortie doit être constituée de la grille 2D finie.

Donc, l'algorithme approximatif ressemblerait à ceci:

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

Il y a un détail dont vous devez être conscient: à la limite de la grille, vous n'aurez que trois sommets du diamant , vous devez donc également calculer uniquement la moyenne de ces trois points.

Une visualisation de quelques exemples (veuillez nous dire quels paramètres vous avez utilisés) est facultative mais appréciée, et n'ajoute bien sûr pas au nombre d'octets.

Une implémentation légèrement variée de cet algorithme peut être trouvée ici: Générateur de terrain de voxels projetés parallèlement

J'ai créé une petite fonction de dessin en javascript pour afficher les cartes de hauteur en 2D comme image en niveaux de gris. http://jsfiddle.net/flawr/oy9kxpsx/

Si quelqu'un d'entre vous aime la 3D fantaisie et peut créer un script pour visualiser des cartes en 3D, faites le moi savoir! =)

flawr
la source

Réponses:

8

Java, 1017 octets

Entrée est un espace séparé liste comme ceci: l s1 s2 s3 s4 h a b.

La sortie est un tableau 2D contenant les nombres.

Programme:

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

Programme en retrait et affichant la carte:

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

}

Voici une fonction en Java pour afficher une carte:

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

Toutes ces images ont une taille de 7. Les 4 graines sont 5, 10, 15et 20.

aet bsont -10et 10respectivement.

La rugosité commence à .1et augmente .1jusqu'à 1.

UnDeuxTroisQuatreCinqSixSeptHuitNeufDix

Terrain générant du code à venir !!!

Images à venir !!!

Le numéro un
la source
Merci beaucoup! Pourriez-vous peut-être fournir une classe autour de cela avec toutes les importations nécessaires afin qu'aucune grosse modification ne soit nécessaire? Ce serait génial!
flawr
@flawr j'y travaille.
TheNumberOne
Je viens de le faire fonctionner, si vous savez comment le faire, ce serait bien si vous pouviez faire apparaître la fenêtre `` non effondrée ''. Au moins sur ma machine, vous devez l'ouvrir à chaque démarrage. Voici comment j'ai terminé le cours: pastebin.com/pRAMst4d
flawr
Cela a l'air génial! J'aime particulièrement la façon élégante dont vous traitez les limites où un sommet manque =)
flawr
@flawr La fenêtre ne sera pas réduite lorsque vous l'ouvrirez maintenant.
TheNumberOne