2012-09-15 94 views
2

从Lisp开始,我试图从文件中读取矩阵来编程A星算法时遇到了一个问题。 我应该读取的文件在文件顶部有行数和列数,并且我必须将它们都保存在几个全局变量中(NM)。文件格式应该是这样的:用Lisp从文件中读取矩阵

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)))) 

我会,如果有人真的感谢可以帮助我。

+0

对不起,我不知道为什么格式有这种方式。 – user1673162

回答

2

有一堆错误。

  1. 你打开一个流,但从来没有关闭它
  2. 你叫PARSE-INTEGER上的字符,当它需要一个字符串
  3. ​​被调用的符号列表,但它应该是号码清单。

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

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会比现在更好。

+0

我在过去几天一直在使用cl-csv。它看起来很好,并处理所有这些特殊字符/角落案件。并不是说你在这里有任何东西,但是我会给这个包提供一个稳健性和效率的+1 –

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)))) 

第四个问题:使阵列形式的需求数量来设置它的尺寸,但你给它两个符号来代替。你需要评估这些符号,以获得您想要的值:

(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)))) 

第五个问题:看来您希望您的基质含有位,但你只把字符转换成它。最重要的是,你的矩阵甚至不会包含#\1(在字符),您期望1(在)和#\0,你期待一个0,而是以下(假定Unix风格的换行符) :

#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,并返回这个类的一个对象。