「待ち行列 (queue)」のライブラリです。リストで実装した queue と配列で実装した ring-buffer が用意されています。詳しい説明は拙作のページ Common Lisp 入門: 構造体 をお読みくださいませ。
アーカイブファイル minlib.tar.gz をインストールする、または プログラムリスト にある以下の 4 つのファイルを、~/common-lisp/ 以下の適当なサブディレクトリ (たとえば queue など) に配置してください。
* (asdf:test-system :queue) ; compiling file ... 略 ... ----- test start ----- (QUEUE-P (SETQ Q (MAKE-QUEUE))) => T OK (RING-BUFFER-P Q) => NIL OK (QUEUE-EMPTYP Q) => T OK (QUEUE-COUNT Q) => 0 OK (DOTIMES (X 8 (QUEUE-COUNT Q)) (ENQUEUE Q X)) => 8 OK (QUEUE-EMPTYP Q) => NIL OK (QUEUE-FULLP Q) => NIL OK (QUEUE-PEEK Q) => 0 OK (LET ((A NIL)) (DOTIMES (X 4 (REVERSE A)) (PUSH (DEQUEUE Q) A))) => (0 1 2 3) OK (QUEUE-EMPTYP Q) => NIL OK (QUEUE-COUNT Q) => 4 OK (QUEUE-PEEK Q) => 4 OK (QUEUE-CLEAR Q) => 0 OK (QUEUE-EMPTYP Q) => T OK (QUEUE-COUNT Q) => 0 OK (QUEUE-PEEK Q) => NIL OK (RING-BUFFER-P (SETQ Q (MAKE-RING-BUFFER 8))) => T OK (QUEUE-P Q) => NIL OK (QUEUE-EMPTYP Q) => T OK (QUEUE-COUNT Q) => 0 OK (DOTIMES (X 8 (QUEUE-COUNT Q)) (ENQUEUE Q X)) => 8 OK (QUEUE-EMPTYP Q) => NIL OK (QUEUE-FULLP Q) => T OK (QUEUE-PEEK Q) => 0 OK (LET ((A NIL)) (DOTIMES (X 4 (REVERSE A)) (PUSH (DEQUEUE Q) A))) => (0 1 2 3) OK (QUEUE-EMPTYP Q) => NIL OK (QUEUE-COUNT Q) => 4 OK (QUEUE-PEEK Q) => 4 OK (QUEUE-CLEAR Q) => 0 OK (QUEUE-EMPTYP Q) => T OK (QUEUE-FULLP Q) => NIL OK (QUEUE-COUNT Q) => 0 OK (QUEUE-PEEK Q) => NIL OK ----- test end ----- TEST: 33 OK: 33 NG: 0 ERR: 0 T
;;; ;;; sample_queue.lisp : queue のサンプルプログラム ;;; ;;; Copyright (C) 2023 Makoto Hiroi ;;; ;;; Released under the MIT license ;;; https://opensource.org/license/mit/ ;;; (require :utils) (require :queue) (use-package :queue) ;;; ;;; 経路の探索 ;;; ;;; 隣接リスト (defvar *adjacent* '((A B C) (B A C D) (C A B E) (D B E F) (E C D G) (F D) (G E))) ;;; 幅優先探索 (defun breadth-first-search (start goal) (let ((q (make-queue))) (enqueue q (list start)) (do () ((queue-emptyp q)) (let ((path (dequeue q))) (if (eq (car path) goal) (print (reverse path)) (dolist (x (cdr (assoc (car path) *adjacent*))) (unless (member x path) (enqueue q (cons x path))))))))) ;;; ;;; 5 パズル ;;; ;;; 盤面 ;;; 0 1 2 ;;; 3 4 5 ;;; 隣接リスト (defvar *adjacent5* #((1 3) (0 2 4) (1 5) (0 4) (1 3 5) (2 4))) ;;; 駒の移動 (defun move-piece (board x s) (let ((new-board (copy-seq board))) (setf (aref new-board s) (aref new-board x) (aref new-board x) 0) new-board)) ;;; 解の表示 (defun print-answer (state) (when state (print-answer (third state)) (print (first state)))) (defun five-puz (start goal) (let ((que (make-ring-buffer (* 6 5 4 3))) (chk nil)) (enqueue que (list start (position 0 start) nil)) (push start chk) (do () ((queue-emptyp que)) (let* ((state (dequeue que)) (board (first state)) (space (second state))) (when (equalp board goal) (print-answer state) (return t)) (dolist (x (aref *adjacent5* space)) (let ((new-board (move-piece board x space))) (unless (member new-board chk :test #'equalp) (push new-board chk) (enqueue que (list new-board x state))))))))) ;;; 最長手数の局面を探す (defun five-puz-max () (let ((que (make-ring-buffer (* 6 5 4 3))) (chk nil) (start (list #(1 2 3 4 5 0) 5 0))) (enqueue que start) (push start chk) (do () ((queue-emptyp que)) (let* ((state (dequeue que)) (board (first state)) (space (second state)) (move (third state))) (dolist (x (aref *adjacent5* space)) (let* ((new-board (move-piece board x space)) (new-state (list new-board x (1+ move)))) (unless (member new-board chk :key #'car :test #'equalp) (push new-state chk) (enqueue que new-state)))))) (dolist (state (utils:take-while (lambda (xs) (= (third xs) (third (first chk)))) chk)) (format t "~d: ~s~%" (third state) (first state)))))
* (load "sample_queue.lisp") T * (breadth-first-search 'a 'g) (A C E G) (A B C E G) (A B D E G) (A C B D E G) NIL * (five-puz #(4 5 0 1 2 3) #(1 2 3 4 5 0)) #(4 5 0 1 2 3) #(4 0 5 1 2 3) #(0 4 5 1 2 3) #(1 4 5 0 2 3) #(1 4 5 2 0 3) #(1 0 5 2 4 3) #(1 5 0 2 4 3) #(1 5 3 2 4 0) #(1 5 3 2 0 4) #(1 5 3 0 2 4) #(0 5 3 1 2 4) #(5 0 3 1 2 4) #(5 2 3 1 0 4) #(5 2 3 1 4 0) #(5 2 0 1 4 3) #(5 0 2 1 4 3) #(0 5 2 1 4 3) #(1 5 2 0 4 3) #(1 5 2 4 0 3) #(1 0 2 4 5 3) #(1 2 0 4 5 3) #(1 2 3 4 5 0) T * (five-puz-max) 21: #(4 5 0 1 2 3) NIL
;;; ;;; queue.lsp : キュー ;;; ;;; Copyright (c) 2023 Makoto Hiroi ;;; ;;; Released under the MIT license ;;; https://opensource.org/license/mit/ ;;; (provide :queue) (defpackage :queue (:use :cl)) (in-package :queue) (export '(make-queue make-ring-buffer queue-p ring-buffer-p enqueue dequeue queue-peek queue-emptyp queue-fullp queue-count queue-clear)) ;;; メソッドの定義 (defgeneric enqueue (q x)) (defgeneric deenque (q)) (defgeneric queue-peek (q)) (defgeneric queue-emptyp (q)) (defgeneric queue-fullp (q)) (defgeneric queue-count (q)) (defgeneric queue-clear (q)) ;;; キューの定義 (defstruct queue (front nil) (rear nil) (size 0)) ;;; キューは空か? (defmethod queue-emptyp ((q queue)) (zerop (queue-size q))) ;;; キューは満杯か? (defmethod queue-fullp ((q queue)) nil) ;;; 要素数を返す (defmethod queue-count ((q queue)) (queue-size q)) ;;; キューを空にする (defmethod queue-clear ((q queue)) (setf (queue-front q) nil (queue-rear q) nil (queue-size q) 0)) ;;; データの挿入 (defmethod enqueue ((q queue) item) (let ((new-cell (list item))) (if (queue-emptyp q) ;; キューは空の状態 (setf (queue-front q) new-cell) ;; 最終セルを書き換える (setf (cdr (queue-rear q)) new-cell)) (setf (queue-rear q) new-cell)) (incf (queue-size q)) ;; item を返す item) ;;; データを取得 (defmethod dequeue ((q queue)) (unless (queue-emptyp q) (prog1 (pop (queue-front q)) (decf (queue-size q)) (when (queue-emptyp q) ;; キューは空になった (setf (queue-rear q) nil))))) ;;; 先頭の要素を返す (defmethod queue-peek ((q queue)) (unless (queue-emptyp q) (car (queue-front q)))) ;;; ;;; リングバッファ ;;; ;;; リングバッファの定義 (defstruct (ring-buffer (:constructor make-ring-buffer (size &aux (buffer (make-array size))))) (front 0) (rear 0) (count 0) size buffer) ;;; キューは空か? (defmethod queue-emptyp ((q ring-buffer)) (zerop (ring-buffer-count q))) ;;; キューは満杯か? (defmethod queue-fullp ((q ring-buffer)) (= (ring-buffer-count q) (ring-buffer-size q))) ;;; 要素数を返す (defmethod queue-count ((q ring-buffer)) (ring-buffer-count q)) ;;; 先頭データの参照 (defmethod queue-peek ((q ring-buffer)) (unless (queue-emptyp q) (aref (ring-buffer-buffer q) (ring-buffer-front q)))) ;;; キューを空にする (defmethod queue-clear ((q ring-buffer)) (setf (ring-buffer-rear q) 0 (ring-buffer-front q) 0 (ring-buffer-count q) 0)) ;;; データの挿入 (defmethod enqueue ((q ring-buffer) item) (unless (queue-fullp q) (setf (aref (ring-buffer-buffer q) (ring-buffer-rear q)) item) (incf (ring-buffer-count q)) (incf (ring-buffer-rear q)) (when (= (ring-buffer-rear q) (ring-buffer-size q)) (setf (ring-buffer-rear q) 0)) item)) ;;; データの取り出し (defmethod dequeue ((q ring-buffer)) (unless (queue-emptyp q) (prog1 (aref (ring-buffer-buffer q) (ring-buffer-front q)) (decf (ring-buffer-count q)) (incf (ring-buffer-front q)) (when (= (ring-buffer-front q) (ring-buffer-size q)) (setf (ring-buffer-front q) 0)))))
リスト : queue.asd (defsystem :queue :description "待ち行列 (queue, ring-buffer)" :version "0.1.0" :author "Makoto Hiroi" :license "MIT" :depends-on () :in-order-to ((test-op (test-op :queue_tst))) :components ((:file "queue")))
;;; ;;; queue_tst.lisp : queue のテスト ;;; ;;; Copyright (C) 2023 Makoto Hiroi ;;; ;;; Released under the MIT license ;;; https://opensource.org/license/mit/ ;;; (provide :queue_tst) (defpackage :queue_tst (:use :cl :queue :mintst)) (in-package :queue_tst) (export '(test)) (defvar q nil) (defun test () (initial) (run (queue-p (setq q (make-queue))) t) (run (ring-buffer-p q) nil) (run (queue-emptyp q) t) (run (queue-count q) 0) (run (dotimes (x 8 (queue-count q)) (enqueue q x)) 8) (run (queue-emptyp q) nil) (run (queue-fullp q) nil) (run (queue-peek q) 0) (run (let ((a nil)) (dotimes (x 4 (reverse a)) (push (dequeue q) a))) '(0 1 2 3)) (run (queue-emptyp q) nil) (run (queue-count q) 4) (run (queue-peek q) 4) (run (queue-clear q) 0) (run (queue-emptyp q) t) (run (queue-count q) 0) (run (queue-peek q) nil) ;; ring-buffer (run (ring-buffer-p (setq q (make-ring-buffer 8))) t) (run (queue-p q) nil) (run (queue-emptyp q) t) (run (queue-count q) 0) (run (dotimes (x 8 (queue-count q)) (enqueue q x)) 8) (run (queue-emptyp q) nil) (run (queue-fullp q) t) (run (queue-peek q) 0) (run (let ((a nil)) (dotimes (x 4 (reverse a)) (push (dequeue q) a))) '(0 1 2 3)) (run (queue-emptyp q) nil) (run (queue-count q) 4) (run (queue-peek q) 4) (run (queue-clear q) 0) (run (queue-emptyp q) t) (run (queue-fullp q) nil) (run (queue-count q) 0) (run (queue-peek q) nil) (final))
リスト : queue_tst.asd (defsystem :queue_tst :description "test for queue" :version "0.1.0" :author "Makoto Hiroi" :license "MIT" :depends-on (:mintst :queue) :components ((:file "queue_tst")) :perform (test-op (o s) (symbol-call :queue_tst :test)))