CIL Toolkit: code snippets: move generation

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: CIL Toolkit: code snippets: Selector server dispatch

Post by sje »

Let's take a look at the slimmed down current version of the move selector server main line:

Code: Select all

;;; Selector server: main routine

(defun selector ()
  "Operate as a move selector server; invoked from a command line call."
  (let ((pse (mk-pse)) (form nil))
    (selector-init pse)
    (dountil (pse-exiting pse)
      (sleep 0.01)
      (dowhile (and (listen (pse-to-pipe pse)) (not (pse-exiting pse)))
        (setf form (read (pse-to-pipe pse)))
        (write form) (newline t) ; For testing
        (selector-dispatch pse form)))
    (selector-term pse))
  (values))
Here follows the somewhat skeletal dispatch routine. It can be called from either the main line (as seen above) or from the search at semi-regular intervals. Some commands make sense if no search is running, some others only work if a search is active. (Appropriate diagnostics are issued if there is a phase error.) Note how he dispatcher handles each command based on whether or not a search is underway:

Code: Select all

;;; Phase error reporting

(defun selector-pe0 (my-pse)
  "Report bad command for search not running."
  (error (format nil "selector-pe0: ~A" (pse-last-form my-pse))))

(defun selector-pe1 (my-pse)
  "Report bad command for search running."
  (error (format nil "selector-pe1: ~A" (pse-last-form my-pse))))


;;; Selector server dispatch

(defun selector-dispatch (my-pse my-cal)
  "Handle command dispatch for the move selector server."
  (let ((ssv (cdr (assoc 'verb my-cal))))
    (declare (type fixnum ssv))
    (setf (pse-last-form my-pse) my-cal)
    (cond
;;
      ((= ssv ssv-deponder)
        (if (not (pse-searching my-pse))
          (selector-pe0 my-pse)
          (warn "selector-dispatch: not fully implemented yet (deponder)~%")))
;;
      ((= ssv ssv-exit)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (setf (pse-exiting my-pse) t)))
;;
      ((= ssv ssv-finish)
        (if (not (pse-searching my-pse))
          (selector-pe0 my-pse)
          (warn "selector-dispatch: not fully implemented yet (finish)~%")))
;;
      ((= ssv ssv-level)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (level)~%")))
;;
      ((= ssv ssv-option)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (option)~%")))
;;
      ((= ssv ssv-play)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (play)~%")))
;;
      ((= ssv ssv-reload)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (reload)~%")))
;;
      ((= ssv ssv-report)
        (warn "selector-dispatch: not implemented yet (report)"))
;;
      ((= ssv ssv-reset)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (reset)~%")))
;;
      ((= ssv ssv-start)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (start)~%")))
;;
      ((= ssv ssv-syncreq)
        (warn "selector-dispatch: not implemented yet (syncreq)"))
;;
      ((= ssv ssv-unplay)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (warn "selector-dispatch: not fully implemented yet (unplay)~%")))
;;
      (t (error "selector-dispatch: cond fault"))))
  (values))
As can be seen, only the "exit" command is operational at the present.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: ver.2 PSE structure

Post by sje »

The new CIL Toolkit has a PSE (Persistent Search Environment) structure that acts as a class with each instance holding all the state data for a search. An instance also hold the variables used by the toolkit's move selector server.

Since there have been a lot of revisions to the PSE, I'll repost the source:

Code: Select all

;;; PSE: Persistent Search Environment structure; used by the move selector server

(defstruct
  (pse
    (:print-function
      (lambda (my-pse my-stream my-level)
        (declare (ignore my-level))
        (encode-pse my-stream my-pse))))
  (options     nil)              ; Option association list
  (pos         nil)              ; Position including stacked items
  (slc         nil)              ; SLC (search limit control)
  (fr-pipe     nil)              ; Command input stream (read by server)
  (to-pipe     nil)              ; Reply output stream (written by server)
  (exiting     nil)              ; Exit flag
  (searching   nil)              ; Search flag
  (pondering   nil)              ; Pondering flag
  (canceling   nil)              ; Canceling flag
  (serial      0 :type integer)  ; Status serial number
  (last-form   nil)              ; The last form (command association list) read
  (pir-vec     nil)              ; Ply Indexed Record vector
  (history-vec nil)              ; Move history popularity vector (indexed by color)
  (tt-pawn     nil)              ; Transtable for pawn stucture evaluations
  (tt-eval-vec nil)              ; Transtable vector (indexed by color) for positional scores
  (tt-hint-vec nil)              ; Transtable vector (indexed by color) for hint moves
  (tt-main-vec nil)              ; Transtable vector (indexed by color) for score/move results
  (tt-tbas-vec nil)              ; Transtable vector (indexed by color) for tablebase scores
  (sts         0 :type fixnum)   ; Search termination status
  (pv          nil)              ; Predicted variation for this position
  (expect      0 :type fixnum)   ; Expected score for this position
  (node-count  0 :type integer)) ; Count of nodes

(defun mk-pse ()
  "Return a new PSE with reasonable default initial values."
  (make-pse
    :options     nil
    :pos         (clone-pos initial-array-pos)
    :slc         (mk-slc)
    :fr-pipe     nil
    :to-pipe     nil
    :exiting     nil
    :searching   nil
    :pondering   nil
    :canceling   nil
    :serial      0
    :last-form   nil
    :pir-vec     (mk-pir-vec)
    :history-vec (mk-history-vec)
    :tt-pawn     (mk-hashflt 12)
    :tt-eval-vec (mk-hashflt-vec 14)
    :tt-hint-vec (mk-hashflt-vec  8)
    :tt-main-vec (mk-hashflt-vec 16)
    :tt-tbas-vec (mk-hashflt-vec 10)
    :sts         sts-unterminated
    :pv          nil
    :expect      neginf-score
    :node-count  0))
The various PSE reset routines:

Code: Select all

;;; PSE Resets

(defun reset-pse-search-control (my-pse)
  "Reset the search control items in a PSE."
  (setf (pse-searching my-pse) nil)
  (setf (pse-pondering my-pse) nil)
  (setf (pse-canceling my-pse) nil)
  my-pse)

(defun reset-pse-pir-vec (my-pse)
  "Reset the ply indexed entries in the given PSE."
  (when (pse-pir-vec my-pse)
    (clear-pir-vec (pse-pir-vec my-pse))))

(defun reset-pse-history (my-pse)
  "Reset the history entries in the given PSE."
  (when (pse-history-vec my-pse)
    (reset-history-vec (pse-history-vec my-pse))))

(defun reset-pse-transtables (my-pse)
  "Reset the transposition table entries in the given PSE."
  (when (pse-tt-pawn my-pse)
    (clear-hashflt (pse-tt-pawn my-pse)))
  (when (pse-tt-eval-vec my-pse)
    (clear-hashflt-vec (pse-tt-eval-vec my-pse)))
  (when (pse-tt-hint-vec my-pse)
    (clear-hashflt-vec (pse-tt-hint-vec my-pse)))
  (when (pse-tt-main-vec my-pse)
    (clear-hashflt-vec (pse-tt-main-vec my-pse)))
  (when (pse-tt-tbas-vec my-pse)
    (clear-hashflt-vec (pse-tt-tbas-vec my-pse))))

(defun reset-pse-search-result (my-pse)
  "Reset the search results in the given PSE."
  (setf (pse-sts        my-pse) sts-unterminated)
  (setf (pse-pv         my-pse) nil)
  (setf (pse-expect     my-pse) neginf-score)
  (setf (pse-node-count my-pse) 0)
  my-pse)

(defun reset-pse (my-pse)
  "Reset the given PSE."
  (setf (pse-pos            my-pse) (clone-pos initial-array-pos))
  (reset-pse-search-control my-pse)
  (reset-pse-search-result  my-pse)
  (reset-pse-pir-vec        my-pse)
  (reset-pse-history        my-pse)
  (reset-pse-transtables    my-pse)
  my-pse)
Loading a position, plus play and unplay. The "advance-pos" name is the new name for the "execute-move" routine, likewise for "retreat-pos" vs "retract-move":

Code: Select all

;;; PSE position loading

(defun load-pse-pos (my-pse my-pos)
  "Load the given position into the given PSE."
  (reset-pse my-pse)
  (setf (pse-pos my-pse) (clone-pos my-pos))
  my-pse)


;;; PSE advance/retreat

(defun advance-pse (my-pse my-move)
  "Advance a PSE by playing a move."
  (let ((old-pv (pse-pv my-pse)))
    (reset-pse-search-result my-pse)
    (mark-san-flags-move (pse-pos my-pse) my-move)
    (advance-pos (pse-pos my-pse) my-move)
    (when (and old-pv (same-move? my-move (first old-pv)))
      (setf (pse-pv my-pse) (rest old-pv))))
  my-pse)

(defun retreat-pse (my-pse)
  "Retreat a PSE by unplaying the last played move."
  (unless (positive? (pos-push-count (pse-pos my-pse)))
    (error "retreat-pse: no move to unplay"))
  (retreat-pos (pse-pos my-pse))
  (reset-pse-search-result  my-pse)
  my-pse)
And also:

Code: Select all

;;; Pre-search and post-search operations

(defun search-init-pse (my-pse)
  "Pre search PSE operations."
  (setf (pse-searching my-pse) t)
  (setf (pse-pondering my-pse) t)
  (setf (pse-canceling my-pse) nil)
  (reset-pse-search-result  my-pse)
  (reset-pse-pir-vec        my-pse)
  my-pse)

(defun search-term-pse (my-pse)
  "Post search PSE operations."
  (reset-pse-search-control my-pse)
  my-pse)
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: ver.2 Selector server dispatch

Post by sje »

The move selector server command dispatch has been expanded; it's now likely quite close to its final version:

Code: Select all

;;; Selector server dispatch

(defun selector-dispatch (my-pse my-cal)
  "Handle command dispatch for the move selector server."
  (let ((ssv (cdr (assoc 'verb my-cal))))
    (declare (type fixnum ssv))
    (setf (pse-last-form my-pse) my-cal)
    (cond
;;
      ((= ssv ssv-deponder)
        (if (pse-searching my-pse)
          (setf (pse-pondering my-pse) nil)
          (selector-pe0 my-pse)))
;;
      ((= ssv ssv-exit)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (setf (pse-exiting my-pse) t)))
;;
      ((= ssv ssv-finish)
        (if (pse-searching my-pse)
          (setf (pse-canceling my-pse) t)
          (selector-pe0 my-pse)))
;;
      ((= ssv ssv-level)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (let ((slc (pse-slc my-pse)))
            (setf (slc-msec-check slc) (cdr (assoc 'msec-check my-cal)))
            (setf (slc-msec-limit slc) (cdr (assoc 'msec-limit my-cal)))
            (setf (slc-node-check slc) (cdr (assoc 'node-check my-cal)))
            (setf (slc-node-limit slc) (cdr (assoc 'node-limit my-cal)))
            (setf (slc-sply-limit slc) (cdr (assoc 'sply-limit my-cal)))
            (setf (slc-sply-check slc) (cdr (assoc 'sply-check my-cal))))))
;;
      ((= ssv ssv-option)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (selector-optionize my-pse my-cal)))
;;
      ((= ssv ssv-play)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (advance-pse
            my-pse
            (match-san-no-fail (pse-pos my-pse) (cdr (assoc 'move my-cal))))))
;;
      ((= ssv ssv-reload)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (selector-reloader my-pse my-cal)))
;;
      ((= ssv ssv-report)
        (let ((sal nil))
          (push (cons 'node-count (pse-node-count my-pse)) sal)
          (push (cons 'expect (pse-expect my-pse)) sal)
          (push (cons 'pv (mapcar #'san-string (pse-pv my-pse))) sal)
          (push (cons 'sts (pse-sts my-pse)) sal)
          (send-client my-pse (add-status-reply my-pse ssr-status sal))))
;;
      ((= ssv ssv-reset)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (reset-pse my-pse)))
;;
      ((= ssv ssv-start)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (select-move my-pse my-cal)))
;;
      ((= ssv ssv-syncreq)
        (let ((sal nil))
          (push (assoc 'ordinal my-cal) sal)
          (send-client my-pse (add-status-reply my-pse ssr-syncack sal)))) 
;;
      ((= ssv ssv-unplay)
        (if (pse-searching my-pse)
          (selector-pe1 my-pse)
          (retreat-pse my-pse)))
;;
      (t (error "selector-dispatch: cond fault"))))
  (values))
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: Selector server helpers

Post by sje »

For some commands, the selector server calls a corresponding routine instead of handing the command inline, Here's two of these helper routines:

Code: Select all

;;; Selector server helper: setting options

(defun selector-optionize (my-pse my-cal)
  "Load option data from a cammand association list."
  (let ((options (cdr (assoc 'options my-cal))))
    (dolist (option options)
      (let ((old-option (assoc (car option) (pse-options my-pse))))
        (if old-option
          (setf (cdr old-option) (cdr option))
          (push option (pse-options my-pse))))))
  my-pse)


;;; Selector server helper: reloading position data

(defun selector-reloader (my-pse my-cal)
  "Load position and history data from a cammand association list."
  (let ((san-moves (cdr (assoc 'played my-cal))))
    (load-pse-pos my-pse (calc-pos-from-str (cdr (assoc 'fen my-cal))))
    (dolist (san-move san-moves)
      (advance-pse my-pse (match-san-no-fail (pse-pos my-pse) san-move))))
  my-pse)
For help with generating status messages (analogous in form to command processor command messages):

Code: Select all

;;; Selector status association list construction assistant

(defun add-status-reply (my-pse my-ssr my-sal)
  "Add a serial number and a reply symbol to a status association list."
  (push (cons 'serial (pse-serial my-pse)) my-sal)
  (push (cons 'action (svref as-ssr-vec my-ssr)) my-sal)
  (push (cons 'reply my-ssr) my-sal)
  (incf (pse-serial my-pse))
  my-sal)


;;; Selector status association list output

(defun send-client (my-pse my-sal)
  "Send the given status association list to the command processor client."
  (write my-sal :stream (pse-to-pipe my-pse))
  (newline (pse-to-pipe my-pse)))
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: speed test 2

Post by sje »

Using the cmucl (CMU Common Lisp) compiler and running an a 2.66 GHz Xeon:

Code: Select all

* (time (scms-driver 2 "2r1nr1k/pp1q1p1p/3bpp2/5P2/1P1Q4/P3P3/1B3P1P/R3K1R1 w Q - 0 1"))
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 
Mate in two found: 1. Qxf6+ Ng7 2. Qxg7#

; Evaluation took:
;   0.01 seconds of real time
;   5.21e-4 seconds of user run time
;   1.2e-4 seconds of system run time
;   3,685,208 CPU cycles
;   0 page faults and
;   65,816 bytes consed.
; 
[CB:Unsearched EX:MateIn2 NC:10 PV:(Qxf6+ Ng7 Qxg7#)]

* (time (scms-driver 2 "rnbqkbn1/ppppp3/7r/6pp/3P1p2/3BP1B1/PPP2PPP/RN1QK1NR w KQq - 0 1"))
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 
Mate in two found: 1. Qxh5+ Rg6 2. Qxg6#

; Evaluation took:
;   0.0 seconds of real time
;   0.001735 seconds of user run time
;   3.17e-4 seconds of system run time
;   5,474,272 CPU cycles
;   0 page faults and
;   297,128 bytes consed.
; 
[CB:Unsearched EX:MateIn2 NC:64 PV:(Qxh5+ Rg6 Qxg6#)]

* (time (scms-driver 3 "r1b1k2r/pp2bppp/8/3N2q1/2p5/8/PPP2PPP/R2QR1K1 w kq - 0 1"))
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 
Mate in three found: 1. Nc7+ Kf8 2. Qd8+ Bxd8 3. Re8#

; Evaluation took:
;   0.0 seconds of real time
;   0.004883 seconds of user run time
;   9.67e-4 seconds of system run time
;   15,608,240 CPU cycles
;   0 page faults and
;   873,848 bytes consed.
; 
[CB:Unsearched EX:MateIn3 NC:146 PV:(Nc7+ Kf8 Qd8+ Bxd8 Re8#)]

* (time (scms-driver 4 "r1b2rk1/pp1p1pp1/1b1p2B1/n1qQ2p1/8/5N2/P3RPPP/4R1K1 w - - 0 1"))
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 
Mate in four found: 1. Qxf7+ Rxf7 2. Re8+ Rf8 3. Rxf8+ Kxf8 4. Re8#

; Evaluation took:
;   1.56 seconds of real time
;   1.332603 seconds of user run time
;   0.22375 seconds of system run time
;   4,145,771,368 CPU cycles
;   [Run times include 0.34 seconds GC run time]
;   0 page faults and
;   183,792,464 bytes consed.
; 
[CB:Unsearched EX:MateIn4 NC:47122 PV:(Qxf7+ Rxf7 Re8+ Rf8 Rxf8+ Kxf8 Re8#)]
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: sync/track logfile example

Post by sje »

I've now gotten end-to-end move synchronization and position tracking working between a command processor and the move selection server. There's still some way to go here, but the basic linkage is working.

Here's an example logfile generated by the interactive command processor. It shows three "g" (go) commands and the resulting client/server communication:

Code: Select all

2008.10.07 06:03:52 Chess In Lisp Toolkit: ICP logfile begin
2008.10.07 06:03:52 Program date: 2008.10.07
2008.10.07 06:03:52 Site: gail
2008.10.07 06:03:52 Opening pipe to server CILp1
2008.10.07 06:03:56 Opening pipe from server CILp0
2008.10.07 06:04:01 [] g
2008.10.07 06:04:01 S< ((VERB . 9) (ACTION . "start") (SERIAL . 0))
2008.10.07 06:04:01 S> ((REPLY . 0) (ACTION . "analysis") (SERIAL . 0) (STS . 10) (PV "Nh3") (EXPECT . 0) (NODE-COUNT . 1))
2008.10.07 06:04:01 S> ((REPLY . 1) (ACTION . "resolved") (SERIAL . 1) (STS . 10))
2008.10.07 06:04:01 S< ((VERB . 2) (ACTION . "finish") (SERIAL . 1))
2008.10.07 06:04:01 S< ((VERB . 5) (ACTION . "play") (SERIAL . 2) (MOVE . "Nh3"))
2008.10.07 06:04:24 [] g
2008.10.07 06:04:24 S< ((VERB . 9) (ACTION . "start") (SERIAL . 3))
2008.10.07 06:04:24 S> ((REPLY . 0) (ACTION . "analysis") (SERIAL . 2) (STS . 10) (PV "f5") (EXPECT . 0) (NODE-COUNT . 1))
2008.10.07 06:04:24 S> ((REPLY . 1) (ACTION . "resolved") (SERIAL . 3) (STS . 10))
2008.10.07 06:04:24 S< ((VERB . 2) (ACTION . "finish") (SERIAL . 4))
2008.10.07 06:04:24 S< ((VERB . 5) (ACTION . "play") (SERIAL . 5) (MOVE . "f5"))
2008.10.07 06:04:37 [] g
2008.10.07 06:04:37 S< ((VERB . 9) (ACTION . "start") (SERIAL . 6))
2008.10.07 06:04:37 S> ((REPLY . 0) (ACTION . "analysis") (SERIAL . 4) (STS . 10) (PV "c4") (EXPECT . 0) (NODE-COUNT . 1))
2008.10.07 06:04:37 S> ((REPLY . 1) (ACTION . "resolved") (SERIAL . 5) (STS . 10))
2008.10.07 06:04:37 S< ((VERB . 2) (ACTION . "finish") (SERIAL . 7))
2008.10.07 06:04:37 S< ((VERB . 5) (ACTION . "play") (SERIAL . 8) (MOVE . "c4"))
2008.10.07 06:04:39 [] exit
2008.10.07 06:04:39 S< ((VERB . 1) (ACTION . "exit") (SERIAL . 9))
2008.10.07 06:04:39 Closing pipe from server CILp0
2008.10.07 06:04:39 Closing pipe to server CILp1
2008.10.07 06:04:39 Chess In Lisp Toolkit: ICP logfile end
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

CIL Toolkit: code snippets: high level move generation

Post by sje »

Here are the routines that gate high level move generation requests to the low level generator functions. Note the use of filtering and the in-check status test:

Code: Select all

;;; Move generation: checkmating moves

(defun generate-checkmates (my-pos)
  "Return a list of checkmating moves for the given position."
  (filter-checkmating-moves (mark-checkmate-flags my-pos (generate-checks my-pos))))


;;; Move generation: checking only legal moves

(defun generate-checks (my-pos)
  "Return a list of checking moves for the given position."
  (if (checked? my-pos)
    (filter-checking-moves (mark-check-flags my-pos (generate-evasion my-pos)))
    (generate-checks-nic my-pos)))


;;; Move generation: holder only legal moves

(defun generate-holders (my-pos)
  "Return a list of holder moves for the given position."
  (if (checked? my-pos)
    (filter-holder-moves (generate-evasion my-pos))
    (generate-holders-nic my-pos)))


;;; Move generation: gainer only legal moves

(defun generate-gainers (my-pos)
  "Return a list of gainer moves for the given position."
  (if (checked? my-pos)
    (filter-gainer-moves (generate-evasion my-pos))
    (generate-gainers-nic my-pos)))


;;; Move generation: full set of legal moves

(defun generate (my-pos)
  "Return a complete list of moves for the given position."
  (if (checked? my-pos)
    (generate-evasion my-pos)
    (generate-nic     my-pos)))


;;; Move generation: full set of marked legal moves

(defun generate-marked (my-pos)
  "Return a complete list of moves for the given position, fully marked."
  (mark-san-flags my-pos (generate my-pos)))


;;; Move generation: sorted full set of marked legal moves

(defun generate-canon (my-pos)
  "Return a complete list of moves for the given position, fully marked and sorted by SAN."
  (sort-moves-by-san (generate-marked my-pos)))


;;; SAN string list generation

(defun generate-san-strings (my-pos)
  "Produce a list of SAN move strings for the moves in the given position."
  (mapcar #'san-string (generate-canon my-pos)))
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: CIL Toolkit: code snippets: high level move generation

Post by sje »

And the following move generator is used in the example mate search; it generates all the moves and presents the result list with all the checking moves at the front of the list.

Code: Select all

;;; Move generation: all move with checks placed first

(defun generate-checks-first (my-pos)
  "Generate moves with the checking moves placed first."
  (let ((result nil) (moves (generate my-pos)) (checkers nil))
    (mark-check-flags my-pos moves)
    (dolist (move moves)
      (if (is-move-check? move)
        (push move checkers)
        (push move result)))
    (dowhile checkers
      (push (pop checkers) result))
    result))
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: CIL Toolkit: code snippets: high level move generation

Post by sje »

A refinement of the above; it positions capture/promotion checks ahead of material neutral checks:

Code: Select all

;;; Move generation: all moves with gainer checks placed first

(defun generate-gainer-checks-first (my-pos)
  "Generate moves with the checking moves placed first."
  (let ((result nil) (moves (generate my-pos)) (gainer-checkers nil) (holder-checkers nil))
    (mark-check-flags my-pos moves)
    (dolist (move moves)
      (if (is-move-check? move)
        (if (is-move-gainer? move)
          (push move gainer-checkers)
          (push move holder-checkers))
        (push move result)))
    (dowhile holder-checkers
      (push (pop holder-checkers) result))
    (dowhile gainer-checkers
      (push (pop gainer-checkers) result))
    result))
Harald
Posts: 318
Joined: Thu Mar 09, 2006 1:07 am

Re: CIL Toolkit: code snippets: move generation

Post by Harald »

Dear Steven

I am not sure whether I should write this comment. But here are some thoughts:

- For nearly two months now we are observing live the developing of a chess engine.
- It is written in a language that I do not understand very easily.
- This thread has grown and is now a big part of my dayly dose of CCC.
- The forum has the title "... discussion" but I only see a big monologue (with rare exceptions).

Here are some suggestions:

- Perhaps you can reduce the number of single posts to weekly updates or to important milestones.
- Perhaps you can start new smaller threads when a milestone is reached.
- Perhaps you can find a webspace and do the development there.
- Perhaps You could do the basic and boring work a little less open, like others do.

On the other hand:

- It is nice that you are very involved and obviously enthusiastic.
- It is a thread about programming and it is technical.
- I should better be working on my own engine and post some achievements here.
- It' s just my thoughts.

Harald