;; 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.
|#