0

现在,我正在开发一个程序,该程序应该能够从 7 人(abcdefg)的列表中挑选 3 人并将他们指定为罪犯。然后这个“游戏”从 7 人中随机挑选 3 人,告诉你如何其中许多人是罪犯,并问你是否想猜测这三个罪犯是谁,有一个猜测(“这三个人中有两个是罪犯,你想猜测谁是罪犯)。但是,我目前有一个程序可以从列表中随机抽取 3 个罪犯,但是我遇到的困难是最初分配谁是罪犯(从列表中随机挑选 3 个并将它们分配给以后可以调用的值)然后能够将其打印出来。到目前为止,这是我的代码,我希望有人能指出我正确的方向,我'

;allows us to use prompt to ask the user for input
(defun prompt-read (prompt)
  (format *query-io* "~a: " prompt)
  (force-output *query-io*)
  (read-line *query-io*))

;allows you to add elements in needed spots
(defun element-at (org-list pos &optional (ini 1))
  (if (eql ini pos)
      (car org-list)
      (element-at (cdr org-list) pos (+ ini 1))))

(defun element-at (lista n)
  (if (= n 1)
      (first lista)
      (element-at (rest lista) (1- n))))

;allows for the removal of unneeded elements 
(defun remove-at (org-list pos &optional (ini 1))
  (if (eql pos ini)
      (cdr org-list)
      (cons (car org-list) (remove-at (cdr org-list) pos (+ ini 1)))))

;returns a chosen  number of random elements from a list
(defun rnd-select (org-list num &optional (selected 0))
  (if (eql num selected)
      nil
      (let ((rand-pos (+ (random (length org-list)) 1)))
        (cons (element-at org-list rand-pos) (rnd-select (remove-at org-list rand-pos) num (+ selected 1))))))

;returns 3 random criminals from a list of 7
(defun rnd-criminals ()
  (rnd-select '(a b c d e f g) 3))

(defun game ()
  (prompt-for-players))

;allows for the storing of number of players
(defun num-of-players(number)
  (list :number number))

;prompts for the amount of players you want to play
(defun prompt-for-players ()
  (num-of-players
   (or (parse-integer (prompt-read "How many players are there?"
                                   :junk-allowed t) 0))))
4

1 回答 1

2

这是一个没有替换问题的抽样(因为,我假设,你不想通过每次从列表中选择同一个人来“选择三个罪犯”)。有很多方法可以做到这一点。一种方法是生成索引,直到你有足够的不同索引。像这样的东西怎么样:

(defun pick (sequence n)
  "Return n elements chosen at random from the sequence."
  (do ((len (length sequence))  ; the length of the sequence
       (indices '())            ; the indices that have been used
       (elements '()))          ; the elements that have been selected
      ((zerop n)          ; when there are no more elements to select,
       elements)          ; return the elements that were selectd.
    (let ((i (random len)))       ; choose an index at random
      (unless (member i indices)  ; unless it's been used already
        (push i indices)          ; add it to the list of used indices
        (push (elt sequence i) elements) ; and grab the element at the index
        (decf n)))))                     ; and decrement n.

如果您不太熟悉do,可以使用递归方法,例如,使用本地递归函数:

(defun pick2 (sequence n &aux (len (length sequence)))
  (labels ((pick2 (indices elements n)
             (if (zerop n) ; if no more elements are needed, 
                 elements ; then return elements.
                 (let ((i (random len))) ; Otherwise, pick an index i.
                   ;; If it's been used before,
                   (if (member i indices) 
                       ;; then continue on with the same indices,
                       ;; elements, and n.
                       (pick2 indices elements n)
                       ;; else, continue with it in the list of
                       ;; indices, add the new element to the list of
                       ;; elements, and select one fewer elements
                       ;; (i.e., decrease n).
                       (pick2 (list* i indices)
                              (list* (elt sequence i) elements)
                              (1- n)))))))
    ;; Start the process off with no indices, no elements, and n.
    (pick2 '() '() n)))

另一种方法是基于从建议Reservoir Sampling的链表中有效地选择一组随机元素

于 2013-11-26T04:19:07.443 回答