使用常见的lisp重新滚动选定的骰子,并使用用户输入保持未选中

时间:2016-06-19 23:50:25

标签: lisp common-lisp

我有这两个基本功能:

(defun dice ()
  (+ 1 (random 6)))

(defun five-dice ()
   (list (dice) (dice) (dice) (dice) (dice)))

他们所做的只是创建一个五个掷骰子的列表。我想要做的是选择一定数量的骰子再次滚动。意思是,我想选择2,3或全部五个再次滚动,并替换重新掷骰子,同时保留我决定不滚动的骰子。我想使用用户输入来做到这一点。

我的假设是,最好的方法是使用符号,但我已经尝试了大约一天,无法确定如何做到这一点。这就是我决定寻求帮助的原因。

编辑:谢谢大家的帮助,我真的很感激。我无法理解lisp如何接受用户输入,以及如何将其存储到变量中。

所以,我创建了一个全局变量,并将其用作用户的初始滚动,但是一旦我尝试使用来自用户的输入来重新滚动某些骰子,那就是我无法理解的部分。我看了几个例子,我试图重新创建它,但它不适合我:

(defun testfunction() (terpri) (princ "would you like to roll? ") (read-line) (if (member (read-line) '("y" "yes" "") :test #'string=) (let ((roll (five-dice))) )))

这就是我想要开始工作的事情,因此,在用户输入yes或y之后,它会给他们5个骰子,并且它会给他们3次机会重新掷出任意数量的骰子他们要。所以,这就是我目前正在努力开展的工作。

EDIT2:

(defun roll-again(lst) (if (null lst)nil (setf (nth (car lst) list-dices)(dice)) (yup (cdr lst)) ))

为什么这个功能不起作用?我现在要做的是使用此功能重新掷出用户选择的骰子。所以,一旦我从用户那里得到输入,我就把这个输入放到一个列表中,然后用这个函数来重新掷骰子。但是,由于某种原因,我无法使用此功能。

3 个答案:

答案 0 :(得分:2)

最简单的方法是使用MAPCAR浏览列表,询问用户是否要重新掷骰子。

(defun dice ()
  (1+ (random 6)))

(defun roll-dice (&optional (n 5))
  (let ((dice (loop repeat n collecting (dice))))
    (format *query-io* "Rolled: ~{~a~^, ~}." dice)
    (finish-output *query-io*)
    (mapcar (lambda (d)
              (if (y-or-n-p "Roll ~a again?" d)
                  (dice)
                  d))
            dice)))

修改

在你的编辑中,你说用户应该可以重复掷任意数量的骰子三次。这是一个允许他们这样做的版本:

(defun roll-dice (&optional (n 5))
  (loop with dice = (loop repeat n collecting (dice))
        for rolls-left from 3 downto 1
        while (y-or-n-p "Rolled: ~{~a~^, ~}.~@
                         Re-roll (~a re-roll~:*~p left)?"
                        dice rolls-left)
        do (map-into dice
                     (lambda (d)
                       (if (y-or-n-p "Roll ~a again?" d)
                           (dice)
                           d))
                     dice)
        finally (return dice)))

答案 1 :(得分:0)

我认为对于小清单,您最好的选择是访问列表中的元素并进行修改。例如,使用函数nth,如果你想修改你可以这样做的第二个元素:

CL-USER> (defparameter list-dices (five-dice))
LIST-DICES
CL-USER> list-dices
(1 5 2 3 2)
CL-USER> (setf (nth 1 list-dices) (dice))
2
CL-USER> list-dices
(1 2 2 3 2)

答案 2 :(得分:0)

像这样的东西可能适用于重新滚动:

(defun reroll-specific-dice (dice-list reroll-list)
  "Takes a list of dice results, and a list of dice indexes to reroll,
   returns a list of those dice, re-rolled. This function is non-destructive."
  (let ((dice-list (copy-list dice-list)))
    (loop for reroll-index in reroll-list
       do (setf (nth reroll-index dice-list) (dice)))
    dice-list))

这可以通过跳过let / copy-list来破坏,但非破坏性通常会更好。这也没有错误检查。它也不涉及从用户那里获取输入,因为以一种非常用户友好的方式做这件事是我没有时间写的。

对于“最小”用户输入,您可以执行以下操作:

(defun get-dice-to-reroll ()
  (format t "Provide a list of dice to reroll, between parentheses: ")
  (finish-output)
  (read))

同样,这只有最少的错误检查,但会返回一个适合作为reroll-list转发到reroll-specific-dice的列表。