come costruire a livello di programmazione una griglia di quadrati ad incastro ma di dimensioni casuali

8

Voglio creare un layout bidimensionale di forme rettangolari, una griglia composta da cubi di dimensioni casuali. Il cubo dovrebbe combaciare e avere uguale imbottitura o margine (spazio tra). Un po 'come un layout di fumetti o più come l'immagine allegata.

Come posso fare questo proceduralmente?

Praticamente, probabilmente userò Python e alcuni software grafici per il rendering di un'immagine, ma non conosco il tipo di algoritmo (o quant'altro) che avrei bisogno di usare per generare la griglia randomizzata.

    
posta Mrwolfy 19.11.2012 - 18:48
fonte

3 risposte

8

Inizia con una griglia di celle 1x1. Scegli un punto casuale, unisci le celle una quantità casuale o finché non collide con un rettangolo più grande.

Questo ti porterà qualcosa di simile all'immagine che fornisci.

C'è un problema più grande se non vuoi che un numero di celle più piccole funga da padding tra le tue celle più grandi. Ad esempio, un libro di fumetti vuole minimizzare la quantità di spazio morto e avere al massimo ~ 9 celle. Puoi scegliere alcuni punti e tracciare alcune linee e chiamare quelle tue cellule.

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

Ci sono molti più modi per dare la pelle a un gatto.

    
risposta data 19.11.2012 - 19:14
fonte
7
  • Inizia con un quadrato che descrive l'intera immagine.
  • Aggiungi il quadrato a un array vuoto.

  • Per ogni quadrato dell'array:

    • Crea un valore booleano con un valore vero / falso casuale
    • Se il valore è true:
      • Dividi il quadrato in 4 sottoquadri di uguali dimensioni.
      • aggiungili alla fine dell'array.
      • Rimuovi il quadrato corrente dall'array.

Alla fine del processo, avrai una serie di quadrati di dimensioni casuali. Tieni presente che probabilmente vorrai definire una dimensione minima (a quel punto non verrà più eseguita alcuna divisione) e una dimensione massima (se il quadrato è più grande, dividere sempre indipendentemente dal valore booleano).

    
risposta data 19.11.2012 - 23:49
fonte
1

Determina la dimensione e la geometria dell'immagine. Se vuoi che questo sia affiancato, la geometria sottostante è quella di un toro.

Mantieni una lista dell'angolo superiore sinistro di tutte le forme possibili. Inizialmente, questo è ogni possibile punto.

Scegli un rettangolo di dimensioni casuali (all'interno dei vincoli che hai deciso - nell'immagine di esempio sono quadrati e hanno una dimensione massima di 4). Posiziona questo rettangolo in un punto casuale in alto a sinistra.

Se il rettangolo è troppo grande (si sovrappone a una macchia allocata esistente), taglia la dimensione del rettangolo in modo che si adatti.

Rimuovi tutte le posizioni coperte da questo rettangolo dall'elenco dei possibili angoli in alto a sinistra.

Ripeti fino a quando l'elenco degli angoli in alto a sinistra è vuoto.

Rendi l'array risultante nel modo preferito. Qui è dove introdurrai un margine.

Se non conosci una particolare libreria grafica, considera l'utilizzo del formato ppm . Il vantaggio chiave è che potresti scrivere un file di testo e poi usare uno dei convertitori (ppmto

risposta data 19.11.2012 - 19:18
fonte

Leggi altre domande sui tag