| 280 | | (defun map-nodes (function node &key (prune-test (constantly nil))) |
|---|
| 281 | | (funcall function node) |
|---|
| 282 | | (dotimes (i 4) |
|---|
| 283 | | (let ((child (child node i))) |
|---|
| 284 | | (when (and child (not (funcall prune-test child))) |
|---|
| 285 | | (map-nodes function child :prune-test prune-test))))) |
|---|
| 286 | | |
|---|
| 287 | | (defun find-node-if (test node &key (prune-test (constantly nil))) |
|---|
| | 280 | (defun map-nodes-internal (nodes function prune-test remove-node add-node) |
|---|
| | 281 | "Used by MAP-NODES for depth-first and breadth-first |
|---|
| | 282 | traversal. |
|---|
| | 283 | |
|---|
| | 284 | NODES is an opaque collection, that is accessed via the given |
|---|
| | 285 | functions REMOVE-NODE and ADD-NODE. |
|---|
| | 286 | |
|---|
| | 287 | REMOVE-NODE will be called with NODES and has to return two |
|---|
| | 288 | values: The removed node and the updated NODES. |
|---|
| | 289 | |
|---|
| | 290 | ADD-NODE will be called with a node to be added and NODES. It has |
|---|
| | 291 | to return the updated NODES. |
|---|
| | 292 | |
|---|
| | 293 | FUNCTION will be called on each visited node. |
|---|
| | 294 | |
|---|
| | 295 | If PRUNE-TEST returns true, the given node will not be visited." |
|---|
| | 296 | (labels ((pop* () |
|---|
| | 297 | (multiple-value-bind (node new-nodes) |
|---|
| | 298 | (funcall remove-node nodes) |
|---|
| | 299 | (setq nodes new-nodes) |
|---|
| | 300 | node)) |
|---|
| | 301 | (push* (node) |
|---|
| | 302 | (setq nodes (funcall add-node node nodes)))) |
|---|
| | 303 | (let ((node (pop*))) |
|---|
| | 304 | (when node |
|---|
| | 305 | (funcall function node) |
|---|
| | 306 | (dotimes (i 4) |
|---|
| | 307 | (let ((child (child node i))) |
|---|
| | 308 | (when (and child (not (funcall prune-test child))) |
|---|
| | 309 | (push* child)))) |
|---|
| | 310 | (map-nodes-internal nodes function prune-test remove-node add-node))))) |
|---|
| | 311 | |
|---|
| | 312 | (defun map-nodes-depth-first (function node prune-test) |
|---|
| | 313 | ;; nodes is here a stack |
|---|
| | 314 | (map-nodes-internal (list node) function prune-test |
|---|
| | 315 | (lambda (nodes) |
|---|
| | 316 | (values (car nodes) (cdr nodes))) |
|---|
| | 317 | (lambda (node nodes) |
|---|
| | 318 | (cons node nodes)))) |
|---|
| | 319 | |
|---|
| | 320 | (defun map-nodes-breadth-first (function node prune-test) |
|---|
| | 321 | ;; nodes is here a queue |
|---|
| | 322 | (let ((nodes (make-queue))) |
|---|
| | 323 | (enqueue node nodes) |
|---|
| | 324 | (map-nodes-internal nodes function prune-test |
|---|
| | 325 | (lambda (nodes) |
|---|
| | 326 | (values (dequeue nodes) nodes)) |
|---|
| | 327 | (lambda (node nodes) |
|---|
| | 328 | (enqueue node nodes) |
|---|
| | 329 | nodes)))) |
|---|
| | 330 | |
|---|
| | 331 | (defun map-nodes (function node &key (prune-test (constantly nil)) (order :depth-first)) |
|---|
| | 332 | (check-type order (member :depth-first :breadth-first)) |
|---|
| | 333 | (let ((mapper (case order |
|---|
| | 334 | (:depth-first #'map-nodes-depth-first) |
|---|
| | 335 | (:breadth-first #'map-nodes-breadth-first)))) |
|---|
| | 336 | (funcall mapper function node prune-test))) |
|---|
| | 337 | |
|---|
| | 338 | (defun find-node-if (test node &key (prune-test (constantly nil)) (order :depth-first)) |
|---|