Мой подход был бы таким:
import random
def test_positions(L1, L2):
return any(a==b for a, b in zip(L1, L2))
def neighbours(L):
return [set([a, b]) for a, b in zip(L[:-1], L[1:])]
def test_neighbours(L1, L2):
return any(nb in neighbours(L2) for nb in neighbours(L1))
def pres_order(n, L):
result = [names[:]]
# random.shuffle(result[0]) # only needed for reording first row
for i in range(1, n):
result.append(names[:])
random.shuffle(result[-1])
while test_positions(result[-1], result[-2]) or test_neighbours(result[-1], result[-2]):
random.shuffle(result[-1])
return result
Идея состоит в том, чтобы сначала создать (случайным образом переупорядоченный (перемешанный)) вариант списка имен.
Затем добавитьследующая перемешанная версия - но перемешивайте снова и снова, пока не будут выполнены ваши два требования.
Добавляйте до длины списка == n.
Два требования реализованы в функциях test_...
.
Первый из них о позициях самоочевиден, я думаю.
Второй проверяет, появляются ли какие-либо соседи последнего ряда также как соседи в последнем, кроме одного ряда.
Для этого есть вспомогательная функция для созданиясписки соседних пар.
Обратите внимание, что функция set
в определении соседей будет предотвращать соседние пары имен в соседних строках независимо от их порядка. Если вы хотите запретить только точную копию пары (например, после [...'E', 'G',... ]
[...'G', 'E',... ]
должно быть разрешено, но [...'E', 'G',... ]
нет), вы можете просто оставить установленную функцию в стороне.
Пример:
names = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
for l in pres_order(5, names):
print(l)
# ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
# ['G', 'B', 'H', 'E', 'C', 'F', 'A', 'D']
# ['H', 'C', 'B', 'A', 'E', 'D', 'F', 'G']
# ['C', 'F', 'E', 'H', 'A', 'G', 'B', 'D']
# ['G', 'H', 'B', 'F', 'D', 'A', 'E', 'C']
Редактировать: Я только что понял, что первый ряд должен быть неизменным исходным списком. Поэтому я прокомментировал первый случай перемешивания;так что вы можете легко получить его обратно, если вам нужно.