【问题标题】:Setting List Values to Numbers in CL, and Subsequently Checking Them将列表值设置为 CL 中的数字,然后检查它们
【发布时间】:2010-12-17 11:57:54
【问题描述】:

我正在玩 CL,在尝试制作完整的二维版本之前制作一维版本的战舰,但我遇到了问题。为了检查船是否在那里,我用零表示它,当一个点被击中时,我用星号替换它,所以我可以用numberp 检查列表。但是,当我运行(new-game) 时,它立即完成,这告诉我我没有正确输入零,因此它们被识别为数字。我究竟做错了什么?我知道这一定是菜鸟的错误。

;;;; Suez-Canal.lisp
;;;;
;;;; A simple, 1-Dimensional version of Battleship
;;;; The computer places a boat randomly, and you must sink it.

(setf *random-state* (make-random-state t))
(defparameter *boat-length* 3)
(defparameter *canal-length* 10)
(defparameter *shots-fired* 0)

(defun new-game ()
  (init-canal *canal-length*)
  (place-boat)
  (game-loop)
  (format t "It took you ~a shots to sink the boat." *shots-fired*))

(defun init-canal (len)
  (defparameter *canal* (make-list len)))

(defun place-boat ()
  (let ((pos (random-spot)))
    (setf (nth pos *canal*) 'O)
    (setf (nth (+ pos 1) *canal*) 'O)
    (setf (nth (+ pos 2) *canal*) 'O)))

(defun random-spot ()
  (let ((x (random 7)))
    x))

(defun game-loop ()
  (loop until (notany #'numberp *canal*)
       do (progn
        (prompt-for-guess)
        (check-guess (read-guess))
        (incf *shots-fired*))))

(defun prompt-for-guess ()
  (format t "~&Enter in a number between 1 and 10 to fire a shot.~&"))

(defun read-guess ()
  (parse-integer (read-line *query-io*) :junk-allowed t))

(defun check-guess (guess)
  (if (and (<= guess 9)
      (>= guess 0))
      (fire-shot guess)
      (progn
        (format t "~&Invalid selection~&")
        (check-guess (read-guess)))))

(defun fire-shot (pos)
  (if (= (nth (- pos 1) *canal*) 0)
      (progn
        (setf (nth (- pos 1) *canal*) #\*)
        (print "Hit!"))
      (print "Miss!")))

【问题讨论】:

  • +1 为您的游戏名称。 :-)

标签: lisp common-lisp clisp


【解决方案1】:

您输入的根本不是零,而是字母“O”。

其他说明:

不要在DEFUN 中使用DEFPARAMETER。在顶层定义变量,并在初始化函数内部 SETF 它。

不要使用列表进行随机访问。使用arrays

Numerical comparison operators 将在给定非数字值时发出错误信号。使用EQL 进行一般比较。

【讨论】:

    【解决方案2】:

    这是一个更正的版本:

    (setf *random-state* (make-random-state t))
    (defparameter *boat-length* 3)
    (defparameter *canal-length* 10)
    (defparameter *shots-fired* 0)
    
    ;;; you need to declare *canal* at toplevel.
    (defparameter *canal* nil)
    
    (defun new-game ()
      (init-canal *canal-length*)
      (place-boat)
      (game-loop)
      (format t "It took you ~a shots to sink the boat." *shots-fired*))
    
    ;;; just set the the variable.
    (defun init-canal (length)
      (setq *canal* (make-list length)))
    
    ;;; you need to set those positions to 0 and not to O
    (defun place-boat ()
      (let ((pos (random-spot)))
        (setf (nth pos       *canal*) 0)
        (setf (nth (+ pos 1) *canal*) 0)
        (setf (nth (+ pos 2) *canal*) 0)))
    
    ;;; no need for a LET
    (defun random-spot ()
      (random 7))
    
    ;;; no need for progn
    ;;; you could also replace UNTIL NOTANY with WHILE SOME
    (defun game-loop ()
      (loop until (notany #'numberp *canal*)
           do
           (prompt-for-guess)
           (check-guess (read-guess))
           (incf *shots-fired*)))
    
    (defun prompt-for-guess ()
      (format t "~&Enter in a number between 1 and 10 to fire a shot.~&"))
    
    (defun read-guess ()
      (parse-integer (read-line *query-io*) :junk-allowed t))
    
    ;;; <= can take more than two arguments
    ;;; typically this recursive version might be replaced with a LOOP
    (defun check-guess (guess)
      (if (<= 0 guess 9)
          (fire-shot guess)
        (progn
          (format t "~&Invalid selection~&")
          (check-guess (read-guess)))))
    
    ;;; use EQL, = only compares numbers
    (defun fire-shot (pos)
      (if (eql (nth (- pos 1) *canal*) 0)
          (progn
            (setf (nth (- pos 1) *canal*) #\*)
            (print "Hit!"))
          (print "Miss!")))
    

    【讨论】:

      猜你喜欢
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      • 2014-04-29
      • 2022-11-14
      • 1970-01-01
      • 2020-04-07
      • 2020-10-16
      • 2021-01-29
      相关资源
      最近更新 更多