LINUX.ORG.RU

Клеточный автомат замкнутый в тор - C++

 


0

1

Доброго времени суток, возникла проблема с написанием алгоритма для клеточного автомата. Вся проблема заключается в проверке соседей на сторонах и по углам массива. К примеру есть массива 10 на 10. Если брать клетки от 2 до 9 то все в порядке, т.к. соседи для них находятся по общему алгоритму. Но что делать со всеми четырьмя сторонами и углами? Писать отдельный алгоритм для них? Кроме глупого перебора ничего в голову не идет. Может кто-нибудь посмотрит на проблему со своей, свежей точки зрения и решение придет самой собой?)

Вот код для проверки соседа «внутренней» части масива. Он меня вполне устраивает.

 int neighbors = -M[i][j], k, m;
    for(k = i-1; k<=i+1; k++)
        for(m = j-1; m <= j+1; m++)
            neighbors += M[k][m];
А вот код который я написал для левого верхнего угла)
    if (i == 0 && j == 0)
    {
        if (M[0][N - 1])
            neighbors++;
        else if (M[N - 1][j])
            neighbors++;
        else if (M[i + 1][0])
            neighbors++;
        else if (M[0][j + 1])
            neighbors++;
    }
Я не хочу даже думать о том, что придется писать такой массивный и некрасивый код для каждого из углов и сторон. Надеюсь на вашу помощь.

По модулю считай индексы...

anonymous
()

M[(i+1)%N][j]

anonymous
()

Как тебе правильно сказали, используй оператор %. При этом желательно чтобы размеры решётки были константой, т.е. известны в compile-time и были степенью двойки. Тогда % превратится в побитовое «и».

utf8nowhere ★★★
()

И не забывайте, что в плюсах деление отрицательного числа по модулю дает отрицательное число. Т.е. лучше что то вроде

M[(i+di+N)%N][(j+dj+N)%N]

где di и dj могут быть -1,0,1.

AIv ★★★★★
()
Ответ на: комментарий от AIv

деление отрицательного числа по модулю

implementation-defined behaviour.

Нормальные люди использую size_t для индексации, у них нет проблем с (i-1)%N.

utf8nowhere ★★★
()
Ответ на: комментарий от utf8nowhere

Отличная идея! И что же мы получим в случае

size_t i = 0;
... M[(i-1)%N] ...

Наверное алгоритм будет работать неожиданным образом?

AIv ★★★★★
()
Ответ на: комментарий от utf8nowhere

использую size_t для индексации, у них нет проблем с (i-1)%N.

лол

i-rinat ★★★★★
()
Ответ на: комментарий от utf8nowhere

Ок, в случае N=2^n нет проблем, а другие N использовать накладно.

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

Но осмелюсь предположить, что ТС-у интересен алгоритм работающий для любых N, а не алгоритм оптимальный для N=2^n и неверный во всех остальных случаях. Ну просто те кому важны фенечки с оптимизацией такого уровня не задают таких вопросов;-)

AIv ★★★★★
()
Ответ на: комментарий от AIv

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

xxArchGoddesSxx
() автор топика
Ответ на: комментарий от xxArchGoddesSxx

Просто используйте везде

M[(i+di+N)%N][(j+dj+N)%N]
вместо
M[i+di][j+dj]
это как раз позволит не думать о границах. Поудмайте что будет например в случае i=0, di=-1. Или в случае i=N-1, di=1.

AIv ★★★★★
()

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

nikitos ★★★
()
Ответ на: комментарий от AIv

перевожу с русского на русский :-)

'AIv ★★★★★ (03.12.2016 23:32:46)'

И не забывайте, что в плюсах деление отрицательного числа по модулю дает отрицательное число. Т.е. лучше что то вроде

M[(x+dx+N)%N][(y+dy+N)%N]

M - матрица твоего квадратно-тороидного мира
N - размерность твоего квадратно-тороидного мира
x - текущая координата по горизонтали
dx - шаг по горизонтали, может быть отрицательным
y - текущая координата по вертикали
dy - шаг по вертикали, может быть отрицательным

важно, чтоб dx и dy были, по абсолютному значению, меньше размерности N

т.е. т.к. «в плюсах деление отрицательного числа по модулю дает отрицательное число», то приходится добавлять в формулах +N, которое гарантированно отправляет результат в область положительных чисел и, при этом, благополучно и гарантированно нивелируется операцией получения остатка от деления.

в некоторых языках такой финт ушами не требуется, например в tcl/tk:

% expr 105%80
25
$ expr 89%80
9
$ expr 81%80
1
% expr 80%80
0
% expr 79%80
79
% expr 55%80
55
% expr 1%80
1
% expr 0%80
0
% expr -1%80
79
% expr -5%80
75
% expr -33%80
47

а в плюсах - требуется +N, потому, что «в плюсах деление отрицательного числа по модулю дает отрицательное число».

anonymous
()
Ответ на: перевожу с русского на русский :-) от anonymous

кстати, точнее:

важно, чтоб x+dx и y+dy были, по абсолютному значению, меньше размерности N

для этого тебе лучше координаты считать отдельно

x=(x+dx+N)%N
y=(y+dy+N)%N

чтоб они не накопились в минусе, чтоб всегда было |x+dx|<N и |y+dy|<N
т.е. чтоб (x+dx+N) и (y+dy+N) были всегда положительными,
и только после этого обращаться по новому адресу

M[x][y]

а всё почему? правильно, потому, что «в плюсах деление отрицательного числа по модулю дает отрицательное число».

P.S. а вот прикинь, теперь, как нудно это всё было расписывать, а? зато, отвлёкся... короче, удачи тебе! :D

anonymous
()

В книге по шахматным алгоритмам - эту проблему предлагали решать - вот так: Сам массив хранения должен быть на 1 клетку больше, а границы обработки нет.

Silerus ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.