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

2 番目の問題: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))))

3 番目の問題: 必要な行の間の行を破棄しすぎているようです。

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

第 4 の問題: make-array フォームは次元を設定するために数値を必要としますが、代わりに 2 つのシンボルを指定します。必要な値を取得するには、これらのシンボルを評価する必要があります。

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

5 番目の問題: 行列にビットを含めたいようですが、文字だけを入れます。その上、行列には​​ (数値)が期待される#\1(文字) と が期待される場所さえ含まれず、代わりに次の (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 に答える