一次一个地为变量分配随机值并在LISP中使用该信息

时间:2013-11-26 01:24:11

标签: lisp common-lisp lispworks

现在我正在制作一个应该能够从7(abcdefg)列表中选出3个人的程序,然后将它们分配给犯罪分子。这个“游戏”然后从7个中选出3个随机的peolpe,告诉你这些人中有多少人是犯罪分子,并询问你是否想猜猜这三个罪犯是谁,只猜一猜(“这三个人中有两个是犯罪分子,你想猜猜犯罪分子是谁)。但是,我目前有一个程序可以从列表中抽取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))))

1 个答案:

答案 0 :(得分: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)))

另一种方法是基于Efficiently selecting a set of random elements from a linked list,建议Reservoir Sampling