Что такое хорошая стратегия построения ориентированного графа для игровой карты (в Python)?

Вот метод, который дает ускорение в 10 000 раз на N=310, M=230. Поскольку метод масштабируется лучше, чем исходный код, я ожидаю, что при полном размере задачи коэффициент будет превышать миллион.

В этом методе используется сдвиговая инвариантность задачи. Например, del_x**2 по сути одинаков с точностью до сдвига при каждом вызове do_calc, поэтому мы вычисляем его только один раз.

Если выходные данные из do_calc взвешены до суммирования, проблема перестает быть полностью трансляционно-инвариантной, и этот метод больше не работает. Результат, однако, затем может быть выражен в терминах линейной свертки. На N=310, M=230 это все еще оставляет нам более чем 1000-кратное ускорение. И, опять же, это будет больше при полном размере задачи

Код для исходной задачи

import numpy as np

#N, M = 3108, 2304
N, M = 310, 230

### OP's code

x,y = np.linspace(1,N,num=N),np.linspace(1,M,num=M) # x&y dimensions of image
X,Y = np.meshgrid(x,y,indexing='ij')
all_coords = np.dstack((X,Y)) # moves to 3-D
all_coords = all_coords.astype(int) # sets coords to int

'''
- below is a function that does a calculation on the full grid using the distance between x0,y0 and each point on the grid.
- the function takes x0,y0 and returns the calculated values across the grid
'''
def do_calc(x0,y0):
    del_x, del_y = X-x0, Y-y0
    np.seterr(divide='ignore', invalid='ignore')
    dmx_ij = (del_x/((del_x**2)+(del_y**2))) # x component
    dmy_ij = (del_y/((del_x**2)+(del_y**2))) # y component
    return np.nan_to_num(dmx_ij), np.nan_to_num(dmy_ij)

# now the actual loop

def do_loop():
    dmx,dmy = 0,0
    for pair in all_coords:
        for xi,yi in pair:
            DM = do_calc(xi,yi)
            dmx,dmy = dmx+DM[0],dmy+DM[1]
    return dmx,dmy

from time import time

t = [time()]

### pp's code

x, y = np.ogrid[-N+1:N-1:2j*N - 1j, -M+1:M-1:2j*M - 1J]
den = x*x + y*y
den[N-1, M-1] = 1
xx = x / den
yy = y / den
for zz in xx, yy:
    zz[N:] -= zz[:N-1]
    zz[:, M:] -= zz[:, :M-1]
XX = xx.cumsum(0)[N-1:].cumsum(1)[:, M-1:]
YY = yy.cumsum(0)[N-1:].cumsum(1)[:, M-1:]
t.append(time())

### call OP's code for reference

X_OP, Y_OP = do_loop()
t.append(time())

# make sure results are equal

assert np.allclose(XX, X_OP)
assert np.allclose(YY, Y_OP)
print('pp {}\nOP {}'.format(*np.diff(t)))

Пример выполнения:

pp 0.015251636505126953
OP 149.1642508506775

Код для взвешенной задачи: [1114 ]

import numpy as np

#N, M = 3108, 2304
N, M = 310, 230

values = np.random.random((N, M))
x,y = np.linspace(1,N,num=N),np.linspace(1,M,num=M) # x&y dimensions of image
X,Y = np.meshgrid(x,y,indexing='ij')
all_coords = np.dstack((X,Y)) # moves to 3-D
all_coords = all_coords.astype(int) # sets coords to int

'''
- below is a function that does a calculation on the full grid using the distance between x0,y0 and each point on the grid.
- the function takes x0,y0 and returns the calculated values across the grid
'''
def do_calc(x0,y0, v):
    del_x, del_y = X-x0, Y-y0
    np.seterr(divide='ignore', invalid='ignore')
    dmx_ij = (del_x/((del_x**2)+(del_y**2))) # x component
    dmy_ij = (del_y/((del_x**2)+(del_y**2))) # y component
    return v*np.nan_to_num(dmx_ij), v*np.nan_to_num(dmy_ij)

# now the actual loop

def do_loop():
    dmx,dmy = 0,0
    for pair, vv in zip(all_coords, values):
        for (xi,yi), v in zip(pair, vv):
            DM = do_calc(xi,yi, v)
            dmx,dmy = dmx+DM[0],dmy+DM[1]
    return dmx,dmy

from time import time
from scipy import signal

t = [time()]
x, y = np.ogrid[-N+1:N-1:2j*N - 1j, -M+1:M-1:2j*M - 1J]
den = x*x + y*y
den[N-1, M-1] = 1
xx = x / den
yy = y / den
XX, YY = (signal.fftconvolve(zz, values, 'valid') for zz in (xx, yy))

t.append(time())
X_OP, Y_OP = do_loop()
t.append(time())
assert np.allclose(XX, X_OP)
assert np.allclose(YY, Y_OP)
print('pp {}\nOP {}'.format(*np.diff(t)))

Пример прогона:

pp 0.12683939933776855
OP 158.35225439071655
9
задан David Eyk 4 March 2009 в 19:00
поделиться

2 ответа

Во-первых, Вам нужен некоторый смысл Местоположения. Ваши различные объекты занимают некоторое количество координатного пространства.

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

Если вещи неправильны - и плотно упакованный - жизнь несколько более сложна.

Определите Карту для содержания местоположений. Каждое местоположение имеет промежуток координат; если Вы работаете с простыми прямоугольниками, то каждое местоположение может иметь (оставленный, вершина, право, нижняя часть) кортеж.

Для Вашей Карты будут нужны методы для определения, кто находится в данном пространстве, и что смежно с пространством и т.д.

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


Во-вторых, Вам нужен своего рода "генератор лабиринта". Просто подключенный лабиринт легко сгенерирован как древовидная структура, это сложено в данное пространство.

Лабиринт/дерево имеет "корневой" узел, который будет центром лабиринта. Не обязательно физический центр Вашего пространства, но корневой узел будет серединой структуры лабиринта.

Идеально, одно ответвление от этого узла содержит один "вход" ко всему пространству.

Другое ответвление от этого узла содержит один "выход" от всего пространства.

Кто-то может блуждать от входа для выхода, посещая много "тупиковых" местоположений по пути.

Выберите своего рода пространство для корневого узла. Бросьте его в свое пространство Карты.

Это будет иметь 1 - n входы, каждый из которых является поддеревом с корневым узлом и 1 - n входы. Именно этот бизнес нескольких-входов делает дерево естественным пригодным для этой структуры. Также надлежащее дерево всегда имеет хорошие связи в этом, Вы никогда не изолировали разделы, которые не могут быть достигнуты.

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

Модульный тест это, чтобы быть уверенным это заполняет пространство обоснованно хорошо.


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

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


Ваше определение пространства может быть 2D или 3D - оба довольно рациональны. Для бонусного кредита рассмотрите, как Вы реализовали бы 2D пространство, размещенное рядом с шестиугольниками вместо квадратов.

Эта "геометрия" может быть плагином Стратегии к различным алгоритмам. Если можно заменить квадрат, 2D 2D шестиугольным, Вы сделали хорошее задание Дизайна OO.

7
ответ дан 4 December 2019 в 21:51
поделиться

Проверьте обсуждения Коннектора MUD - существуют некоторые большие дискуссии о мировом расположении и поколении и различных типах координаты / системы навигации в "Усовершенствованном Кодировании и Дизайне" (или подобны) форум.

2
ответ дан 4 December 2019 в 21:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: