Isoraqathedh

betza wip 4

Mar 25th, 2014
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 16.13 KB | None | 0 0
  1. ;;;; Betza Notation
  2.  
  3. (defpackage :info.isoraqathedh.betza
  4.   (:use :common-lisp))
  5.  
  6. (in-package :info.isoraqathedh.betza)
  7.  
  8. ;;;------
  9.  
  10. (define-condition range-not-long-enough (error)
  11.   ((requested-range :initarg :requested-range
  12.             :reader  range-not-long-enough-requested)
  13.    (requested-distance :initarg :requested-distance
  14.                :reader  range-not-long-enough-distance))
  15.   (:report (lambda (condition stream)
  16.              (format stream "Range ~a is not long enough to get to cell number ~d."
  17.              (range-not-long-enough-requested condition)
  18.                      (range-not-long-enough-distance condition)))))
  19.  
  20. ;;;------
  21.  
  22. (defun dest (x y)
  23.   (if (and (numberp x)
  24.        (numberp y))
  25.       (list x y)
  26.       (error "Destination must be a number")))
  27.  
  28. ;;; ======
  29. ;;; Range functor (do not use directly)
  30. ;;; ======
  31.  
  32. (defun append-range (move distance)
  33.   (append move (list :range (list :distance distance))))
  34.  
  35. ;;; ======
  36. ;;; Combinators and attributes
  37. ;;; ======     
  38.  
  39. ;; Attributes
  40. ;; =====
  41.  
  42. (defun component-combine (func dests) "Basic combine moves with a free slot to indicate the combining function. Helper function."
  43.   (loop for dest in dests append (mapcar func dest)))
  44. (defun combine (&rest dests)
  45.   (component-combine #'identity dests)) ; For consistency, this function uses the rather silly identity function.
  46. (defun capture (&rest dests)
  47.   (component-combine #'(lambda (p) (append p (list :capture t))) dests))
  48. (defun move (&rest dests)
  49.   (component-combine #'(lambda (p) (append p (list :move t))) dests))
  50. (defun igui (&rest dests)
  51.   (component-combine #'(lambda (p) (append p (list :igui t))) dests))
  52. (defun lame (&rest dests) ; use (then '(:complete t)) (NYI) for finer control over lame moves.
  53.   (component-combine #'(lambda (p) (append p (list :lame t))) dests))
  54. (defun jump (optlist &rest dests) ; Jumping makes sense only on range moves, or when exactly one of the options are false.
  55.                     ; Single destinations are jumps by default.
  56.   (destructuring-bind (&key (jump-friendly-p t) (jump-enemy-p t)) optlist
  57.                     ; The destructuring-bind above catches settings that are not included with the attribute
  58.     (component-combine #'(lambda (p) (append p (list :jump (list :jump-friendly-p jump-friendly-p
  59.                                  :jump-enemy-p    jump-enemy-p)))) dests)))
  60. (defun cylindrical (optlist &rest dests)
  61.   (destructuring-bind (&key (wrap-left-right T)
  62.                 (wrap-front-back NIL)) optlist
  63.     (component-combine #'(lambda (p) (append p (list :cylindrical (list :wrap-left-right wrap-left-right
  64.                                     :wrap-front-back wrap-front-back)))) dests)))
  65. (defun cannon (optlist &rest dests)
  66.   (destructuring-bind (&key (steps-before :any)
  67.                 (jump-enemy-p T)
  68.                 (jump-friendly-p T)
  69.                 (capture-screen-p nil)
  70.                 (screen-count 1)
  71.                 (steps-after :any)) optlist
  72.       (component-combine #'(lambda (p) (append p (list :cannon (list :steps-before     steps-before
  73.                                      :jump-enemy-p     jump-enemy-p
  74.                                      :jump-friendly-p  jump-friendly-p
  75.                                      :capture-screen-p capture-screen-p
  76.                                      :screen-count     screen-count
  77.                                      :steps-after      steps-after)))) dests)))
  78.  
  79.  
  80. ;; Multimoves
  81. ;; =====
  82.  
  83. ;(loop for i in set-1
  84. ;       nconc (loop for j in set-2 collect (list i j))))
  85.  
  86. (defun combo (obligate-complete-p repeatp outwards-only-p steps)
  87.   (let ((initial-list (reduce #'(lambda (first-step second-step)
  88.                   (loop for i in first-step
  89.                      append (loop for j in second-step
  90.                            collect (if (keywordp (car i))
  91.                                (concatenate 'list i (list j))
  92.                                (list :then (list :obligate-complete-p obligate-complete-p
  93.                                          :repeatp             repeatp)
  94.                                  i j)))))
  95.                   steps)))
  96.     (if outwards-only-p
  97.     (remove-if #'(lambda (p) (apply #'< (loop for (x y . nil) in (cddr p)
  98.                            for aggr-x = x then (+ aggr-x x)
  99.                            for aggr-y = y then (+ aggr-y y)
  100.                            collect (+ (expt aggr-x 2) (expt aggr-y 2))))) initial-list)
  101.     initial-list)))
  102.  
  103. (defun then      (&rest steps) (combo nil nil t   steps))
  104. (defun must-go   (&rest steps) (combo t   nil t   steps))
  105. (defun alternate (&rest steps) (combo nil t   nil steps))
  106.  
  107. ;;; ======
  108. ;;; Pieces
  109. ;;; ======
  110.  
  111. (defun zero () (list (dest 0 0)))
  112.  
  113. ;; Orthogonally-jumping pieces
  114. ;; =====
  115.  
  116. ;; Generic orthogonal
  117. (defun orthogonal-jump (&key (directions '(:f :b :r :l)) (jump-distance 1))
  118.   (let ((vectors (list :r (dest (+ jump-distance) 0)
  119.                :l (dest (- jump-distance) 0)
  120.                :f (dest 0 (+ jump-distance))
  121.                :b (dest 0 (- jump-distance)))))
  122.     (mapcar #'(lambda (x) (getf vectors x)) directions)))
  123.  
  124. ;; Specialized orthogonal
  125. (defmacro define-orthogonal-jump (name dist)
  126.   `(defun ,name (&key (directions '(:f :b :r :l)))
  127.      (orthogonal-jump :directions directions :jump-distance ,dist)))
  128. (define-orthogonal-jump wazir       1)
  129. (define-orthogonal-jump dabbabah    2)
  130. (define-orthogonal-jump threeleaper 3)
  131.  
  132. ;; Generic rider orthogonal
  133. (defun orthogonal-ride (&key (distance :infinite) (directions '(:f :b :r :l)) (jump-distance 1))
  134.   (let ((used-vectors (orthogonal-jump :directions directions :jump-distance jump-distance)))
  135.     (if (eql distance 1)
  136.     used-vectors
  137.     (mapcar #'(lambda (x) (append-range x distance)) used-vectors))))
  138.  
  139. ;; Specialized rider orthogonal
  140. (defmacro define-orthogonal-range (name dist)
  141.   `(defun ,name (&key (distance :infinite) (directions '(:f :b :r :l)))
  142.      (orthogonal-ride :distance distance :directions directions :jump-distance ,dist)))
  143. (define-orthogonal-range rook              1)
  144. (define-orthogonal-range dabbabah-rider    2)
  145. (define-orthogonal-range threeleaper-rider 3)
  146.  
  147. ;; Diagonally-jumping pieces
  148. ;; =====
  149.  
  150. ;; Generic diagonal
  151. (defun diagonal-jump (&key (directions '(:f :b :r :l)) (jump-distance 1))
  152.   (flet ((expand-diagonals (dir) ;keyword shorthand expansion
  153.        (loop
  154.           for i in dir
  155.           append (case i
  156.                (:f  '(:fl :fr))
  157.                (:b  '(:bl :br))
  158.                (:l  '(:fl :bl))
  159.                (:r  '(:fr :br))
  160.                (:fl '(:fl))
  161.                (:bl '(:bl))
  162.                (:br '(:br))
  163.                (:fr '(:fr))))))
  164.     (let ((vectors (list :fr (dest (+ jump-distance) (+ jump-distance))
  165.              :fl (dest (- jump-distance) (+ jump-distance))
  166.              :br (dest (+ jump-distance) (- jump-distance))
  167.              :bl (dest (- jump-distance) (- jump-distance)))))
  168.       (remove-duplicates (mapcar #'(lambda (x) (getf vectors x)) (expand-diagonals directions))))))
  169.  
  170. ;; Specialized diagonal
  171. (defmacro define-diagonal-jump (name dist)
  172.   `(defun ,name (&key (directions '(:f :b :r :l)))
  173.      (diagonal-jump :directions directions :jump-distance ,dist)))
  174. (define-diagonal-jump ferz    1)
  175. (define-diagonal-jump alfil   2)
  176. (define-diagonal-jump tripper 3)
  177.  
  178. ;; Generic rider diagonal
  179. (defun diagonal-ride (&key (distance :infinite) (directions '(:f :b :r :l)) (jump-distance 1))
  180.   (let ((used-vectors (diagonal-jump :directions directions :jump-distance jump-distance)))
  181.     (if (eql distance 1)
  182.     used-vectors
  183.     (mapcar #'(lambda (x) (append-range x distance)) used-vectors))))
  184.  
  185. ;; Specialized rider orthogonal
  186. (defmacro define-diagonal-range (name dist)
  187.   `(defun ,name (&key (distance :infinite) (directions '(:f :b :r :l)))
  188.      (diagonal-ride :distance distance :directions directions :jump-distance ,dist)))
  189. (define-diagonal-range bishop        1)
  190. (define-diagonal-range alfil-rider   2)
  191. (define-diagonal-range tripper-rider 3)
  192.  
  193. ;; Hippogonal pieces
  194. ;; =====
  195.  
  196. ;; Generic hippogonal
  197. (defun hippo (long-side short-side &key (directions '(:f :b :r :l)))
  198.   (cond
  199.     ;; degenerate cases
  200.     ((< long-side short-side) (hippo short-side long-side :directions directions))
  201.     ((= long-side short-side) (diagonal-jump :directions directions :jump-distance long-side))
  202.     ((zerop short-side)     (orthogonal-jump :directions directions :jump-distance long-side))
  203.     ;; the real thing
  204.     (t (flet ((expand-hippogonals (dir) ;keyword shorthand expansion
  205.         (loop for i in dir
  206.            append (case i
  207.                 (:f   '(:ffr :ffl :fsr :fsl))
  208.                 (:b   '(:bbr :bbl :bsr :bsl))
  209.                 (:r   '(:ffr :fsr :bsr :bbr))
  210.                 (:l   '(:ffl :fsl :bsl :bbl))
  211.                 (:fr  '(:ffr :fsr))
  212.                 (:fl  '(:ffl :fsl))
  213.                 (:br  '(:bbr :bsr))
  214.                 (:bl  '(:bbl :bsl))
  215.                 (:ff  '(:ffr :ffl))
  216.                 (:fs  '(:fsr :fsl))
  217.                 (:bb  '(:bbr :bbl))
  218.                 (:bs  '(:bsr :bsl))
  219.                 (:ll  '(:bsl :fsl))
  220.                 (:lv  '(:bbl :ffl))
  221.                 (:rr  '(:bsr :fsr))
  222.                 (:rv  '(:bbr :ffr))
  223.                 (:fb  '(:ffl :ffr :bbl :bbr))
  224.                 (:rl  '(:fsl :fsr :bsl :bsr))
  225.                 (:ffr '(:ffr))
  226.                 (:fsr '(:fsr))
  227.                 (:bsr '(:bsr))
  228.                 (:bbr '(:bbr))
  229.                 (:bbl '(:bll))
  230.                 (:bsl '(:bsl))
  231.                 (:fsl '(:fsl))
  232.                 (:ffl '(:ffl))))))
  233.      (let ((vectors (list :ffr (dest (+ short-side) (+ long-side) )
  234.                   :fsr (dest (+ long-side)  (+ short-side))
  235.                   :bsr (dest (+ long-side)  (- short-side))
  236.                   :bbr (dest (+ short-side) (- long-side) )
  237.                   :bbl (dest (- short-side) (- long-side) )
  238.                   :bsl (dest (- long-side)  (- short-side))
  239.                   :fsl (dest (- long-side)  (+ short-side))
  240.                   :ffl (dest (- short-side) (+ long-side)))))
  241.        (remove-duplicates (mapcar #'(lambda (x) (getf vectors x)) (expand-hippogonals directions))))))))
  242.        
  243.  
  244. ;; Specialized hippogonal
  245. (defmacro define-hippo (name long short)
  246.   `(defun ,name (&key (directions '(:f :b :r :l)))
  247.      (hippo ,long ,short :directions directions)))
  248. (define-hippo knight   2 1)
  249. (define-hippo camel    3 1)
  250. (define-hippo zebra    3 2)
  251. (define-hippo giraffe  4 1)
  252. (define-hippo antelope 4 3)
  253.  
  254. ;; Generalized hippogonal ride
  255. (defun hippogonal-ride (long-side short-side &key (distance :infinite) (directions '(:f :b :r :l)))
  256.   (let ((used-vectors (hippo long-side short-side :directions directions)))
  257.     (if (eql distance 1)
  258.     used-vectors
  259.     (mapcar #'(lambda (x) (append-range x distance)) used-vectors))))
  260.  
  261. ;; Specialized rider orthogonal
  262. (defmacro define-hippogonal-range (name long short)
  263.   `(defun ,name (&key (distance :infinite) (directions '(:f :b :r :l)))
  264.      (hippogonal-ride ,long ,short :distance distance :directions directions)))
  265. (define-hippogonal-range nightrider 2 1)
  266. (define-hippogonal-range camelrider 3 1)
  267. (define-hippogonal-range zebrarider 3 2)
  268.  
  269. ;; Commonly-used pieces
  270. ;; =====
  271. (defvar *wazir* (wazir))
  272. (defvar *dabbabah* (dabbabah))
  273.  
  274. (defvar *ferz* (ferz))
  275. (defvar *alfil* (alfil))
  276.  
  277. (defvar *rook* (rook))
  278. (defvar *remarkable-short-rook* (rook :distance 4))
  279.  
  280. (defvar *bishop* (bishop))
  281.  
  282. (defvar *knight*   (knight))
  283. (defvar *camel*    (camel))
  284. (defvar *zebra*    (zebra))
  285. (defvar *giraffe*  (giraffe))
  286. (defvar *antelope* (antelope))
  287.  
  288. ;; FIDE
  289. (defvar *king* (combine (wazir) (ferz)) "The King from FIDE Chess.")
  290. (defvar *queen* (combine (rook) (bishop)) "The Queen from Fide Chess.")
  291. (defvar *rook* (rook) "The Rook from FIDE Chess.")
  292. (defvar *bishop* (bishop) "The Bishop from FIDE Chess.")
  293. (defvar *knight* (knight) "The Knight from FIDE Chess.")
  294. (defvar *pawn* (combine (capture (ferz :directions '(:f))) (move (wazir :directions '(:f)))) "The Pawn from FIDE chess, less the initial kerfluffle.")
  295.  
  296. ;; Shogi
  297. (defvar *incense-chariot* (rook :directions '(:f))
  298.   "The Incense Chariot from Shogi, also called 'lance', 'fragrant chariot' or 'wing'.")
  299. (defvar *honourable-horse* (knight :directions '(:ff))
  300.   "The Honorable Horse from Shogi, also called 'horse', 'laureled horse' or 'helm'.")
  301. (defvar *silver-general* (combine (ferz) (wazir :directions '(:f))) "The Silver General from Shogi. Also the elephant from Makruk.")
  302. (defvar *gold-general* (combine (wazir) (ferz :directions '(:f))) "The Gold General from Shogi.")
  303. (defvar *dragon-king* (combine (rook) (ferz)) "The Dragon King from Shogi. Also called 'chatelaine'.")
  304. (defvar *dragon-horse* (combine (bishop) (wazir)) "The Dragon Horse from Shogi. Also called 'primate'.")
  305. (defvar *foot-soldier* (wazir :directions '(:f)) "The Foot Soldier from Shogi. Also called 'fuhyo' or 'point'.")
  306.  
  307. ;; Xiangqi
  308. (defvar *horse* (must-go (move (wazir)) (ferz)) "The Horse from Xiangqi. Like a knight but lame.")
  309. (defvar *chinese-elephant* (lame (alfil)) "The elephant from Xiangqi.  Like an Alfil but lame.")
  310. (defvar *cannon* (combine (move (rook)) (capture (cannon nil (rook)))) "The Cannon from Xiangqi.")
  311.  
  312. ;; ======
  313. ;; Writer
  314. ;; ======
  315.  
  316. (defun write-in-diagram-array (diagram destination-descr &optional force-char)
  317.   (destructuring-bind (y x &rest args) destination-descr ; again, reversed x-ys in arrays
  318.     (let ((centre-of-array-x (floor (/ (first (array-dimensions diagram)) 2)))
  319.       (centre-of-array-y (floor (/ (second (array-dimensions diagram)) 2))))
  320.       (labels ((write-functor (x y char centre-of-array-x centre-of-array-y)
  321.          (setf (aref diagram (- (first (array-dimensions diagram)) (+ x centre-of-array-x 1)) (+ y centre-of-array-y)) char))
  322.            (select-character (args default force-char)
  323.          (if force-char force-char (cond
  324.                          ((getf args :igui) "!")
  325.                          ((and (getf args :move)
  326.                            (not (getf args :capture))) "m")
  327.                          ((and (getf args :capture)
  328.                            (not (getf args :move))) "c")
  329.                          (t default)))))
  330.     (handler-case
  331.         (cond ((and (getf args :range)
  332.             (numberp (getf (getf args :range) :distance)))
  333.            (let ((total-distance (getf (getf args :range) :distance)))
  334.              (loop for i from 1 to total-distance
  335.             do (write-functor (* i x) (* i y) (select-character args "x" force-char) centre-of-array-x centre-of-array-y))))
  336.           ((and (getf args :range)
  337.             (eql (getf (getf args :range) :distance) :infinite))
  338.            (let ((max-distance-x (- (first (array-dimensions diagram)) centre-of-array-x 1))
  339.              (max-distance-y (- (second (array-dimensions diagram)) centre-of-array-y 1)))
  340.              (loop for i from 1 to (max max-distance-x max-distance-y)
  341.             do (write-functor (* i x) (* i y)
  342.                       (select-character args (cond ((= x y) "/")
  343.                                        ((= x (- y)) "\\")
  344.                                        ((= x 0) "-")
  345.                                        ((= y 0) "|")
  346.                                        (t "~")) force-char)
  347.                       centre-of-array-x centre-of-array-y))))    
  348.           (t (write-functor x y (select-character args "x" force-char) centre-of-array-x centre-of-array-y)))
  349.       (SB-INT:INVALID-ARRAY-INDEX-ERROR () nil))
  350.     diagram))))
  351.  
  352. (defun write-all-in-diagram-array (diagram piece)
  353.   (loop for dest-descr in piece
  354.      do
  355.        ; (format t "~&~a" dest-descr)
  356.        (write-in-diagram-array diagram dest-descr)
  357.      finally (return diagram)))
  358.  
  359. (defun make-diagram-array (piece &optional (spaciousp t) (squarep t))
  360.   (flet ((max-coords-needed (piece squarep)
  361.        (loop for dest in piece
  362.           maximize (cond ((keywordp (first dest)) (reduce #'+ (subseq dest 2) :key #'first))
  363.                  ((and (getf (nthcdr 2 dest) :range)
  364.                    (numberp (getf (getf (nthcdr 2 dest) :range) :distance)))
  365.                   (* (getf (getf (nthcdr 2 dest) :range) :distance) (first dest)))
  366.                  (t (first dest))) into max-x
  367.           maximize (cond ((keywordp (first dest)) (reduce #'+ (subseq dest 2) :key #'second))
  368.                  ((and (getf (nthcdr 2 dest) :range)
  369.                    (numberp (getf (getf (nthcdr 2 dest) :range) :distance)))
  370.                   (* (getf (getf (nthcdr 2 dest) :range) :distance) (second dest)))
  371.                  (t (second dest))) into max-y
  372.           finally
  373.            (return
  374.          (let ((max-all (max max-x max-y)))
  375.            (list (if squarep max-all max-x)
  376.              (if squarep max-all max-y)))))))
  377.     (let ((true-size (reverse ; The array x-y is reversed compared to the conventional x-y.
  378.                (mapcar #'(lambda (p) (+ (if spaciousp 3 1) (* 2 p)))
  379.                    (max-coords-needed piece squarep)))))
  380.       (write-all-in-diagram-array
  381.        (write-in-diagram-array (make-array true-size :initial-element ".") '(0 0) "O")
  382.        piece))))
  383.  
  384. (defun print-diagram (stream diagram &optional returnp)
  385.   (when (or (< (first (array-dimensions diagram)) 10)
  386.         (< (first (array-dimensions diagram)) 10)
  387.         (eql stream t)
  388.         (y-or-n-p "Holy crap, this diagram is going to be huge. Continue?"))
  389.     (loop with 2d = diagram
  390.        with (rows cols) = (array-dimensions 2d)
  391.        for row below rows
  392.        do (format stream "~&")
  393.      (loop for col below cols
  394.         do (format stream "~a " (aref 2d row col))))
  395.     (if returnp diagram)))
  396.  
  397. (defun make-and-print-diagram (stream piece &optional returnp)
  398.   (print-diagram stream (make-diagram-array piece) returnp))
Advertisement
Add Comment
Please, Sign In to add comment