0

現在、私は 7 人のリスト ( abcdefg) から 3 人を選び出し、犯罪者に割り当てるプログラムに取り組んでいます。この「ゲーム」は、7 人からランダムに 3 人を選び、その方法を説明しますそれらの人々の多くは犯罪者であり、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

これは置換問題のないサンプリングです (リストから毎回同じ人を選ぶことによって「3 人の犯罪者を選ぶ」ことは望ましくないと思います)。これを行う方法はたくさんあります。1 つの方法は、十分な数の個別のインデックスが得られるまでインデックスを生成することです。このようなものはどうですか:

(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 に答える