wie man programmgesteuert ein Gitter aus ineinandergreifenden Quadraten mit zufälliger Größe erstellt

8

Ich möchte ein zweidimensionales Layout aus rechteckigen Formen erstellen, ein Gitter aus zufällig großen Würfeln. Der Würfel sollte zusammenpassen und die gleiche Polsterung oder den gleichen Rand (Abstand dazwischen) haben. Ein bisschen wie ein Comic-Layout oder eher wie das angehängte Bild.

Wie könnte ich das prozedural machen?

Praktisch würde ich wahrscheinlich Python und eine Grafiksoftware verwenden, um ein Bild zu rendern, aber ich kenne nicht die Art von Algorithmus (oder was auch immer), die ich zum Generieren des zufälligen Rasters verwenden müsste.

zufällige Würfel

Mrwolfy
quelle
Das ist wirklich kein Programmierproblem. Sie müssen kommen mit und dann entscheiden , das Verfahren - auch bekannt als ‚Algorithmus‘ - von dem Sie die Quadrate; Die Implementierung ist dann ein Programmierproblem. Um die Methode zu finden? Beginnen Sie mit einem leeren Stück Papier - vorzugsweise viel Papier -, zeichnen Sie und beschreiben Sie dann, was Sie tun.
AakashM

Antworten:

8

Beginnen Sie mit einem Raster von 1x1 Zellen. Wählen Sie einen zufälligen Punkt aus, führen Sie Zellen in zufälliger Menge zusammen oder bis sie mit einem größeren Rechteck kollidieren.

Dadurch erhalten Sie etwas Ähnliches wie das von Ihnen bereitgestellte Bild.

Es gibt größere Probleme, wenn Sie nicht möchten, dass mehrere kleinere Zellen als Polster zwischen Ihren größeren Zellen fungieren. Ein Comic zum Beispiel möchte den Totraum minimieren und höchstens ~ 9 Zellen haben. Sie könnten einige Punkte auswählen und einige Linien zeichnen und diese Ihre Zellen nennen.

//Philip Haubrich, 2012, public domain
//Build instructions: gcc comicPanels.c

#include <stdio.h>  //entirely for printf()
#include <stdlib.h> //Entirely for rand()
#include <time.h> //Entirely to help srand()

#define PAINTINGSIZE_X 79
#define PAINTINGSIZE_Y 20

#define MYNUMBEROFPOINTS 4

#define MINDISTANCEBETWEENBOXES 2
//Because I suck at naming things. You should really fix this before it gets into your codebase.

#define NORTH 0
#define EAST 1
#define SOUTH 2
#define WEST 3

#define WHITE 0
#define BLACK 1

//Or, you know, a struct with .color, .r .g .b .alpha .editablebydeadpool
char g_paintingArea[PAINTINGSIZE_X][PAINTINGSIZE_Y];

void drawLineUntilBlocked(int x, int y, int direction)
{
  do
  {
    g_paintingArea[x][y] = BLACK;
    switch(direction)
    {
    case NORTH:
      y++;
      break;
    case SOUTH:
      y--;
      break;
    case EAST:
      x++;
      break;
    case WEST:
      x--;
      break;
    default:
      printf("I really need to get away from switch statements...\n");
    }
  } while(g_paintingArea[x][y] == WHITE && x > 0 && y > 0 && x < PAINTINGSIZE_X && y < PAINTINGSIZE_Y);
  //dowhile, when you are too lazy to re-arrange the code
}

//Feel free to sub in something like SDL or openGL here
void paint()
{
  int x,y;
  for(y=0; y<PAINTINGSIZE_Y; y++)
  {
    for(x=0; x<PAINTINGSIZE_X; x++)
    {
      printf("%c",g_paintingArea[x][y]);
    }
    printf("\n");
  }
}

int empty(int origx, int origy)
{
  int x,y;
  for(x=origx-MINDISTANCEBETWEENBOXES; x<origx+MINDISTANCEBETWEENBOXES; x++)
  {
    for(y=origy-MINDISTANCEBETWEENBOXES; y<origy+MINDISTANCEBETWEENBOXES; y++)
    { 
      if( x < 0 || y < 0 || x >= PAINTINGSIZE_X || y >= PAINTINGSIZE_Y)
        continue;
      if( g_paintingArea[x][y] == BLACK)
        return 0; //Not empty, there is something nearby
    }
  }
  return 1; //Empty, like my heart
}

void init()
{
  int x,y;
  //initalize to zero
  for(x=0; x<PAINTINGSIZE_X; x++)
  {
    for(y=0; y<PAINTINGSIZE_Y; y++)
    {
      g_paintingArea[x][y] = WHITE;
    }
  }
  //Border, or as I like to call it B-town
  for(x=0; x<PAINTINGSIZE_X; x++)
  {
    g_paintingArea[x][0] = BLACK;
    g_paintingArea[x][PAINTINGSIZE_Y-1] = BLACK;
  }
  for(y=0; y<PAINTINGSIZE_Y; y++)
  {
    g_paintingArea[0][y] = BLACK;
    g_paintingArea[PAINTINGSIZE_X-1][y] = BLACK;
  }

  //oh yeah, this is important
  x = abs(time(NULL));
  srand(x);
}

int main(int argc, char** argv)
{
  int x,y,i; 

  init();

  //That part you actually asked about
  for( i=0; i<MYNUMBEROFPOINTS; i++)
  {
    x = rand() % PAINTINGSIZE_X;
    y = rand() % PAINTINGSIZE_Y;

    if(!empty(x,y))
      continue;

    switch(rand()%3)
    {
    case 0: //4 way
      drawLineUntilBlocked(x,y,NORTH);
      drawLineUntilBlocked(x,y,SOUTH);
      drawLineUntilBlocked(x,y,EAST);
      drawLineUntilBlocked(x,y,WEST);
      break;
    case 1: //North/sourth
      drawLineUntilBlocked(x,y,NORTH);
      drawLineUntilBlocked(x,y,SOUTH);
      break;
    case 2: //East/West
      drawLineUntilBlocked(x,y,EAST);
      drawLineUntilBlocked(x,y,WEST);
      break;
    default:
      printf("Oh god wtf, and other useful error messages\n");
    }
  }
  //If I have to explain to you that this next bit will depend on your platform, then programming may not be for you
  paint();  
  return 0;
}

Es gibt viel mehr Möglichkeiten, eine Katze zu häuten.

Philip
quelle
7
  • Beginnen Sie mit einem Quadrat, das das gesamte Bild beschreibt.
  • Fügen Sie das Quadrat einem leeren Array hinzu.

  • Für jedes Quadrat im Array:

    • Erstellen Sie einen Booleschen Wert mit einem zufälligen True / False-Wert.
    • Wenn der Wert wahr ist:
      • Teilen Sie das Quadrat in 4 gleich große Unterquadrate auf.
      • Fügen Sie sie am Ende des Arrays hinzu.
      • Entfernen Sie das aktuelle Quadrat aus dem Array.

Am Ende des Prozesses haben Sie eine Reihe von zufällig großen Quadraten. Beachten Sie, dass Sie wahrscheinlich eine Mindestgröße (zu diesem Zeitpunkt erfolgt keine weitere Teilung mehr) und eine Höchstgröße (wenn das Quadrat größer ist, unabhängig vom Booleschen Wert immer teilen) definieren möchten.

Ameise
quelle
1
Dies scheint eine gute Lösung zu sein.
Mrwolfy
(Ich habe im College einen ähnlichen Algorithmus für einen rekursiven Labyrinthgenerator verwendet.) Dies hat den Nebeneffekt, dass immer Linien das gesamte Bild durchschneiden.
@MichaelT: Auf jeden Fall ein Problem, aber die Einfachheit und Geschwindigkeit des Algorithmus machen das wohl wieder wett. Es hängt wirklich vom Anwendungsfall ab, ob dies ein angemessener Ansatz für das Problem ist oder nicht. Das Beispielbild scheint mit diesem Algorithmus generiert worden zu sein, da es unter dem von Ihnen hervorgehobenen Problem leidet.
Ameise
1

Bestimmen Sie die Größe und Geometrie des Bildes. Wenn Sie möchten, dass dies gekachelt wird, ist die zugrunde liegende Geometrie die eines Torus.

Pflegen Sie eine Liste der oberen linken Ecke aller möglichen Formen. Dies ist zunächst jeder mögliche Punkt.

Wählen Sie ein Rechteck mit zufälliger Größe (innerhalb der von Ihnen festgelegten Einschränkungen - im Beispielbild handelt es sich um Quadrate mit einer maximalen Größe von 4). Platzieren Sie dieses Rechteck an einer zufälligen Stelle in der oberen linken Ecke.

Wenn das Rechteck zu groß ist (überlappt einen vorhandenen zugewiesenen Punkt), schneiden Sie die Abmessung des Rechtecks ​​so, dass es passt.

Entfernen Sie alle von diesem Rechteck abgedeckten Stellen aus der Liste der möglichen oberen linken Ecken.

Wiederholen, bis die Liste der oberen linken Ecken leer ist.

Rendern Sie das resultierende Array auf Ihre bevorzugte Weise. Hier würden Sie einen Rand einführen.


Wenn Sie mit einer bestimmten Grafikbibliothek nicht vertraut sind, sollten Sie das ppm-Format verwenden . Der Hauptvorteil besteht darin, dass Sie eine Textdatei schreiben und dann einen der Konverter (ppmto___) verwenden können, um das Bild in das von Ihnen gewählte Format zu konvertieren (ppmtogif. Ppmtojpeg, ...).


quelle
Vielen Dank. Tatsächlich bin ich mehr daran interessiert, es in eine Reihe von Mittelpunkten (auf einem x-, y-Raster) und Skalenbeschreibungen (wie zum Beispiel in 1 oder .5 oder 2) umzuwandeln. Ich werde diese Zahlen in eine 3D-App einspeisen.
Mrwolfy