Достаточно простым решением было бы взять список атрибутов и выполнить на нем случай Фишера-Йейтса .
Вы можете создать функцию, которая возвращает новый список, содержащий перемешанный элементы списка атрибутов. Приведенная ниже функция shuffle
выбирает случайный элемент из списка ввода и ограничивает его результатом перетасовки оставшихся элементов.
Затем вы можете использовать функцию subseq
, чтобы получить необходимое количество элементов из перетасованный список:
(defvar *pirate-attributes*
(list "has a pirate costume"
"has a wooden leg"
"has a ball"
"has a parrot"
"has a monkey"
"has a saber"
"has an eye patch"
"has a bottle of rum"))
(defun shuffle (xs)
(if (or (null xs)
(null (cdr xs)))
xs
(let* ((i (random (length xs)))
(x (nth i xs)))
(cons x (shuffle (append (subseq xs 0 i)
(subseq xs (1+ i))))))))
(defun select-random-n (xs n)
(subseq (shuffle xs) 0 n))
Пример взаимодействия REPL:
CL-USER> (select-random-n *pirate-attributes* 3)
("has a bottle of rum" "has a pirate costume" "has an eye patch")
CL-USER> (select-random-n *pirate-attributes* 3)
("has an eye patch" "has a ball" "has a bottle of rum")
CL-USER> (select-random-n *pirate-attributes* 2)
("has a monkey" "has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a ball" "has a saber" "has an eye patch" "has a wooden leg"
"has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a wooden leg" "has a monkey" "has a ball" "has a pirate costume"
"has a parrot")