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

StackOverflow https://stackoverflow.com/questions/4470211

  •  11-10-2019
  •  | 
  •  

Вопрос

Я играю в 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!")))
Это было полезно?

Решение

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

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

Не используй Defparameter внутри Деф. Анкет Определите переменную на верхнем уровне и внутри функции инициализации. Setf Это.

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

Численные операторы сравнения будет сигнализировать об ошибке при получении ненужного значения. Использовать Экл Для общих сравнений.

Другие советы

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

(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!")))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top