Повторять функцию до тех пор, пока условие сбоя не будет выполнено - PullRequest
0 голосов
/ 29 июня 2019

Я создаю похожего на python roguelike, который использует процедурно созданные карты подземелий.Я решил добиться этого, используя списки питонов.Я создал 2d список (матрицу) для использования в качестве карты и использовал 0 для обозначения пустого пространства.Чтобы создать «комнаты» в подземелье, я использовал случайно сгенерированные переменные, чтобы определить случайную строку и столбец для верхнего правого угла комнаты, и заменил 0 на 1 (для обозначения комнат), используя циклы for и перебирая случайное число строк истолбцы:

Пример сетки заранее:

00000000000000
00000000000000
00000000000000
00000000000000
00000000000000
00000000000000

Пример сетки после создания и вставки комнаты:

00000000000000  or  00000000000000 etc
01111000000000      00000111111000
01111000000000      00000111111000
01111000000000      00000000000000
00000000000000      00000000000000
00000000000000      00000000000000 

Код с функцией для создания сетки, создания и вставки комнатыи напечатайте сетку:

import random

rand_row = random.randint(0,25)
rand_column = random.randint(0,25)
room_height = random.randint(7,15)
room_length = random.randint(7,15)

def create_grid():
    global grid
    grid = [[0 for column in range (50)] for row in range(50)]
    create_room()

def create_room():
    global grid
    print (f"Room generated is of length {room_length} and height {room_height}")
    print (f"Room placed randomly in row {rand_row} and column {rand_column}")
    print (" ")

    if room_height > 0:
        for point in grid[rand_row]:
            for each_number in range(room_length):
                for increment in range(room_height):
                    grid[rand_row+increment][rand_column+each_number] = 1


def print_grid():
    global grid
    for row in grid:
        print(" ".join(map(str,row)))

create_grid()
print_grid()

Я не знаю, как это сделать, - создать несколько комнат, убедившись, что ни одна из них не перекрывается.Я попытался создать подпрограмму проверки, которая возвращала бы логическое значение, зависящее от того, будут ли работать случайно сгенерированные значения для размера и местоположения комнат (если было перекрытие с другой комнатой, это не будет работать):

def check_if_space_taken():
    global space_is_taken
    global grid
    for each_row in range(rand_row,room_height+rand_row):
        if any(1 in each_row for each_row in grid):
            space_is_taken = True
        else:
            space_is_taken = False

Тем не менее, я не знаю, как использовать это, и я даже не уверен, что это работает.Я также создал функцию, которая изменяет все значения комнаты:

def change_room_params():
    cfg.first_row = random.randint(0,50)
    cfg.first_column  = random.randint(0,50)
    cfg.temp_room_height = random.randint(5,20)
    cfg.temp_room_length = random.randint(5,20)

Но я знаю, что процесс проверки может длиться вечно, если случайные числа продолжают давать значения, которые не работают.

Подводя итог, как мне создать новые параметры для новой комнаты и проверить, есть ли перекрытие между комнатами: создать новые значения и повторить процесс, если есть перекрытие, или создать комнату, если нет перекрытия, и впоследствии повторять процесс до тех пор, покаОпределенно нет места для больше комнат.

Спасибо за вашу помощь заранее.Я уже писал этот вопрос раньше, но удалил и сделал еще раз для более подробной информации.Я не очень разбираюсь в Python или в программировании в целом, поэтому предложения по повышению эффективности моей задачи очень ценятся.

1 Ответ

0 голосов
/ 29 июня 2019

Улучшение будет заключаться в использовании numpy массивов вместо списков Python. Особенно, когда у тебя огромные карты.

Тогда вы можете использовать модуль рисования лыжного мага для рисования полигонов или прямоугольников в вашем случае. Чтобы проверить, перехватывает ли номер, вы можете проверить, есть ли в какой-либо точке новой комнаты 1 в массиве. Эта проверка не должна занять много времени. Особенно, когда вы делаете это только один раз. Чтобы избежать бесконечной петли. Вы можете установить высокую максимальную итерацию. А если вам не хватает комнат, просто обнулите массив и повторите процесс.

Я создал код, который должен работать. Если у вас есть какие-либо вопросы, не стесняйтесь задавать их в комментариях.

Метод без звука и лыжного мага

def insert_room(data, row, col) -> bool:
    if row + ROOM_HEIGHT > MAP_HEIGHT or col + ROOM_LENGTH > MAP_WIDTH or row < 0 or col < 0:
        return False
    # This method assumes that all rooms are equal in size
    if (data[row][col] == 1 or
            data[row + ROOM_HEIGHT - 1][col] == 1 or
            data[row][col + ROOM_LENGTH - 1] == 1 or
            data[row + ROOM_HEIGHT - 1][col + ROOM_LENGTH - 1] == 1):
        return False
    for r in range(row, row + ROOM_HEIGHT):
        for c in range(col, col + ROOM_LENGTH):
            data[r][c] = 1
    return True

Допускаются номера всех размеров

def insert_room(data, row, col) -> bool:
    if row + ROOM_HEIGHT > MAP_HEIGHT or col + ROOM_LENGTH > MAP_WIDTH or row < 0 or col < 0:
        return False
    # Can room be added
    for r in range(row, ROOM_HEIGHT):
        if any(data[r][col:col+ROOM_LENGTH]):
            return False
    # Add room
    for r in range(row, row + ROOM_HEIGHT):
        for c in range(col, col + ROOM_LENGTH):
            data[r][c] = 1
    return True

Метод с NumPy и Skimage

import numpy as np
import random
import skimage.draw

MAP_WIDTH = 10
MAP_HEIGHT = 10

ROOM_LENGTH = 3
ROOM_HEIGHT = 3

NUM_ROOMS = 5


def create_map():
    # These values define how long you gonna to try to create a map
    outer_max_iteration = 10
    max_iteration = 1000

    outer_iteration = 0
    iteration = 0

    created_rooms = 0

    data = np.zeros((MAP_WIDTH, MAP_HEIGHT))
    while created_rooms < NUM_ROOMS and outer_iteration < outer_max_iteration:
        data = np.zeros((MAP_WIDTH, MAP_HEIGHT))
        while created_rooms < NUM_ROOMS and iteration < max_iteration:
            col = random.randint(0, MAP_WIDTH - ROOM_LENGTH)
            row = random.randint(0, MAP_HEIGHT - ROOM_HEIGHT)
            inserted = insert_room(data, col, row)
            created_rooms += inserted

            iteration += 1
        outer_iteration += 1
    if created_rooms < NUM_ROOMS:
        print("ERROR: Map cannot contain so many rooms!")
    print(data)
    return data


def insert_room(data, row, col) -> bool:
    # check bounds
    if row + ROOM_HEIGHT > MAP_HEIGHT or col + ROOM_LENGTH > MAP_WIDTH or row < 0 or col < 0:
        return False

    #: The rows of the polygon
    r = np.array([row, row, row + ROOM_HEIGHT, row + ROOM_HEIGHT])
    #: The columns of the polygon
    c = np.array([col, col + ROOM_LENGTH, col + ROOM_LENGTH, col])

    # create data where room should be created
    rr, cc = skimage.draw.polygon(r, c)

    #: check if room overlap with existing
    if not any(data[rr, cc]):
        data[rr, cc] = 1
        return True
    return False

пример вывода:

[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [1. 1. 1. 0. 0. 0. 1. 1. 1. 0.]
 [1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
 [1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
 [0. 0. 0. 1. 1. 1. 1. 1. 1. 0.]
 [0. 0. 0. 0. 0. 0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0. 0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
 [0. 1. 1. 1. 0. 0. 0. 0. 0. 0.]]
...