2

我从 Lisp 开始,尝试从文件中读取矩阵以对 A-star 算法进行编程时遇到了很大的问题。我应该阅读的文件在文件的顶部有行数和列数,我必须将两者保存在几个全局变量(NM)中。文件格式应该是这样的:

ROWS
5
COLUMNS
5
MATRIX
1 1 1 1 1
1 1 0 1 1
1 1 0 0 1
1 1 0 0 1
1 1 1 0 1
START
4 2
GOAL
4 4

我现在的代码是这样的(顺便说一句,这可能很蹩脚)

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (let ((in (OPEN file :DIRECTION :INPUT)))
    (read-line in nil) 
    (SETQ *N* (parse-integer (read-char in)))
    (read-line in nil)
    (read-line in nil)
    (SETQ *M* (parse-integer (read-line in)))
    (read-line in nil)
    (read-line in nil)
    (SETQ *Matrix* (MAKE-ARRAY '(*N* *M*) :initial-element 1))
    (loop for i from 0 to *N*
        do (loop for j from 0 to *M*
               do (SETF (AREF *Matrix* i j)
                    (read-char in))))
    (read-line in nil)
    (SETQ *Start* (read-line in))
    (read-line in nil)
    (SETQ *Goal* (read-line in))))

如果有人可以帮助我,我将不胜感激。

4

3 回答 3

2

有一堆错误。

  1. 你打开一个流,但从不关闭它
  2. 你调用PARSE-INTEGER一个字符,当它需要一个字符串时
  3. MAKE-ARRAY用符号列表调用,但它应该是数字列表。

另外:使用全局变量不是一个好主意。

于 2012-09-15T15:06:54.450 回答
1

第一个问题:您打开一个文件,但从不关闭它。使用时open,需要记住close之后。由于这很常见,因此有with-open-file, 会自动关闭(有关文档,请参阅 CLHS)。

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (with-open-file (in file
                      :direction :input)
    (read-line in nil) 
    (setq *N* (parse-integer (read-char in)))
    (read-line in nil)
    (read-line in nil)
    (setq *M* (parse-integer (read-line in)))
    (read-line in nil)
    (read-line in nil)
    (setq *Matrix* (make-array '(*N* *M*) :initial-element 1))
    (loop for i from 0 to *N*
        do (loop for j from 0 to *M*
               do (setf (aref *Matrix* i j)
                    (read-char in))))
    (read-line in nil)
    (setq *Start* (read-line in))
    (read-line in nil)
    (setq *Goal* (read-line in))))

第二个问题:read-char返回一个字符,并且parse-integer没有为一个字符定义。似乎您可以简单地阅读整行。

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (with-open-file (in file
                      :direction :input)
    (read-line in nil) 
    (setq *N* (parse-integer (read-line in)))
    (read-line in nil)
    (read-line in nil)
    (setq *M* (parse-integer (read-line in)))
    (read-line in nil)
    (read-line in nil)
    (setq *Matrix* (make-array '(*N* *M*) :initial-element 1))
    (loop for i from 0 to *N*
        do (loop for j from 0 to *M*
               do (setf (aref *Matrix* i j)
                    (read-char in))))
    (read-line in nil)
    (setq *Start* (read-line in))
    (read-line in nil)
    (setq *Goal* (read-line in))))

第三个问题:您似乎在需要的行之间丢弃了太多行。

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (with-open-file (in file
                      :direction :input)
    (read-line in nil) ; "ROWS"
    (setq *N* (parse-integer (read-line in)))
    (read-line in nil) ; "COLUMNS"
    (setq *M* (parse-integer (read-line in)))
    (read-line in nil) ; "MATRIX"
    (setq *Matrix* (make-array '(*N* *M*) :initial-element 1))
    (loop for i from 0 to *N*
        do (loop for j from 0 to *M*
               do (setf (aref *Matrix* i j)
                    (read-char in))))
    (read-line in nil) ; "START"
    (setq *Start* (read-line in))
    (read-line in nil) ; "GOAL"
    (setq *Goal* (read-line in))))

第四个问题:make-array 形式需要数字来设置它的维度,但是你给它两个符号。您需要评估这些符号以获得所需的值:

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (with-open-file (in file
                      :direction :input)
    (read-line in nil) ; "ROWS"
    (setq *N* (parse-integer (read-line in)))
    (read-line in nil) ; "COLUMNS"
    (setq *M* (parse-integer (read-line in)))
    (read-line in nil) ; "MATRIX"
    (setq *Matrix* (make-array (list *N* *M*) :initial-element 1))
    (loop for i from 0 to *N*
        do (loop for j from 0 to *M*
               do (setf (aref *Matrix* i j)
                    (read-char in))))
    (read-line in nil) ; "START"
    (setq *Start* (read-line in))
    (read-line in nil) ; "GOAL"
    (setq *Goal* (read-line in))))

第五个问题:您似乎希望矩阵包含位,但您只将字符放入其中。最重要的是,您的矩阵甚至不会包含您期望的(the number ) 和期望a 的#\1(the character ) ,而是包含以下 (假设 Unix 样式的换行符):1#\00

#2A((#\1 #\Space #\1 #\Space #\1)
    (#\Space #\1 #\Space #\1 #\Newline)
    (#\1 #\Space #\1 #\Space #\0)
    (#\Space #\1 #\Space #\1 #\Newline)
    (#\1 #\Space #\1 #\Space #\0))

为了完成你想要的,我建议读取矩阵行,然后将它们拆分为空格并解析字段。一个方便的库是split-sequence.

(defvar *N*)
(defvar *M*)
(defvar *Goal*)
(defvar *Start*)
(defvar *Matrix*)

(defun read-matrix (file)
  (with-open-file (in file
                      :direction :input)
    (read-line in nil) ; "ROWS"
    (setq *N* (parse-integer (read-line in)))
    (read-line in nil) ; "COLUMNS"
    (setq *M* (parse-integer (read-line in)))
    (read-line in nil) ; "MATRIX"
    (setq *Matrix* (make-array (list *N* *M*) :initial-element 1))
    (loop :for i :from 0 :to *N*
          :do (let* ((line (read-line in))
                     (fields (split-sequence:split-sequence #\Space line))))
                (loop :for field :in fields
                      :for j :upfrom 0
                      :do (setf (aref *matrix* i j)
                                (parse-integer field))))
    (read-line in nil) ; "START"
    (setq *Start* (read-line in))
    (read-line in nil) ; "GOAL"
    (setq *Goal* (read-line in))))

在这一点上,这应该“工作”,对于“工作”的一些价值(虽然我没有测试过)。

然而,大约 30 年前,使用全局变量来传递信息已被确立为不成熟的。将其引入更适合健壮程序的样式的第一步是从函数返回值。

(defun read-matrix (file)
  (let (n m goal start matrix)
    (with-open-file (in file
                        :direction :input)
      (read-line in nil) ; "ROWS"
      (setf n (parse-integer (read-line in)))
      (read-line in nil) ; "COLUMNS"
      (setf m (parse-integer (read-line in)))
      (read-line in nil) ; "MATRIX"
      (setf matrix (make-array (list n m) :initial-element 1))
      (loop :for i :from 0 :to n
            :do (let* ((line (read-line in))
                       (fields (split-sequence:split-sequence #\Space line))))
                  (loop :for field :in fields
                        :for j :upfrom 0
                        :do (setf (aref matrix i j)
                                  (parse-integer field))))
      (read-line in nil) ; "START"
      (setf start (read-line in))
      (read-line in nil) ; "GOAL"
      (setf goal (read-line in)))
    (values n m goal start matrix)))

我认为您真正需要的是一个结构或类,用于您在此处阅读的内容。它可能被称为game-state.

(defclass game-state ()
  ((rows :accessor rows :initarg :rows)
   (columns :accessor columns :initarg :columns)
   (goal :accessor goal :initarg :goal)
   (start :accessor start :initarg :start)
   (board :accessor board :initarg board)))

然后应该命名您的函数read-game-state并返回此类的对象。

于 2012-09-16T12:34:35.297 回答
0

让你开始的东西:

(defvar *rows*)
(defvar *columns*)
(defvar *goal*)
(defvar *start*)
(defvar *matrix*)

(defun parse-sequence (tokens parser &key (delimiter #\Space))
  (do ((start 0)
       (end (position delimiter tokens :start 0)
            (position delimiter tokens :start start))
       result)
      ;; you could also read from end to avoid reversing
      ;; I just find this to be more natural
      ((null end)
       (reverse
        (cons
         (funcall parser
                  (subseq tokens start (length tokens)))
                 result)))
    (setf result
          (cons (funcall parser
                         (subseq tokens start end)) result))
    (setf start (1+ end))))

(defun parse-matrix-source (file)
  (with-open-file (stream file :direction :input)
    (do ((line (read-line stream nil :eof)
               (read-line stream nil :eof))
         (matrix-row 0)
         (matrix-column 0 0)
         state)
        ((eq line :eof))
      (cond
        ((string= line "ROWS") (setf state '*rows*))
        ((string= line "COLUMNS") (setf state '*columns*))
        ((string= line "MATRIX") (setf state '*matrix*))
        ((string= line "START") (setf state '*start*))
        ((string= line "GOAL") (setf state '*goal*))
        ((eq state '*rows*) (setf *rows* (parse-integer line)))
        ((eq state '*columns*)
         (setf *columns* (parse-integer line)
               *matrix* (make-array (list *rows* *columns*)
                                    :initial-element 0)))
        ((eq state '*matrix*)
         (dolist (i (parse-sequence line 'parse-integer))
           (setf (aref *matrix* matrix-column matrix-row) i
                 matrix-column (1+ matrix-column)))
         (incf matrix-row))
        ((eq state '*start*)
         (setf *start* (parse-sequence line 'parse-integer)))
        ((eq state '*goal*)
         (setf *goal* (parse-sequence line 'parse-integer)))))))

(defun test-parse-matrix ()
  (parse-matrix-source #P"~/Projects/lisp-doodles/matrix.txt")
  (format t "rows: ~d, columns: ~d, goal: ~s, start: ~s~& matrix: ~s~&"
          *rows* *columns*  *goal* *start* *matrix*))

(test-parse-matrix)

但我会考虑一种更好的格式——在这种情况下,你很有可能找到一个已经能够解析它的库+将在未来提供更大的灵活性。即使是 CSV 或 INI 也会比你现在拥有的更好。

于 2012-09-15T16:09:21.840 回答