Làm thế nào tôi có thể tăng dần một đồ thị?


8

Tôi vừa bắt đầu một dự án mới, trong đó tôi muốn thế giới trò chơi bao gồm các địa điểm được tạo theo thủ tục được kết nối bởi các dịch chuyển tức thời. Sau một chút nghiên cứu, tôi đã phát hiện ra điều này được gọi là "lý thuyết đồ thị" hoặc "phức tạp đẫm máu", tùy thuộc vào người đang thảo luận về nó. Thật không may, tôi đã tìm thấy rất ít thông tin về việc tạo biểu đồ; hầu hết các công cụ tôi đã thấy đều hướng đến việc kiểm tra các biểu đồ hiện có.

Giả sử tôi có thuật ngữ được sắp xếp chính xác, yêu cầu của tôi là biểu đồ là:

  • đơn giản - không có vị trí (đỉnh) nên có một dịch chuyển tức thời (cạnh) kết nối lại với chính nó, cũng không nên có hai đỉnh có nhiều cạnh kết nối chúng
  • đã kết nối - nên có thể di chuyển giữa hai đỉnh bất kỳ trong biểu đồ (mặc dù tôi không thấy trước khi cần tìm đường dẫn; chỉ cần biết người chơi có thể tìm thấy một nếu họ chọn là đủ)
  • tuần hoàn - nên có nhiều hơn một đường giữa hai đỉnh bất kỳ
  • không bị ảnh hưởng - tất cả các cạnh có thể được di chuyển theo một trong hai hướng
  • vô hạn - nếu người chơi mong muốn, họ sẽ có thể di chuyển vô thời hạn, với biểu đồ tiếp tục tạo ra tăng dần khi họ tiếp cận các đỉnh ngoài cùng chưa được khám phá của nó
  • hữu hạn cục bộ - mức độ của một đỉnh sẽ không bao giờ thay đổi sau khi người chơi đã truy cập nó
  • được gắn nhãn ổn định - mỗi đỉnh đại diện cho một vị trí sẽ được tạo theo thủ tục từ hạt giống; cùng một hạt giống phải được gán cho một đỉnh bất kể người chơi đã sử dụng con đường nào để đi đến đó hoặc đồ thị lớn như thế nào khi họ làm

Tôi đã có một số ý tưởng (mà tôi chưa thử thực hiện) liên quan đến việc sử dụng cực đại cục bộ của nhiễu perlin 2D làm đỉnh (đầu vào xy sau đó có thể được sử dụng làm nhãn của nó), nhưng cảm giác đó quá phức tạp và quá phức tạp.

Có cách nào tốt hơn để tạo một biểu đồ như thế này không? Tôi đang phát triển trong Python 2.6 bằng cách sử dụng Panda3D và numpy, và tất nhiên sẽ sẵn sàng xem xét bao gồm các thư viện khác nếu chúng sẽ giúp giải quyết vấn đề này!

Biên tập

Tôi nghĩ rằng tôi đã làm một công việc kém giải thích một số yêu cầu của tôi, vì vậy đó là thời gian minh họa! Hy vọng, điều này sẽ làm sáng tỏ mọi thứ.

Điều tôi muốn nói là có nhãn ổn định là tôi muốn, ví dụ, Người chơi A có thể thực hiện một loạt các khám phá và tìm kiếm, trong số những thứ khác, một con đường tuần hoàn trở lại vị trí bắt đầu của họ và một ngọn núi trông giống như một con mèo. Trò chơi của anh ta bây giờ trông giống như sau (các đỉnh được đánh số bằng hạt giống và các cạnh của chúng theo thứ tự mà người chơi đi qua chúng). Ông bắt đầu trên đỉnh 8329 (màu xanh lá cây) và Núi Happycat nằm ở đỉnh 6745 (màu xanh).

Biểu đồ thế giới của người chơi A

Người bạn tốt của người chơi A Người chơi B là một người hâm mộ mèo, vì vậy anh ta muốn cho cô ấy xem. Anh ta đưa cho cô hạt giống gốc cho thế giới của mình và chỉ đường dọc theo con đường ngắn hơn đến ngọn núi quan tâm. Trò chơi của cô bây giờ trông như thế này:

Biểu đồ thế giới của người chơi B

Vấn đề tôi hiện đang gặp khó khăn nhất là "Làm cách nào để tạo cùng một hạt giống cho Người chơi B khi cuộc thám hiểm của cô ấy không đi theo cùng một con đường?" Đó là điều khiến tôi nảy ra ý tưởng sử dụng tiếng ồn Perlin - miễn là sử dụng cùng một hạt giống gốc, cực đại sẽ không di chuyển, do đó tọa độ của chúng có thể được sử dụng làm hạt đỉnh ổn định.


Tại sao một đồ thị được kết nối không phù hợp với điều này? mathworld.wolfram.com/ConnectedGraph.html Tôi có thể bị mất điểm mặc dù. Nếu người dùng muốn đi từ địa điểm này sang địa điểm khác và tất cả họ đều được kết nối, hãy cung cấp cho họ danh sách các địa điểm và di chuyển vị trí của họ trên bản đồ thế giới sang địa điểm mới.
brandon

@brandon - "Đã kết nối" là tài sản thứ hai tôi liệt kê. :-)
Ben Trống

quan điểm của tôi là, nếu bạn có thể đi từ nút này sang nút khác. Khi họ truy cập dịch chuyển tức thời, hãy cung cấp cho họ danh sách tất cả các nút mà họ đã truy cập ngoại trừ nút này. Không cần phải có biểu đồ, bạn giữ một danh sách tất cả các nút được truy cập và vị trí của chúng và bạn chỉ cần dịch chuyển đến vị trí họ chọn. Tôi có hiểu lầm không?
brandon

hầu như tất cả các mô tả của bạn về các điều khoản đó là chính xác, ngoại trừ "chu kỳ" và "hữu hạn cục bộ". Đầu tiên hạn chế biểu đồ của bạn giống như biểu đồ của chúng - một vòng tròn. Một thuật ngữ bạn có thể sử dụng cho yêu cầu có nhiều hơn một đường dẫn từ đỉnh này sang đỉnh khác là "kết nối 2". "Hữu hạn cục bộ" chỉ có nghĩa là mỗi đỉnh có số cạnh hữu hạn.
Harry Stern

@Harry Stern - Hiểu biết của tôi là đồ thị tuần hoàn là đồ thị chứa ít nhất một chu kỳ đồ thị . Có vẻ như bạn đang nói về một biểu đồ chu kỳ , đó là một biểu đồ bao gồm một chu kỳ biểu đồ duy nhất và không có gì khác. Tôi đặc biệt không tìm kiếm các biểu đồ "kết nối 2" (xem "đơn giản"). Và vâng, đó là những gì tôi có nghĩa là "hữu hạn địa phương".
Ben Trống

Câu trả lời:


6

Bạn không thể tạo một biểu đồ vô hạn. Bộ nhớ của bạn là hữu hạn, do đó số lượng đỉnh và cạnh cũng là hữu hạn. Những gì bạn có thể làm là tạo một biểu đồ hữu hạn sau đó thêm nhiều hơn vào nó. Bạn dường như đã nhận ra điều này nhưng tôi nghĩ điều quan trọng là nó phải được tuyên bố rõ ràng để bạn không đi vào một con đường cụt.

Bạn phải rất cẩn thận khi nói về "đỉnh ngoài cùng". Biểu đồ là một tập hợp các đỉnh, một tập hợp các cạnh và một hàm liên quan đến hai. Không có thiết lập giải thích hình học trừ khi bạn áp dụng một. Ví dụ: cả hai hình ảnh này hiển thị cùng một biểu đồ. Trong hình ảnh đầu tiên, đỉnh 2 có thể được coi là một đỉnh "ngoài cùng", nhưng trong hình ảnh thứ hai, đỉnh 2 sẽ không được coi là "ngoài cùng". Nếu bạn xem xét ba chiều, bạn có thể nói tất cả các đỉnh là "ngoài cùng".

Đồ thị 1 Đồ thị 2

Điều này có nghĩa là bạn phải có một số thông tin khác để bạn có thể biết đỉnh "ngoài cùng" là gì. Bạn có thể sử dụng các cặp (x, y) vì điều đó sẽ giúp bạn dễ hình dung biểu diễn hình học, tuy nhiên tôi không nghĩ bạn cần phải đi xa đến thế. Từ những gì bạn nói, tất cả những gì bạn cần biết là những đỉnh nào trong biểu đồ đã có.

Nếu bạn chạy cái này mỗi khi bạn truy cập một đỉnh:

if(this.needsNeighbours)
{
    List<int> connections = genRandomNumbers(n);
    foreach (int connection in connections)
    {
        //Simple graph
        if(connection == this.seed || this.hasNeighbour(connection))
        {
            continue;
        }
        //Connections to already existing, unvisited vertices
        else if(nodeMap.containsKey(connection) && 
                nodeMap.getByKey(connection).needsNeighbours)
        {
            nodeMap.getByKey(connection).addNeighbour(this.seed);
            this.addNeighbour(connection);
        }
        //Grow graph with new vertices
        else
        {
            nodeMap.add(connection, new Node(connection));
            nodeMap.getByKey(connection).addNeighbour(this.seed);
            this.addNeighbour(connection);
        }
    }
    this.needsNeighbours = false;
}

đồ thị của bạn sẽ đáp ứng tất cả các yêu cầu của bạn ngoại trừ theo chu kỳ. Tôi không biết nếu bạn thực sự cần một sự đảm bảo. Nếu bạn làm như vậy thì bạn có thể chọn cụ thể một nút không mong muốn và tạo kết nối, điều đó sẽ đảm bảo một đường dẫn giữa nút hiện tại và nút đã truy cập vì tất cả các nút không mong muốn được kết nối với ít nhất một nút đã truy cập và vì bạn phải truy cập vào một nút nút đã truy cập để đến nơi bạn đang ở hiện tại có ít nhất hai đường dẫn.

Nó đơn giản vì có một kiểm tra rõ ràng cho nó, được kết nối vì tất cả các nút mới nhận được ít nhất một kết nối, hữu hạn cục bộ vì các cạnh chỉ được thêm trước khi bạn truy cập hoặc trong lần truy cập đầu tiên và chỉ vào các nút không được chú ý. Về mặt kỹ thuật, nó không phải là vô hướng, nhưng về mặt chức năng, nó giống như bạn tạo ra một cạnh định hướng theo cả hai hướng. Bạn có thể gắn nhãn cho nút bất cứ điều gì bạn muốn, tôi sử dụng số ngẫu nhiên được tạo, nhưng bạn có thể thêm các tham số khác vào hàm tạo, một tham số là hạt giống của bạn.


Bạn nhận thức chính xác những gì tôi muốn nói là "vô hạn" và quan điểm của bạn về "ngoài cùng" được thực hiện tốt - tôi đã điều chỉnh các câu trong câu hỏi của tôi. Tuy nhiên, hoặc tôi không hiểu chính xác trình tạo của bạn hoặc tôi đã giải thích nhu cầu của mình kém, vì điều này có vẻ như điều này sẽ không tạo ra cùng một hạt giống cho các đường dẫn khác nhau đến cùng một đỉnh. Tôi đã thêm một số hình ảnh minh họa cho câu hỏi của mình, hy vọng sẽ làm rõ hơn những gì tôi đang cố gắng thực hiện. :-)
Ben Trống

Tôi thấy những gì bạn có nghĩa là bây giờ. Đó là một chút khó khăn hơn. Những gì bạn cần làm là thay đổi lệnh gọi genRandomNumbers thành một hàm luôn trả về cùng một bộ số cho đầu vào của nó và sử dụng hạt giống của nút làm đối số. Điều này sẽ đảm bảo rằng bạn sẽ nhận được các kết nối và hạt giống nhau cho dù bạn đi theo con đường nào hoặc bắt đầu với nút nào. Bạn sẽ phải cẩn thận rằng tập hợp các số cho nút B mà A kết nối cũng chứa A để bạn có được thuộc tính đồ thị vô hướng của mình. Nếu bạn không làm điều này thì bạn sẽ có được một biểu đồ được định hướng.
Chewy Gumball

1

Một phương pháp:

init:
  root = generateLocation using random seed
  store root's seed
  place player in root location

when the player enters a new location:
  release the memory used by locations that are further than 1 edge away, but keep their seeds
  generate some neighbors for the new location. for every neighbor n:
    gen.seed(getSeed(n))
    n = generateLocation using n's random seed
    numCyclicEdges = gen.randint(0, 1)
    create numCycleEdges edges to existing locations

getSeed(n):
  if(n already has a seed) return n's seed
  else return randomSeed()

Có rất nhiều chi tiết tôi bỏ qua, nhưng điều này sẽ nắm bắt được ý tưởng chung. Bạn có thể muốn giữ hàng xóm trong bộ nhớ cách xa vị trí hiện tại hơn, tùy thuộc vào khoảng cách thế giới giữa các cổng, có nhiều bộ nhớ khả dụng, v.v.

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.