3 (defstruct (node (:predicate nodep)
4 (:constructor make-node (word)))
5 (word (error "uninitialized slot") :type string :read-only t)
7 (up nil :type (or node null))
8 (down nil :type (or node null))
9 (right nil :type (or node null)))
11 (defun word-chain (stream)
12 (declare (optimize speed))
14 (let ((map (make-hash-table :test #'equal))
18 (let ((line (read-line stream nil)))
19 (unless line (return))
20 (setf (gethash line map) (make-node line))))
22 (maphash (lambda (word node)
23 (declare (type string word)
26 ;;(format t ";; contemplate `~A'~%" word)
27 (let ((parent (let ((len (length word)))
29 (gethash (subseq word 0 (1- len))
31 (nlen (node-len node)))
32 (setf (node-up node) parent)
34 (unless parent (return))
36 (let ((plen (node-len parent)))
37 ;;(format t ";; node `~A' ~D parent `~A' ~D~%"
38 ;; (node-word node) (1- nlen)
39 ;; (node-word parent) plen)
41 ;;(format t ";; longer chain through `~A'~%"
42 ;; (node-word (node-down parent)))
45 (setf (node-right node) (node-down parent)
46 (node-down parent) node)
49 ;;(format t ";; new longest chain ~A > ~A~%"
51 (setf (node-down parent) node
53 (node-len parent) nlen
55 parent (node-up node))))))
56 (when (> nlen max) (setf max nlen))))
59 (maphash (lambda (word node)
60 (declare (ignore word)
63 (when (= (node-len node) max)
64 (labels ((print-chain (node)
65 (cond ((null (node-right node))
66 (write-string (node-word node))
67 (let ((down (node-down node)))
74 (write-string (node-word node))
75 (let ((down (node-down node)))
79 (let ((right (node-right node)))
80 (unless right (return))
83 (write-string " }")))))
89 (let ((args (uiop:command-line-arguments))
92 (handler-bind ((warning #'muffle-warning))
93 (let ((*compile-verbose* nil))
94 (compile 'word-chain)))
96 (when (and args (>= (length (car args)) 2)
97 (string= (car args) "-T" :end1 2))
98 (let ((arg (pop args)))
99 (setf timing-out (if (= (length arg) 2) t
103 (setf t0 (get-internal-run-time)) ; warm cache
104 (setf t0 (get-internal-run-time)) ; start time
105 (setf t1 (get-internal-run-time)) ; overhead
106 (flet ((hack-file (path)
107 (cond ((string= path "-") (word-chain *standard-input*))
108 (t (with-open-file (stream path) (word-chain stream))))))
110 (word-chain *standard-input*))
112 (hack-file (car args)))
115 (format t "~A: " arg)
117 (setf t2 (get-internal-run-time)) ; final time
119 (flet ((write-time (stream)
120 (format stream "~,3F~%"
121 (/ (max 0 (+ t2 t0 (* -2 t1)))
122 internal-time-units-per-second))))
123 (cond ((eq timing-out t)
124 (write-string ";; time = ")
125 (write-time *standard-output*))
127 (with-open-file (stream timing-out
129 :if-does-not-exist :create
130 :if-exists :supersede)
131 (write-time stream)))))))