Во-первых, некоторые переформатирование:
(loop for e in entries do
(if (and (not (member e sub))
(not (member e col)))
(progn (setq choices (nconc choices (list e)))
(print choices)))
(if (= (length choices) 1)
(setq pick (car choices))
(if (not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
Тогда, если вам не нужен альтернативный раздел if
, но хотите progn
, вы можете использовать when
:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(if (= (length choices) 1)
(setq pick (car choices))
(if (not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
Последние два предложения if
являются взаимоисключающими, поэтому либо cond
, либо case
будет уместным (я буду использовать cond
на данный момент):
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
Существует zerop
предикат:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (+ 0 (length choices))) choices))))
Я не вижу, что добавление от 0 до некоторого значения следует выполнить:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices))))
Если вы не уверены, что pick
настроен на разумное значение по умолчанию для начала, возможно, у вас есть случай по умолчанию (это может быть одна из ваших проблем):
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil))
Вместо использования setq
и nconc
, вы можете использовать push
(это помещает новый элемент в начале списка, но так как вы выбираете случайным образом в любом случае, это не должно быть проблемой):
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(push e choices)
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil))
Я подозреваю, что в начале этого фрагмента, choices
должен быть ()
, что вам не нужно choices
после этого фрагмента кода, и что печать choices
только для отладки, так что вы могли бы сделать это по-другому по используя remove-if
и изменяющее это состояние:
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil)))
Если choices
печатаются как ()
сейчас, это означает, что нет выбора, оставленного здесь, так что вам придется сделать немного назад, то (или что-то ваш алгоритм делает, когда достигается тупик).
Наконец, поскольку (length choices)
может быть только неотрицательные целые числа, вы можете использовать case
вместо cond
, если проверить случаи в другом порядке:
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(case (length choices)
(0 (setq pick nil))
(1 (setq pick (car choices)))
(otherwise (setq pick (nth (random (length choices)) choices)))))
Update по запросу.
Как отмечает Райнер, это в основном тело функции pick
, поэтому мы можем избавиться от всех свободных переменных.Кроме того, вместо car
, вы можете использовать (для списков) более описательное имя first
:
(defun pick (entries sub col)
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(case (length choices)
(0 nil)
(1 (first choices))
(otherwise (nth (random (length choices)) choices)))))
Эта функция будет определена в другом месте, а вместо сниппета, это будет называться так:
(pick entries sub col)
чтобы не вычислять (length choices)
дважды, мы можем положить, что в let
(который должен стать let*
для последовательной оценки):
(defun pick (entries sub col)
(let* ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries))
(choices-length (length choices)))
(print choices)
(case choices-length
(0 nil)
(1 (first choices))
(otherwise (nth (random choices-length) choices)))))
Последний шаг (поистине необязательный, но, возможно, вы обнаружите, что у вас есть больше последовательностей, уменьшающих ваши варианты, например. row
) будет немного обобщением:
(defun pick (entries &rest exclusion-sequences)
(let* ((choices (remove-if (lambda (e)
(some #'identity
(mapcar (lambda (seq)
(member e seq))
exclusion-sequences)))
entries))
(choices-length (length choices)))
(print choices)
(case choices-length
(0 nil)
(1 (first choices))
(otherwise (nth (random choices-length) choices)))))
Вызов этой функции имеет ту же форму, но теперь вы можете использовать любое количество запретных последовательностей:
(pick entries col sub row ver ima fou)
Нет, записи - это список элементов, не найденных в sub и col. Col представляет столбец, в котором я находится в текущем цикле, а sub представляет собой подматрицу платы. Имея
как таблица, для итерации 3, col представляют (1 2 -1) и sub ((2 2 2) (3 3 -1)) – Manticore