#!/bin/sh /usr/local/bin/lminsh

; Magic squares, from Robert van Engelen's tinylisp.

; wrap-around increment/decrement n within m
(defun inc-wrap ("integer" n "integer" m) (mod (+ n 1) m))
(defun dec-wrap ("integer" n "integer" m) (mod (+ n m -1) m))

; global data
(define square-size 0)
(define square ())

; make an empty square
(defun make-square ()
    (let*
	(s (vector square-size))
	(mapcar
	    (lambda (i) (vector-set! s i (vector square-size 0)))
	    (seq 0 square-size)
	)
	s
    )
)

; set square at (row,col) with key value
(defun square! ("integer" row "integer" col "integer" key)
    (vector-set! (vector-get square row) col key)
)

; true if square at (row,col) is set
(defun square? ("integer" row "integer" col)
    (< 0 (vector-get (vector-get square row) col))
)

; populate the magic square
(defun build-square ()
    (let*
	(row 0)
	(col (/ (- square-size 1) 2))
	(key 0)
	(while (< key (* square-size square-size))
	    (setq! key (+ key 1))
	    (square! row col key)
	    (let*
		(row-1 (dec-wrap row square-size))
		(col-1 (dec-wrap col square-size))
		(if (square? row-1 col-1)
		    (setq! row (inc-wrap row square-size))
		    (progn
			(setq! row row-1)
			(setq! col col-1)))))))

; display the magic square
(defun show-square ()
	(mapcar
	    (lambda (i)
		(write-line (vector-get square i))
	    )
	    (seq 0 square-size)
	)
)

; create a new magic square -- size must be an odd number!!
(defun magic ("integer" size)
    (progn
	(if (even? size) (err "size must be odd"))
	(setq! square-size size)
	(setq! square (make-square size))
	(build-square)
	(show-square)
	'done))

(magic (parse-integer (first args)))
