(defparameter *segments* '((p0 (p1) (p2 p4 p6) (p3 p7 p9) (p5 p8 p10)) (p1 (p2 p3 p5) (p4 p7 p8) (p6 p9 p10)) (p2 (p3 p5) (p4 p6)) (p3 (p5) (p7 p9)) (p4 (p7 p8) (p6)) (p5 (p8 p10)) (p6 (p9 p10)) (p7 (p8) (p9)) (p8 (p10)) (p9 (p10)) (p10))) ;; A dynamic variable to hold to final solution (defvar *triangles*) ;; Removes sub-lists from a list (eg, (a (b) c) => (a b c) (defun explode (object) (when object (if (listp object) (append (explode (car object)) (explode (cdr object))) (list object)))) ;; Loops from a given point over all the possible connections to it (defun map-segments (p1 rest) (let ((links (explode rest))) (loop for segment in rest collect ; gather all the sub points along a segment (loop for p2 in segment do ; find all the points connected to p2 from the list (loop for p3 in (explode (cdr (assoc p2 segments))) collect ; only connect p1->p2->p3 if p1 can reach p3 ; and p2->p3 are not on the same line segment (when (and (not (member p3 segment)) (member p3 links)) (push (list p1 p2 p3) *triangles*))))))) ;; Sets the global return value and calls map-segment once for each point (defun find-triangles () (let ((*triangles* nil)) (loop for connections in *segments* do (map-segments (first connections) (rest connections))) ; return the final list of all triangles found (reverse *triangles*)))