;;; -*- Mode: Lisp; Package: Puser; Base: 10. ; Options:((WORLD GRAPHICS-DEMOS)); -*-
;;; (C) Copyright 1983,1984,1985, Uppsala University

;;; Predicates that draw chess boards.

(define-predicate display-board
  ((display-board ?heading ((:absolute-size ?width ?height) . ?pos0) ?pos)
   (quotient ?xstep ?width 20.)
   (product ?ystep ?xstep .8)
   (lisp-value ?xbase (// (- '?width (* 8 '?xstep)) 2) :dont-invoke)
   (lisp-value ?ybase (// (- '?height (* 8 '?ystep)) 2) :dont-invoke)
   (= ?pos0 ((:define-coords ?xbase ?ybase ?xstep ?ystep)
	     (:line 0 0 8 0) (:line 8 0 8 8) (:line 8 8 0 8) (:line 0 8 0 0)
	     . ?pos1))
   (squares 0 0 ?pos1 ((:centered-text ?heading 0 8 -1) . ?pos))))

(define-predicate squares
  ((squares 7 9 ?pos0 ?pos) (cut) (= ?pos0 ?pos))
  ((squares ?row 9 ?pos0 ?pos) (cut) (sum ?row+1 ?row 1) (squares ?row+1 0 ?pos0 ?pos))
  ((squares ?row 8 ?pos0 ?pos) (cut) (sum ?row+1 ?row 1) (squares ?row+1 1 ?pos0 ?pos))
  ((squares ?row ?column ((:rectangle 1 1 ?row ?column) . ?pos0) ?pos)
   (sum ?column+2 ?column 2)
   (squares ?row ?column+2 ?pos0 ?pos)))


;;; Predicates that draw chess pieces.

(send tv:main-screen ':parse-font-descriptor #-3600 'fonts:s30chs #+3600 'fonts:s35ger)

#-3600
(define-predicate queen
  (:options (:compile-method :open))
  ((queen ((:char :s30chs #/b ?x ?y) . ?pos) ?pos ?x ?y)))

#+3600
(define-predicate queen
  :(options (compile-method open))
  ((queen ((:char :s35ger #/Q ?x ?y) . ?pos) ?pos ?x ?y)))

#-3600
(define-predicate knight
  :(options (compile-method open))
  ((knight ((:char :s30chs #/h ?x ?y) . ?pos) ?pos ?x ?y)))

#+3600
(define-predicate knight
  :(options (compile-method open))
  ((knight ((:char :s35ger #/K ?x ?y) . ?pos) ?pos ?x ?y)))

;;; The Eight Queens Problem.

(define-predicate no-threat
  ((no-threat ?y1 ?y2 ?dx)
   (lisp-predicate ( (abs (- '?y1 '?y2)) '?dx) :invoke)))

(define-predicate safe-queen
  ((safe-queen ? () ?) (cut))
  ((safe-queen ?y1 (?y2 . ?rest) ?dx)
   (prolog:constrain ?y2 (no-threat ?y1 ?y2 ?dx))
   (sum ?dx1 ?dx 1)
   (safe-queen ?y1 ?rest ?dx1)))

(define-predicate display-safe-queens
  ((display-safe-queens 8 () ?pos ?pos)
   (cut))
  ((display-safe-queens ?i (?y . ?rest) ?pos0 ?pos)
   (sum ?i1 ?i 1)
   (display-safe-queens ?i1 ?rest ?pos1 ?pos)
   (safe-queen ?y ?rest 1)
   (prolog:constrain ?y (queen ?pos0 ?pos1 ?i ?y))))

(define-predicate 8-queens-solution
  ((8-queens-solution ?l ?pos0 ?pos)
   (display-safe-queens 0 ?l ?pos0 ?pos)
   (sub-permutation (0 1 2 3 4 5 6 7) ?l)))

;;Sub-permutation is defined at the end of this file.

(define-predicate 8-queens 
  ((8-queens)
   (8-queens ?))
  ((8-queens ?v)
   (8-queens ?v ?))
  ((8-queens ?v ?pos0)
   (graphics-demos-stream ?pos0)
   (display-board "8 Queens Problem" ?pos0 ?pos1)
   (time-and-print (8-queens-solution ?v ?pos1 ()))))

;;; The Knights Tour Problem.

;;SIMPLE-LOGICAL-ARRAYS are just arrays of logical variables.
prolog:
(defun simple-logical-array (&rest dimensions)
  (let* ((array (make-array dimensions ':area *prolog-work-area*))
	 (origin (ap-1-force array 0)))
    (dotimes (i (apply #'* dimensions))
      (let ((place (%make-pointer-offset dtp-locative origin i)))
	(rplaca place place)))
    array))

prolog:
(define-predicate 2d-array-element ;;:(options (deterministic always))
  ((2d-array-element ?value ?array ?x ?y)
   (lisp-value ?value (aref '?array '?x '?y) :dont-invoke))
   ;;(nth ?row ?x ?array)
   ;;(nth ?value ?y ?row)
   )

prolog:
(define-predicate 2d-array
  ((2d-array ?array ?x ?y)
   (lisp-value ?array (simple-logical-array '?x '?y) :dont-invoke)))

(define-predicate first-best-move :(options (argument-list (* * +)))
  ((first-best-move ?best ?best ()))
  ((first-best-move ?best ?sofar (?move . ?moves))
   (= (? . ?sl) ?sofar)
   (= (? . ?ml) ?move)
   (cases ((< ?ml ?sl) (first-best-move ?best ?move ?moves))
	  ((first-best-move ?best ?sofar ?moves)))))

(define-predicate best-move
  ((best-move ?pattern ?old-pos ?count (?x . ?y))
   (bag-of (?move . ?moves) (?pos . ?n)
	   (legal-move ?pattern ?old-pos ?count ?pos)
	   (bag-of ?list x (legal-move ?pattern ?pos x ?))
	   (length ?n ?list))
   (first-best-move (? . ?least) ?move ?moves)
   (member ((?x . ?y) . ?least) (?move . ?moves))
   (prolog:2d-array-element ?count ?pattern ?x ?y)))

(define-predicate display-move
  ((display-move (?x0 . ?y0) (?x1 . ?y1) ?pos0 ?pos3)
   (knight ?pos0 ?pos1 ?x0 ?y0)
   (knight ?pos1 ?pos2 ?x1 ?y1)
   (lisp-value ?pos2
	       (prolog:prolog-cons
		 (prolog:prolog-list ':line (+ .5 '?x0) (+ .5 '?y0) (+ .5 '?x1) (+ .5 '?y1))
		 '?pos3)
	       :dont-invoke)))

(define-predicate knight-move
  ((knight-move ? ? ?max ?max ?pos ?pos))
  ((knight-move ?pattern ?last-move ?count ?max ?pos0 ?pos)
   (< ?count ?max)
   (sum ?count+1 ?count 1)
   (best-move ?pattern ?last-move ?count ?new-move)
   (display-move ?last-move ?new-move ?pos0 ?pos1)
   (knight-move ?pattern ?new-move ?count+1 ?max ?pos1 ?pos)))

(define-predicate legal-move
  ((legal-move ?pattern (?last-x . ?last-y) ?count (?new-x . ?new-y))
   (knight-delta ?dx ?dy)
   (sum ?new-x ?last-x ?dx)
   ( 0 ?new-x 7)
   (sum ?new-y ?last-y ?dy)
   ( 0 ?new-y 7)
   (prolog:2d-array-element ?count ?pattern ?new-x ?new-y)))

(define-predicate knight-delta
  ((knight-delta -2 -1))
  ((knight-delta -1 -2))
  ((knight-delta +1 -2))
  ((knight-delta +2 -1))
  ((knight-delta +2 +1))
  ((knight-delta +1 +2))
  ((knight-delta -1 +2))
  ((knight-delta -2 +1)))

(define-predicate knights-tour
  ((knights-tour ?pos0)
   (graphics-demos-stream ?pos0)
   (display-board "Knights Tour Problem" ?pos0 ((:fix-mouse "Pick a square" ?mx ?my) . ?pos1))
   (knight ?pos1 ?pos2 ?mx ?my)
   (prolog:2d-array ?pattern 8 8)
   (prolog:2d-array-element 0 ?pattern ?mx ?my)
   (time-and-print (knight-move ?pattern (?mx . ?my) 1 64. ?pos2 ())))
  ((knights-tour)
   (knights-tour ?)))

;;; The Send More Money Problem.

(define-predicate display-equation
  ((display-equation ?heading ?coords ((:absolute-size ?width ?height) . ?pos0) ?pos)
   (either (= ?width 100.) (true))		;default if graphics is off
   (either (= ?height 100.) (true))		;ditto
   (quotient ?xstep ?width 15.)
   (product ?ystep ?xstep .8)
   (lisp-value ?xbase (// (- '?width (* 5 '?xstep)) 2) :dont-invoke)
   (lisp-value ?ybase (// (- '?height (* 3 '?ystep)) 2) :dont-invoke)
   (= ?pos0 ((:define-coords ?xbase ?ybase ?xstep ?ystep)
	     (:line -1 2 5 2)
	     (:centered-text ?heading 0 5 -1)
	     . ?pos1))
   (display-equation-1 ?coords ?pos1 ?pos)))

(define-predicate display-equation-1
  ((display-equation-1 () ?pos ?pos) (cut))
  ((display-equation-1 ((?) . ?specs) ?pos0 ?pos)
   (cut)
   (display-equation-1 ?specs ?pos0 ?pos))
  ((display-equation-1 ((?var (?x . ?y) . ?coords) . ?specs) ?pos0 ?pos)
   (prolog:constrain ?var (= ?pos0 ((:digit :43vxms ?var ?x ?y) . ?pos1)))
   (display-equation-1 ((?var . ?coords) . ?specs) ?pos1 ?pos)))

(define-predicate send-more-money
  ((send-more-money)
   (send-more-money ?))
  ((send-more-money ?graph)
   (time-and-print (send-more-money-solution ?graph))))

(define-predicate send-more-money-solution
  ((send-more-money-solution ?pos0)
   (prolog:constrain ?s (> ?s 0))
   (prolog:constrain ?m (> ?m 0))
   (prolog:constrain ?e (add-two-with-carry ?c1 ?y ?d ?e 0))
   (prolog:constrain ?r (add-two-with-carry ?c2 ?e ?n ?r ?c1))
   (prolog:constrain ?o (add-two-with-carry ?c3 ?n ?e ?o ?c2))
   (prolog:constrain ?m (add-two-with-carry ?m  ?o ?s ?m ?c3))
   (graphics-demos-stream ?pos0)
   (display-equation "SEND + MORE = MONEY"
		     ((?y (4 . 2))
		      (?d (4 . 0))
		      (?e (2 . 0) (4 . 1) (3 . 2))
		      (?n (3 . 0) (2 . 2))
		      (?r (3 . 1))
		      (?o (2 . 1) (1 . 2))
		      (?s (1 . 0))
		      (?m (1 . 1) (0 . 2)))
		     ?pos0 ())
   (sub-permutation (0 1 2 3 4 5 6 7 8 9) (?y ?d ?e ?n ?r ?o ?s ?m))))

(define-predicate add-two-with-carry
  ((add-two-with-carry 0 ?sum ?x ?y ?c)
   (lisp-value ?sum (+ '?x '?y '?c) :invoke))
  ((add-two-with-carry 1 ?sum ?x ?y ?c)
   (lisp-value ?sum (+ '?x '?y '?c -10) :invoke)))

(define-predicate sub-permutation
  ((sub-permutation ? ()))
  ((sub-permutation ?all (?x . ?but-one-perm))
   (extraction ?all ?x ?but-one)
   (sub-permutation ?but-one ?but-one-perm)))

(define-predicate extraction
  ((extraction (?x . ?l) ?x ?l))
  ((extraction (?x . ?all) ?y (?x . ?some))
   (extraction ?all ?y ?some)))
