anchor.diff: -(ql:quickload :rt)
  -
   (defun range (n)
     "Returns a list with elements 0 to N-1."
     (let (range) (dotimes (i n (nreverse range)) (push i range))))
  
positive.code: (defun sum (seq)
    "Returns the numeric sum of a sequence."
    (reduce #'+ seq))
  
  (defun row (array row-index)
    "Returns the row of ARRAY at index ROW-INDEX as a vector."
  
negative.code:                       (array-dimension square 1))
                  :initial-contents new-rows)))
  
  (defun mirror-square (square &key (axis :horizontal))
    "Returns a mirror image of SQUARE rotated around a vertical axis."
    (ecase axis
      (:horizontal
       (make-array (list (array-dimension square 0)
                         (array-dimension square 1))
                   :initial-contents (mapcar #'nreverse (rows square))))
      (:vertical
       (make-array (list (array-dimension square 0)
                         (array-dimension square 1))
                   :initial-contents (nreverse (rows square))))
      (:diagonal
       (mirror-square
        (rotate-square
         (make-array (list (array-dimension square 0)
                           (array-dimension square 1))
                     :initial-contents (rows square)))
        :axis :horizontal))))
  
  ;;; normalize-square is sort of a mess -- i think it's correct for 3x3 though
  (defun normalize-square (square)
    "Returns the normalized version of SQUARE.
  
  Normalized is when the lowest corner digit is in the upper-right, with the next
  lowest in the mid-upper. If no corners are set, mid-upper is key one, mid-left
  is key two."
    (let ((norm-square (copy-square square))
          (num-rows (array-dimension square 0))
          (num-cols (array-dimension square 1)))
      ;; todo: generalize the function
      (unless (and (= 3 num-rows) (= 3 num-cols)) (error "limit 3x3 for now"))
      (let ((corners (list (aref square 0 0)
                           (aref square 2 0)
                           (aref square 2 2)
                           (aref square 0 2)))
            (middles (list (aref square 0 1)
                           (aref square 1 2)
                           (aref square 2 1)
                           (aref square 1 0))))
        (flet ((lowest-position (sequence)
                 (position (apply #'min (remove-if #'zerop sequence)) sequence))
               (needs-mirror (square)
                 (cond
                   ((or (plusp (aref square 0 1))
                        (plusp (aref square 1 0)))
                    (or (zerop (aref square 0 1))
                        (and (plusp (aref square 1 0))
                             (> (aref square 0 1) (aref square 1 0)))))
                   ((or (plusp (aref square 0 2))
                        (plusp (aref square 2 0)))
                    (or (zerop (aref square 0 2))
                        (and (plusp (aref square 2 0))
                             (> (aref square 0 2) (aref square 2 0)))))
                   ((or (plusp (aref square 1 2))
                        (plusp (aref square 2 1)))
                    (or (zerop (aref square 1 2))
                        (and (plusp (aref square 2 1))
                             (> (aref square 1 2) (aref square 2 1))))))))
          (if (remove-if #'zerop corners)
              (dotimes (i (lowest-position corners))
                (setf norm-square (rotate-square norm-square)))
              (when (remove-if #'zerop middles)
                (dotimes (i (lowest-position middles))
                  (setf norm-square (rotate-square norm-square)))))
          (when (needs-mirror norm-square)
            (setf norm-square (mirror-square norm-square :axis :diagonal))))
        norm-square)))
  
  (defun square= (square-1 square-2)
    (string= (write-to-string square-1) (write-to-string square-2)))
  
  (defun square-equiv (square-1 square-2)
    (square= (normalize-square square-1) (normalize-square square-2)))
  
  (rt:deftest copy-square-test
      (let ((square #2a ((1 2 3)
                         (4 5 6)
                         (7 8 9))))
        (square= (copy-square square) square)) t)
  
  (rt:deftest rotate-square-clockwise
      (let ((square-1 #2a ((1 2 3)
                           (4 5 6)
                           (7 8 9)))
            (square-2 #2a ((7 4 1)
                           (8 5 2)
                           (9 6 3))))
        (square= (rotate-square square-1) square-2)) t)
  
  (rt:deftest mirror-square-horizontally
      (let ((square-1 #2a ((1 2 3)
                           (4 5 6)
                           (7 8 9)))
            (square-2 #2a ((3 2 1)
                           (6 5 4)
                           (9 8 7))))
        (square= (mirror-square square-1) square-2)) t)
  
  (rt:deftest normalize-square-1
      (let ((square-1 #2a ((1 4 7)
                           (2 5 8)
                           (3 6 9)))
            (square-2 #2a ((1 2 3)
                           (4 5 6)
                           (7 8 9))))
        (square= (normalize-square square-1) square-2)) t)
  
  (rt:deftest normalize-square-2
      (let ((square-1 #2a ((0 0 9)
                           (0 0 0)
                           (0 0 4)))
            (square-2 #2a ((4 0 9)
                           (0 0 0)
                           (0 0 0))))
        (square= (normalize-square square-1) square-2)) t)
  
  (rt:deftest normalize-square-3
      (let ((square-1 #2a ((0 0 0)
                           (0 0 2)
                           (0 4 0)))
            (square-2 #2a ((0 2 0)
                           (4 0 0)
                           (0 0 0))))
        (square= (normalize-square square-1) square-2)) t)
  
  (defparameter *perfect-square* #2a ((8 1 6)
                                      (3 5 7)
                                      (4 9 2)))
  (defparameter *wrong-square* #2a ((5 6 4)
                                    (9 7 8)
                                    (1 2 3)))
  
  ;; actual magic squares tests (not just matrix junk)
  
  (rt:deftest magic-square
      (magic-square-p *perfect-square*) t)
  