(require 'cl)
(require 'calc)

(defvar *maze-operators* (list #'math-add #'math-sub #'math-mul #'math-div))

(defvar *maze-values*
'((a . "( 4, 1)")
(b . "( 3,-2)")
(c . "( 2, 5)")
(d . "( 1, 3)")
(e . "( 3,-5)")
(f . "( 1, 1)")
(g . "(10, 0)")
(h . "( 7,-3)")
(i . "( 2, 3)")))

(dolist (i *maze-values*) (setf (cdr i) (calc-eval (cdr i) 'raw)))

(defvar *maze-adjacency*
'((a . (b c d))
(b . (a c e f))
(c . (a b d e f g))
(d . (a c f g))
(e . (b c f h))
(f . (b c d e g h))
(g . (c d f h))
(h . (e f g i))
(i . (h))))

(defun valid (val)
(and (listp val)
(destructuring-bind (cplx x y) val
(and (eq cplx 'cplx)
(integerp x)    (integerp y)
(not (zerop x)) (not (zerop y))
(or (eql 1 (abs x)) (eql 1 (abs y)))))))

(defun successors (state)
(destructuring-bind (position value &rest history) state
(loop for newpos in (cdr (assq position *maze-adjacency*))
for operand = (cdr (assq newpos *maze-values*))
append (loop for op in *maze-operators*
for newval = (funcall op value operand)
if (valid newval)
collect (list* newpos newval
(list newpos op) history)))))

(defun finishing (state)
(destructuring-bind (position value &rest history) state
(if (eq position 'i)
(progn (print state t) t)
nil)))

(defun search (start)
(loop for queue = (list start) then queue
for state = (pop queue)
unless (finishing state)
do (setf queue (nconc queue (successors state)))
while queue))

(search (list 'a (calc-eval "(4,1)" 'raw)))