Ищете идеи, как реорганизовать мой алгоритм

Я пытаюсь написать свою Игру Жизни, со своим собственным набором правил. Первой "концепцией", которую я хотел бы применить, является социализация (что в основном означает, что клетка хочет быть одна или в группе с другими ячейками). Структура данных - это двумерный массив (на данный момент).

Чтобы иметь возможность перемещать ячейку в/из группы других ячеек, мне нужно определить, куда ее перемещать. Идея состоит в том, что я оцениваю все ячейки в области (соседей) и получаю вектор, который говорит мне, куда перемещать ячейку. Размер вектора равен 0 или 1 (не двигайтесь и не двигайтесь), а угол представляет собой массив направлений (вверх, вниз, вправо, влево).

Это изображение с изображением сил для клетки, как я себе это представлял (но охват может быть больше 5):

ForceAppliedToACell

Позвольте, например, сделать эту фотографию:

Example

Forces from lower left neighbour: down (0), up (2), right (2), left (0)
Forces from right neighbour     : down (0), up (0), right (0), left (2)
sum                             : down (0), up (2), right (0), left (0)

Так что клетка должна идти вверх.

Я мог бы написать алгоритм с большим количеством операторов if и проверить все ячейки по соседству. Конечно, этот алгоритм был бы самым простым, если бы параметр 'reach' был установлен в 1 (первый столбец на рисунке 1). Но что, если я изменю параметр досягаемости на 10, например? Мне нужно было бы заранее написать алгоритм для каждого параметра "достижения"... Как я могу избежать этого (обратите внимание, что сила возрастает (1, 2, 4, 8, 16, 32,...))? Могу ли я использовать конкретный шаблон дизайна для этой проблемы?

Кроме того: самое главное не скорость, а возможность расширить исходную логику.

Что следует принять во внимание:

  • досягаемость должна быть передана как параметр
  • Я хотел бы изменить функцию, которая рассчитывает силу (потенциал, Фибоначчи)
  • ячейка может перейти в новое место, только если это новое место не заселено
  • следите за углами (например, вы не можете оценить правых и верхних соседей в верхнем правом углу)

Ответы

Ответ 1

Нетрудно написать свой алгоритм для поиска всех ячеек в пределах досягаемости определенной ячейки C. Каждая ячейка, у которой есть житель, будет иметь особую силу отталкивания на ячейке C. Эта сила отталкивания основана на расстоянии от ячейки до ячейки C. В примере, который вы указали, эта сила отталкивания основана на расстоянии L-1 и составляет 2^(reach-distance). Затем каждая сила отталкивания складывается вместе, чтобы создать кумулятивную силу, которая диктует направление перемещения жителя в ячейку C.

Вам не нужно писать алгоритм для каждого разного охвата. Величину силы можно определить по простой формуле. Если вы измените эту формулу на что-то еще, например, на число Фибоначчи, вы все равно сможете вычислить величину по мере необходимости на основе расстояния и досягаемости.


Вот грубый код, написанный на псевдо-Java, показывающий основные идеи: http://codepad.org/K6zxnOAx

enum Direction {Left, Right, Up, Down, None};

Direction push(boolean board[][], int testX, int testY, int reach)
{
    int xWeight = 0;
    int yWeight = 0;
    for (int xDist=-reach; xDist<=+reach; ++xDist)
    {
        for (int yDist=-reach; yDist<=+reach; ++yDist)
        {
            int normDist = abs(xDist) + abs(yDist);
            if (0<normDist && normDist<reach)
            {
                int x = testX + xDist;
                int y = testY + yDist;
                if (0<=x && x<board.length && 0<=y && y<board[0].length)
                {
                   if (board[x][y])
                   {
                       int force = getForceMagnitude(reach, normDist);
                       xWeight += sign(xDist) * force;
                       yWeight += sign(yDist) * force;
                   }
                }
            }
        }
    }
    if (xWeight==0 && yWeight==0) return Direction.None;
    if (abs(xWeight) > abs(yWeight))
    {
        return xWeight<0 ? Direction.Left : Direction.Right;
    }
    else
    {
        return yWeight<0 ? Direction.Up : Direction.Down;
    }
}

int getForceMagnitude(int reach, int distance)
{
    return 1<<(reach-distance);
}

Ответ 2

Напишите функцию для циклического перехода по соседям:

  • Используйте min/max, чтобы закрепить границы матрицы.
  • Используйте цикл for для цикла по всем соседям.
  • Измените границы цикла для представления охвата.

:

def CalculateForceOnCell(x, y):
    force_on_x_y = [0,0,0,0]
    for i in range(max(0, x-reach), min(WIDTH, x+reach)+1):
        limited_reach = reach - abs(x-i)
        for j in range(max(0, y - limited_reach), min(HEIGHT, y + limited_reach + 1)):
            force_coefficient = limited_reach + 1
            AddNeighborForce(force_on_x_y, (x, y), (i, j), force_coefficient)
    return force_on_x_y