;; author: Tayssir John Gabbour #| This is only a commentary version of my earlier submission. I think it would be somewhat immoral for people to have to read that version I just sort of whipped up, but you're definitely free to refer to it as I criticize it. My background is that I have about a year of experience in Lisp, and learned Scheme before that. Incidentally, I just watched these two videos, which influenced me: http://www.archive.org/movies/details-db.php?collection=opensource_movies&collectionid=AV_Geek_Skip_20021212071234&PHPSESSID=d9de32ce5c3acf73e1f3663f7c6ecd38 http://www.archive.org/movies/details-db.php?collection=opensource_movies&collectionid=AV_Geek_Skip_20021212061248 |# (defconstant +lines+ '((p0 p5 p8 p10) (p0 p1) (p0 p3 p7 p9) (p0 p2 p4 p6) (p1 p2 p3 p5) (p1 p4 p7 p8) (p1 p6 p9 p10))) #| I made a small misstep previous to this, where I drew out something silly like: (p0 p10 (p5 p8)) ... where the points within the line were listed off to the side, but after I drew out a line of that, I looked at the drawing and realized it was not particularly clear-minded of me. All that matters is defining LEGAL-TRIANGLE? as we see below, so any extra complexity was pointless. |# (defconstant +points+ '(p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10)) #| Hack. Generated by a format statement. Maybe smarter to generate from +lines+, but whatever. Blah. |# (defun colinear? (&rest points) (loop for line in +lines+ thereis (every (lambda (p) (member p line)) points))) #| This test for colinearity is different from my submitted version. It's generalized to any number of points. I tend not to generalize immediately out of some YAGNI (you ain't gonna need it) complex. Also it had unfortunate parameter names like blah1, which is what I tend to name things. One reason why I like the separation of variable/function namespaces is that I get to name two things blah... |# (defun legal-triangle? (pt1 pt2 pt3) (and (colinear? pt1 pt2) (colinear? pt1 pt3) (colinear? pt2 pt3) (not (colinear? pt1 pt2 pt3)))) #| My earlier version of legal-triangle was not specified so neatly. Its last clause broke a level of abstraction by not talking in terms of colinearity. Talked about data structures instead, unfortunately. |# (defun all-triples (points) "Generate all unordered permutations of three points." (loop for sublist on points for i = (first sublist) nconc (loop for sublist2 on (rest sublist) for j = (first sublist2) nconc (loop for sublist3 on (rest sublist2) for k = (first sublist3) collect (list i j k))))) #| One big insane list of triples. What I get for not familiarizing myself with things like lazy eval or permutations. But whatever, it's just something I kicked out. |# (defparameter *answers* (loop for i in (all-triples +points+) when (apply #'legal-triangle? i) collect i)) #| Tada. For any triple which is a legal triangle, save it. |# (format t "~&Number of triangles: ~A. ~%Triangles: ~{~A ~}" (length *answers*) *answers*) (test:test-now! (equal *answers* '((p0 p1 p2) (p0 p1 p3) (p0 p1 p4) (p0 p1 p5) (p0 p1 p6) (p0 p1 p7) (p0 p1 p8) (p0 p1 p9) (p0 p1 p10) (p0 p2 p3) (p0 p2 p5) (p0 p3 p5) (p0 p4 p7) (p0 p4 p8) (p0 p6 p9) (p0 p6 p10) (p0 p7 p8) (p0 p9 p10) (p1 p2 p4) (p1 p2 p6) (p1 p3 p7) (p1 p3 p9) (p1 p4 p6) (p1 p5 p8) (p1 p5 p10) (p1 p7 p9) (p1 p8 p10))) ) #| The test harness which I wrote has some features which can't be seen here. It can instrument functions, so it can tell you what the parameters were if a statement turns out false. Also it watches out for signals like warnings and errors. |#