;; lib/minikanren/tests/queens-fd.sx — N-queens via CLP(FD).
;;
;; Native FD propagation makes N-queens tractable: 4-queens finds both
;; solutions instantly; 5-queens finds all 10 in seconds. Compare with
;; the naive enumerate-then-filter version in queens.sx, which struggles
;; past N=4.

(define
  fd-no-diag
  (fn
    (ci cj k)
    (fresh
      (a b)
      (fd-plus cj k a)
      (fd-plus ci k b)
      (fd-neq ci a)
      (fd-neq cj b))))

(define
  n-queens-4-fd
  (fn
    (cs)
    (let
      ((c1 (nth cs 0))
        (c2 (nth cs 1))
        (c3 (nth cs 2))
        (c4 (nth cs 3)))
      (mk-conj
        (fd-in c1 (list 1 2 3 4))
        (fd-in c2 (list 1 2 3 4))
        (fd-in c3 (list 1 2 3 4))
        (fd-in c4 (list 1 2 3 4))
        (fd-distinct cs)
        (fd-no-diag c1 c2 1)
        (fd-no-diag c1 c3 2)
        (fd-no-diag c1 c4 3)
        (fd-no-diag c2 c3 1)
        (fd-no-diag c2 c4 2)
        (fd-no-diag c3 c4 1)
        (fd-label cs)))))

(define
  n-queens-5-fd
  (fn
    (cs)
    (let
      ((c1 (nth cs 0))
        (c2 (nth cs 1))
        (c3 (nth cs 2))
        (c4 (nth cs 3))
        (c5 (nth cs 4)))
      (mk-conj
        (fd-in
          c1
          (list 1 2 3 4 5))
        (fd-in
          c2
          (list 1 2 3 4 5))
        (fd-in
          c3
          (list 1 2 3 4 5))
        (fd-in
          c4
          (list 1 2 3 4 5))
        (fd-in
          c5
          (list 1 2 3 4 5))
        (fd-distinct cs)
        (fd-no-diag c1 c2 1)
        (fd-no-diag c1 c3 2)
        (fd-no-diag c1 c4 3)
        (fd-no-diag c1 c5 4)
        (fd-no-diag c2 c3 1)
        (fd-no-diag c2 c4 2)
        (fd-no-diag c2 c5 3)
        (fd-no-diag c3 c4 1)
        (fd-no-diag c3 c5 2)
        (fd-no-diag c4 c5 1)
        (fd-label cs)))))

(mk-test
  "n-queens-4-fd-two-solutions"
  (run*
    q
    (fresh (a b c d) (== q (list a b c d)) (n-queens-4-fd (list a b c d))))
  (list
    (list 2 4 1 3)
    (list 3 1 4 2)))

(mk-test
  "n-queens-5-fd-ten-solutions"
  (let
    ((sols (run* q (fresh (a b c d e) (== q (list a b c d e)) (n-queens-5-fd (list a b c d e))))))
    (= (len sols) 10))
  true)

(mk-tests-run!)
