Python/Pygame – ближайшие координаты в сетке

Это реализуется с помощью Python и Pygame, но это довольно общий вопрос программирования (что означает независимость от реализации).

У меня есть функция, которая принимает в качестве входных данных целое число x и y и должна генерировать сетку 3x3 соседних точек (включая x и y).

Примечание: начало координат 0,0 начинается слева вверху. x увеличивается при движении вправо, y увеличивается при движении вниз.

Eg.

def nearest_grid(x, y):
    return [[(x-1,y-1),(x,y-1),(x+1,y-1)],[(x-1,y)(x,y),(x+1,y)],[(x-1,y+1),(x,y+1),(x+1,y+1)]]

Итак, учитывая сетку и точку (отмеченную p), он возвращает следующее как список из 3 списков:

x  x  x
x  p  x
x  x  x

Это самый эффективный/разборчивый способ сделать это в Python?

РЕДАКТИРОВАТЬ: Предположим, я хотел передать значение радиуса (где указанное выше значение радиуса было бы равно 1). Итак, если бы я передал значение радиуса 2, то описанный выше метод быстро стал бы утомительным. Есть ли более общий способ?


person sdasdadas    schedule 15.07.2012    source источник


Ответы (2)


Мне больше нравится это решение на основе numpy:

>>> import numpy
>>> def nearest_grid(x, y, radius=1):
...     X, Y = numpy.mgrid[-radius:radius + 1, -radius:radius + 1]
...     return numpy.dstack((X + x, Y + y))
... 
>>> nearest_grid(1, 2)
array([[[0, 1],
        [0, 2],
        [0, 3]],

       [[1, 1],
        [1, 2],
        [1, 3]],

       [[2, 1],
        [2, 2],
        [2, 3]]])

Вот сильно обобщенная версия, которая принимает любое количество координат. Это не разбивает возвращаемый список на сетку; он просто возвращает плоский список соседей для простоты.

>>> def nearest_grid(*dims, **kwargs):
...     radius = kwargs.get('radius', 1)
...     width = radius * 2 + 1
...     dims = (d - radius for d in dims)
...     return list(itertools.product(*(xrange(d, d + width) for d in dims)))
... 
>>> nearest_grid(1, 2, 3, radius=1)
[(0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 2), (0, 2, 3), (0, 2, 4), 
 (0, 3, 2), (0, 3, 3), (0, 3, 4), (1, 1, 2), (1, 1, 3), (1, 1, 4), 
 (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 2), (1, 3, 3), (1, 3, 4), 
 (2, 1, 2), (2, 1, 3), (2, 1, 4), (2, 2, 2), (2, 2, 3), (2, 2, 4), 
 (2, 3, 2), (2, 3, 3), (2, 3, 4)]

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

>>> def nearest_grid(x, y, radius=1):
...     X, Y = numpy.mgrid[-radius:radius + 1, -radius:radius + 1]
...     return numpy.dstack((Y + y, X + x))
... 
>>> grid
array([[[0, 0],
        [1, 0],
        [2, 0]],

       [[0, 1],
        [1, 1],
        [2, 1]],

       [[0, 2],
        [1, 2],
        [2, 2]]])

Теперь у нас есть сетка, в которой значения хранятся в [x, y] порядке. Что происходит, когда мы используем их в качестве индексов для grid?

>>> grid = nearest_grid(1, 1)
>>> x, y = 0, 2
>>> grid[x][y]
array([2, 0])

Мы не получаем ячейку, которую мы ожидали! Это потому, что с сеткой, расположенной так:

grid = [[(x, y), (x, y), (x, y)],
        [(x, y), (x, y), (x, y)],
        [(x, y), (x, y), (x, y)]]

grid[0] дает нам первую строку, то есть y = 0 строку. Итак, теперь мы должны изменить порядок:

>>> grid[y][x]
array([0, 2])

Лучше хранить значения в порядке строк ((y, x)).

person senderle    schedule 15.07.2012

person    schedule
comment
Вы также можете использовать более компактную версию: [(x+dx,y+dy) для dx в xrange(-r,r+1) для dy в xrange(-r,r+1)] - person pmoleri; 16.07.2012