Если вы действительно хотите «как можно дальше друг от друга», то (1) держу пари, что вам не повезло, и (2) если бы это было достижимо, это, вероятно, привело бы к не очень случайным результатам.Но если все, что вы хотите, это «несколько далеко друг от друга», это не так уж плохо.Вот несколько вещей, которые вы можете сделать:
(1) Классифицировать позиции сетки в соответствии с четностью их координат x, y: то есть, являются ли они нечетными и четными.Разделите фотографии на четыре партии примерно одинакового размера.Теперь выберите из разных партий в соответствии с соотношением координат.Следующий код (который немного «умный»; извините) делает это, по модулю ошибок и опечаток.
System.Random rng = new System.Random();
for (int x=0; x<nx; ++x) {
for (int y=0; y<ny; ++y) {
k = ((x&1)<<1) + (y&1); // 0..3
int n_photos_in_batch = (n_photos+3-k) >> 2;
int photo_number = (rng.Next(0,n_photos_in_batch-1) << 2) + k;
// use this photo
}
}
Недостатки: ничего не делает, чтобы отодвинуть копии фотографии еще дальше от одногодругой, чем один шаг.Несколько уменьшает случайность, так как все копии любой данной фотографии будут в фиксированном подмножестве позиций;в некоторых контекстах это может быть видно и выглядеть довольно глупо.
Вариации: мы в основном покрываем сетку плитками 2х2 и ограничиваем диапазон фотографий, которые могут появляться в каждой плитке.Вы можете использовать большие плитки, или плитки различной формы, или расположить их по-другому.Например, если вы скажете k = ((x&1)<<1) ^ (y&3)
, вы получите плитки 2х2, расположенные в виде своего рода шестиугольника, что на самом деле, вероятно, лучше, чем в приведенной выше версии.
(2) Зацикливание позиций в вашей сетке (порядок растра будетсделайте, хотя могут быть и более лучшие альтернативы) и для каждой выберите фотографию, которая (а) уже не появляется слишком близко к позиции, на которую вы смотрите, и (б) в противном случае является случайной.Следующий код (опять же, по модулю ошибок и опечаток) делает что-то подобное, хотя для больших сеток вы можете захотеть сделать его более эффективным.
System.Random rng = new System.Random();
radius = MAX_RADIUS; // preferably not too big, so that the search isn't too slow
while ((2*radius+1)*(2*radius+1) >= n_photos) --radius; // gratuitously inefficient!
for (int x=0; x<nx; ++x) {
for (int y=0; y<ny; ++y) {
// which photos already appear too near to here?
System.Collections.BitArray unseen = new System.Collections.BitArray(n_photos,True);
for (x1=x-radius; x1<=x+radius; ++x1) {
for (int y1=y-radius; y1<=y+radius; ++y1) {
if (0 <= x1 && x1 < nx && 0 <= y1 && y1 < nx && (y1<y || (y1==y && x1<x))) {
unseen[photos[x1,y1]] = False;
}
}
}
// now choose a random one of them
int n_unseen = 0;
for (int i=0; i<n_photos; ++i) if (unseen[i]) ++n_unseen;
System.Debug.Assert(n_unseen>0, "no photos available");
int j = rng.Next(0,n_unseen-1);
for (int i=0; i<n_photos; ++i) {
if (unseen[i]) {
if (j==0) { photos[x,y] = i; break; }
--j;
}
}
}
}
Примечания: это намного дороже, чем вариант 1.проверка достоверности на x1, y1, конечно, здесь совершенно неэффективна.Так же и выбор радиуса.Однако очевидные, более эффективные их версии могут сломаться, если вы примете некоторые из вариантов, которые я собираюсь перечислить.Этот код, в его нынешнем виде, не будет ничего делать для разделения фотографий, если их меньше 9. Выбор радиуса на самом деле полностью поддельный, для порядка обхода сетки, который я использовал, потому что никогда не бывает больше 2r.^ 2 + 2r «исключенных» позиций;опять же, это может измениться, если вы пересекаете сетку в другом порядке.И т. Д.
Вариации: нет реальной причины, по которой регион, по которому вы ведете поиск, должен быть квадратным.Циркуляр вполне может быть лучше, например.Вы можете, проделав дополнительную работу, построить регион, в котором всегда будет ровно столько точек, сколько у вас фотографий (хотя, если вы это сделаете, вы получите в основном периодический шаблон фотографий, так что лучше быть немного менее агрессивным).Возможно, было бы лучше обрабатывать элементы сетки в другом положении - например, по спирали от центра.
(3) Вариант 2 выше сохранит фотографии уникальными в определенном диапазоне (примерно настолько большом, насколько это возможно).учитывая, сколько у вас есть разных фотографий), но вам не нужно хранить копии подальше от этого.Вместо этого вы могли бы решить, насколько плохо иметь две одинаковые фотографии на любом заданном расстоянии, а затем выбрать фотографии, чтобы минимизировать общее количество ошибок.Это будет даже дороже, чем вариант 2. Я не буду давать пример кода;Вы, вероятно, можете понять, как это сделать.
[ИЗМЕНЕНО, чтобы добавить ...]
(4) Вот милая вариация на тему (1).Он будет работать лучше всего, когда сетка квадратная, а ее размер равен степени 2, но вы можете адаптировать ее для более общей работы.Это занимает время, пропорциональное размеру вашей сетки, сколько бы фотографий у вас ни было.Для каждой позиции (x, y): выбросить все, кроме нижних k битов координат, для некоторого k.Обращайте их по битам и чередуйте биты, задавая число m от 0 до 2 ^ (2k) -1.Выберите k так, чтобы это было где-то порядка, скажем, n_photos / 4.Теперь в позиции (x, y) вы поместите номер фотографии вокруг (n_photos * m / 2 ^ (2k) + smallish_random_number).Я оставлю вам несколько деталей для заполнения: -).