;; lib/minikanren/queens.sx — N-queens via ino + all-distincto + project.
;;
;; Encoding: q = (c1 c2 ... cn) where ci is the column of the queen in
;; row i. Each ci ∈ {1..n}; all distinct (no two queens share a column);
;; no two queens on the same diagonal (|ci - cj| ≠ |i - j| for i ≠ j).
;;
;; The diagonal check uses `project` to escape into host arithmetic
;; once both column values are ground.

(define
  safe-diag
  (fn
    (a b dist)
    (project (a b) (if (= (abs (- a b)) dist) fail succeed))))

(define
  safe-cell-vs-rest
  (fn
    (c c-row others next-row)
    (cond
      ((empty? others) succeed)
      (:else
        (mk-conj
          (safe-diag c (first others) (- next-row c-row))
          (safe-cell-vs-rest c c-row (rest others) (+ next-row 1)))))))

(define
  all-cells-safe
  (fn
    (cols start-row)
    (cond
      ((empty? cols) succeed)
      (:else
        (mk-conj
          (safe-cell-vs-rest
            (first cols)
            start-row
            (rest cols)
            (+ start-row 1))
          (all-cells-safe (rest cols) (+ start-row 1)))))))

(define
  range-1-to-n
  (fn
    (n)
    (cond
      ((= n 0) (list))
      (:else (append (range-1-to-n (- n 1)) (list n))))))

(define
  ino-each
  (fn
    (cols dom)
    (cond
      ((empty? cols) succeed)
      (:else (mk-conj (ino (first cols) dom) (ino-each (rest cols) dom))))))

(define
  queens-cols
  (fn
    (cols n)
    (let
      ((dom (range-1-to-n n)))
      (mk-conj
        (ino-each cols dom)
        (all-distincto cols)
        (all-cells-safe cols 1)))))
