Làm thế nào để lập trình xây dựng một mạng lưới các ô vuông xen kẽ nhưng có kích thước ngẫu nhiên


8

Tôi muốn tạo một bố cục hai chiều của các hình chữ nhật, một lưới được tạo thành từ các hình khối có kích thước ngẫu nhiên. Các hình khối phải phù hợp với nhau và có phần đệm hoặc lề bằng nhau (khoảng cách giữa). Kiểu như một bố cục truyện tranh, hoặc giống như hình ảnh đính kèm.

Làm thế nào tôi có thể làm điều này theo thủ tục?

Thực tế, tôi có thể sẽ sử dụng Python và một số phần mềm đồ họa để hiển thị hình ảnh, nhưng tôi không biết loại thuật toán (hoặc không có gì) tôi sẽ cần sử dụng để tạo lưới ngẫu nhiên.

khối ngẫu nhiên


Thực sự, đây không phải là một vấn đề lập trình. Bạn phải đưa ra và sau đó quyết định phương pháp - còn gọi là 'thuật toán' - theo đó bạn muốn các hình vuông; thực hiện nó sau đó là một vấn đề lập trình. Để đưa ra phương pháp? Bắt đầu với một mảnh giấy trắng - tốt nhất là nhiều mảnh giấy - vẽ, và sau đó mô tả những gì bạn đang làm.
AakashM

Câu trả lời:


8

Bắt đầu với một lưới gồm các ô 1x1. Chọn một điểm ngẫu nhiên, hợp nhất các ô một lượng ngẫu nhiên hoặc cho đến khi nó va chạm với một hình chữ nhật lớn hơn.

Điều này sẽ giúp bạn có một cái gì đó tương tự như hình ảnh bạn cung cấp.

Có một vấn đề lớn hơn nếu bạn không muốn một số ô nhỏ hơn đóng vai trò đệm giữa các ô lớn hơn của bạn. Ví dụ, một cuốn truyện tranh muốn giảm thiểu lượng không gian chết và có tối đa ~ 9 ô. Bạn có thể chọn một số điểm và vẽ một số dòng và gọi chúng là các ô của bạn.

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

Có rất nhiều cách để da mèo.


7
  • Bắt đầu với một hình vuông mô tả toàn bộ hình ảnh.
  • Thêm hình vuông vào một mảng trống.

  • Đối với mỗi hình vuông trong mảng:

    • Tạo một boolean với giá trị đúng / sai ngẫu nhiên.
    • Nếu giá trị là đúng:
      • Chia hình vuông thành 4 hình vuông có kích thước bằng nhau.
      • Thêm chúng vào cuối mảng.
      • Loại bỏ hình vuông hiện tại khỏi mảng.

Khi kết thúc quá trình, bạn sẽ có một mảng các ô vuông có kích thước ngẫu nhiên. Lưu ý rằng có thể bạn sẽ muốn xác định kích thước tối thiểu (tại thời điểm không thực hiện chia nữa) và kích thước tối đa (nếu hình vuông lớn hơn, luôn luôn phân chia bất kể giá trị boolean).


1
Đây có vẻ là một giải pháp tốt.
Mrwolfy

(Tôi đã sử dụng một thuật toán tương tự cho một trình tạo mê cung đệ quy ở trường đại học) Điều này sẽ có tác dụng phụ là luôn có các đường cắt xuyên qua toàn bộ hình ảnh.

@MichaelT: Chắc chắn là một vấn đề, nhưng sự đơn giản và tốc độ của thuật toán có thể bù đắp cho nó. Nó thực sự phụ thuộc vào trường hợp sử dụng cho dù đây có phải là một cách tiếp cận phù hợp cho vấn đề hay không. Hình ảnh ví dụ dường như đã được tạo bằng thuật toán này vì nó gặp phải vấn đề bạn nêu bật.
Kiến

1

Xác định kích thước và hình dạng của hình ảnh. Nếu bạn muốn điều này được lát gạch, hình học cơ bản là hình xuyến.

Duy trì một danh sách các góc trên bên trái của tất cả các hình dạng có thể. Ban đầu, đây là mọi điểm có thể.

Chọn một hình chữ nhật có kích thước ngẫu nhiên (trong các ràng buộc bạn đã quyết định - trong hình ảnh ví dụ chúng là hình vuông và có kích thước tối đa là 4). Đặt hình chữ nhật này ở một vị trí góc trên bên trái ngẫu nhiên.

Nếu hình chữ nhật quá lớn (chồng lấp một vị trí được phân bổ hiện có), hãy cắt kích thước của hình chữ nhật sao cho phù hợp.

Xóa tất cả các vị trí được bao phủ bởi hình chữ nhật này khỏi danh sách các góc trên bên trái có thể.

Lặp lại cho đến khi danh sách góc trên bên trái trống.

Kết xuất mảng kết quả theo cách ưa thích của bạn. Đây là nơi bạn sẽ giới thiệu một lề.


Nếu bạn không quen thuộc với bất kỳ thư viện đồ họa cụ thể nào, hãy xem xét sử dụng định dạng ppm . Ưu điểm chính là bạn có thể viết ra một tệp văn bản và sau đó sử dụng một trong các trình chuyển đổi (ppmto___) để chuyển đổi hình ảnh sang định dạng bạn đã chọn (ppmtogif. Ppmtojpeg, ...)


Cảm ơn. Trong thực tế, tôi quan tâm nhiều hơn đến việc chuyển đổi nó thành một tập hợp các điểm trung tâm (trên lưới x, y) và mô tả tỷ lệ (ví dụ như trong 1 hoặc 0,5, hoặc 2). Tôi sẽ đưa những con số này vào một ứng dụng 3d.
Mrwolfy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.