Установка значений списка в числа в CL и последующая их проверка

Я играю в 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!")))

person Oso    schedule 17.12.2010    source источник
comment
+1 за название вашей игры. :-)   -  person Andrzej Doyle    schedule 17.12.2010


Ответы (2)


Вы вообще вводите не нули, а букву 'O'.

Другие примечания:

Не используйте DEFPARAMETER внутри DEFUN. Определите переменную на верхнем уровне, а внутри функции инициализации просто SETF ее .

Не используйте списки для произвольного доступа. Используйте массивы.

операторы числового сравнения будут сигнализировать об ошибке, если им будет присвоено нечисловое значение. Используйте EQL для общего сравнения.

person Ramarren    schedule 17.12.2010

Вот исправленная версия:

(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!")))
person Rainer Joswig    schedule 17.12.2010