diff options
author | Jason Katz-Brown <jason@airbnb.com> | 2013-08-25 02:17:13 -0700 |
---|---|---|
committer | Jason Katz-Brown <jason@airbnb.com> | 2013-08-25 02:17:13 -0700 |
commit | 9306cb60c32082c5403931de0823a9fd5daa196c (patch) | |
tree | ca1b6eb695fdf3f0c2294e92416b272164bae642 /lisp/ouat/scrabble-move-finding.lisp | |
parent | 8fb2c681cecc01b46b0f4ba02d5cc177c4747b1c (diff) |
Initial git commit.
Diffstat (limited to 'lisp/ouat/scrabble-move-finding.lisp')
-rw-r--r-- | lisp/ouat/scrabble-move-finding.lisp | 834 |
1 files changed, 834 insertions, 0 deletions
diff --git a/lisp/ouat/scrabble-move-finding.lisp b/lisp/ouat/scrabble-move-finding.lisp new file mode 100644 index 0000000..b80a762 --- /dev/null +++ b/lisp/ouat/scrabble-move-finding.lisp @@ -0,0 +1,834 @@ +(in-package :ouat) + +(defstruct blank-state + idx + limit + rack-pos + seq-idx + assignment) + +(defmacro def-move-finder (fn-name layout tiles + lexicon rules result-type debug-p) + `(defun ,fn-name (board unsorted-rack bag) + ,(if debug-p + `(declare (optimize debug)) + `(declare (optimize (speed 3) (safety 0) (space 1) (debug 0)))) + (declare (ignore board bag) + (type (simple-array tile) ,tiles)) + (let* ((rack (rack-sort unsorted-rack)) + (seq (unique-rack-perms rack)) + (elts (perm-seq-elts seq)) + (dawg (lexicon-dawg ,lexicon)) + (nodes (dawg-nodes dawg)) + (nth-child-letter-table (dawg-nth-child-letter-table dawg)) + (letter2child-table (dawg-letter2child-table dawg)) + (rack-pos-dawg-idxs (make-array (i1+ (rack-size rack)) + :element-type 'fixnum)) + (max-rack-pos (i1- (rack-size rack))) + (seq-idx 0) + (blank-states (make-array (i1+ (rack-size rack)))) + (move-over-blank-p nil) + (blank-state nil) + (num-blanks-active 0) + (blank-id ,(tiles-blank (symbol-value tiles))) + (blank-tile (aref ,tiles blank-id)) + (blank-quantity (tile-quantity blank-tile)) + (blank-designations (make-array blank-quantity :element-type 'fixnum)) + (word (make-array (the fixnum (rack-size rack)) :element-type 'fixnum)) + (letter-muls ,(layout-letter-muls (symbol-value layout))) + (word-muls ,(layout-word-muls (symbol-value layout))) + (center-row ,(layout-center-row (symbol-value layout))) + (center-col ,(layout-center-col (symbol-value layout))) + (bingo-bonus ,(rules-bingo-bonus (symbol-value rules))) + (elt nil) + (rack-pos nil) + (letter-idx nil) + (dawg-idx nil) + (node 0) + (skip-seq-idx nil) + (tile-id nil) + (letter-id +empty+) + (length 0) + (result ,(if (eq result-type :TOP-VALUE) + `MOST-NEGATIVE-FIXNUM + `nil))) + + (declare (ignore blank-designations) + (type (simple-array perm-elt) elts) + (type (simple-array fixnum) nodes) + ;(type (simple-array fixnum) nth-child-letter-table) + (type (simple-array (unsigned-byte 8)) nth-child-letter-table) + (type (simple-array (unsigned-byte 32)) letter2child-table) + (type fixnum node) + (type (simple-array fixnum) rack-pos-dawg-idxs)) + + ,(when debug-p + `(format t "rack has ~a permutations~%" + (length elts))) + + (loop while (i< seq-idx (length elts)) do + (labels ((node-has-child (child-letter) + (logbitp (the fixnum child-letter) node)) + + (find-child-idx (child-letter) + (when (node-has-child child-letter) + (i+ dawg-idx + (node-letter-offset node child-letter)))) + + (fast-child-idx (idx child-letter) + (aref letter2child-table (i+ (i* 32 idx) child-letter))) + + (fast-nth-child-letter (idx n) + (aref nth-child-letter-table (i+ (i* 32 idx) n))) + + (num-children () + (declare (type (simple-vector 28) *mask*) + (type (simple-vector #.(ash 1 13)) + *one-bits-per-13*)) + (let ((first-13 (ilogand node (mask 13))) + (second-13 (iash node -13))) + (i+ (aref *one-bits-per-13* first-13) + (aref *one-bits-per-13* second-13)))) + + (trimmed () + (declare (sb-ext:muffle-conditions + sb-ext:compiler-note)) + (subseq word 0 length)) + + (blank-ps () + (let ((bps (make-array length :initial-element nil))) + (loop + for idx below num-blanks-active + for bs across blank-states + for rack-pos = (blank-state-rack-pos bs) + do (setf (aref bps rack-pos) t)) + bps)) + + (process-word (start-col) + (let* ((word-mul-product 1) + (bps (blank-ps)) + (bingo-p (i= length (rack-capacity rack))) + (score + (loop + with sum = 0 + with row = center-row + for col from start-col + for idx below length + for tile-idx = (aref word idx) + for tile = (aref ,tiles tile-idx) + for tile-score = (tile-score tile) + for letter-mul = (aref letter-muls row col) + for word-mul = (aref word-muls row col) + do + (setf word-mul-product + (i* word-mul-product word-mul)) + (unless (aref bps idx) + (iincf sum (i* letter-mul tile-score))) + finally (return sum))) + (score (i* score word-mul-product)) + (score (if bingo-p + (i+ score bingo-bonus) + score))) + (macrolet ((make-this-move () + `(make-move + :action :place + :bingo-p bingo-p + :score score + :direction :horizontal + :start-row center-row + :start-col start-col + :word (trimmed) + :blank-ps bps + :tiles (trimmed) + :already-on-board-ps + (make-array length + :element-type 'boolean + :initial-element nil)))) + ,(when (eq :TOP-VALUE result-type) + `(setf result (imax result score))) + ,(when (eq :TOPS result-type) + `(let ((top-score (if result + (move-score + (first result)) + MOST-NEGATIVE-FIXNUM))) + (cond ((i> score top-score) + (setf result (list (make-this-move)))) + ((i= score top-score) + (push (make-this-move) result))))) + ,(when (eq :ALL result-type) + `(push (make-this-move) result))))) + + (process-word-in-all-placements () + #+nil + ,(when debug-p + `(format t "processing word in all placements~%")) + (loop + with min-col = (i- center-col (i1- length)) + for start-col from min-col to center-col do + (process-word start-col))) + + (blank-hop () + ,(when debug-p + `(format t "do the blank-hop!~%")) + (setf seq-idx skip-seq-idx + elt (aref elts (if (i< seq-idx (length elts)) + seq-idx + 0))) + (loop + named :blank-hopping + while (iplusp num-blanks-active) do + (let* ((next-rack-pos (if (i< seq-idx (length elts)) + (perm-elt-change-pos elt) + 0)) + (bs (aref blank-states (i1- num-blanks-active)))) + ,(when debug-p + `(format t "num-blanks-active: ~a~%~ + next-rack-pos: ~a~%~ + (blank-state-rack-pos bs): ~a~%" + num-blanks-active next-rack-pos + (blank-state-rack-pos bs))) + (if (i<= next-rack-pos (blank-state-rack-pos bs)) + (progn + ,(when debug-p + `(format t "moving over blank (~a <= ~a)~%~ + (blank-state-idx bs): ~a ~ + (blank-state-limit bs): ~a~%" + next-rack-pos (blank-state-rack-pos bs) + (blank-state-idx bs) (blank-state-limit bs))) + (if (i< (blank-state-idx bs) (blank-state-limit bs)) + (let ((pe (aref elts (blank-state-seq-idx bs)))) + ,(when debug-p + `(format t " advancing blank...~%")) + (iincf (blank-state-idx bs)) + (setf seq-idx (blank-state-seq-idx bs) + move-over-blank-p t + rack-pos (blank-state-rack-pos bs) + length (i1+ rack-pos) + dawg-idx (aref rack-pos-dawg-idxs rack-pos) + node (aref nodes dawg-idx) + letter-idx (perm-elt-pos-value pe) + tile-id (aref (rack-tiles rack) letter-idx) + skip-seq-idx (perm-elt-next pe)) + (return-from :blank-hopping)) + (progn + ,(when debug-p + `(format t " deleting blank...~%")) + (idecf num-blanks-active)))) + (progn + (setf seq-idx skip-seq-idx) + (return-from :blank-hopping)))))) + . + ,(when debug-p + `((word-text () + (apply #'concatenate + (cons 'string + (loop + for idx below length + for tile-idx = (aref word idx) + for tile = (and (iplusp tile-idx) + (aref ,tiles tile-idx)) + collect (if tile + (tile-text tile) + "_"))))) + (node-string (bits) + (apply #'concatenate + (cons 'string + (loop + for letter fixnum below 26 + for tile = (aref ,tiles (i1+ letter)) + when (logbitp letter bits) + collect (tile-text tile))))) + (nth-child-letter (n) + ,(when debug-p + `(format t "looking for ~ath child-letter at ~a (~a)~%" + n dawg-idx (node-string node))) + (loop + with found = 0 + for letter below 26 ;; ick! + when (node-has-child letter) + do (if (i= found n) + (return-from + nth-child-letter + (i1+ letter)) + (iincf found))) + ,(when debug-p + `(format t "did not find ~ath child-letter at ~a (~a)~%" + n dawg-idx (node-string node))))))) + + (declare (dynamic-extent #'node-has-child + #'fast-child-idx + #'find-child-idx + #'fast-nth-child-letter + #'num-children + #'trimmed + #'blank-ps + #'process-word + #'process-word-in-all-placements + #'blank-hop)) + ,(when debug-p + `(declare (dynamic-extent #'word-text + #'node-string + #'nth-child-letter))) + + (unless move-over-blank-p + (setf elt (aref elts seq-idx) + rack-pos (perm-elt-change-pos elt) + letter-idx (perm-elt-pos-value elt) + dawg-idx (aref rack-pos-dawg-idxs rack-pos) + node (aref nodes dawg-idx) + skip-seq-idx (perm-elt-next elt) + tile-id (aref (rack-tiles rack) letter-idx) + letter-id +empty+ + length (i1+ rack-pos))) + + ,(when debug-p + `(format t "====================~%~ + START of the loop~%~ + seq-idx: ~a~%~ + num-blanks-active: ~a~%~ + move-over-blank-p: ~a~%~ + rack-pos: ~a~%~ + ====================~%" + seq-idx num-blanks-active move-over-blank-p + rack-pos)) + + (setf blank-state + (if (izerop num-blanks-active) + nil + (aref blank-states (i1- num-blanks-active)))) + + ,(when debug-p + `(format t "seq-idx: ~a~%" seq-idx)) + (when (and (i= tile-id blank-id) + (not move-over-blank-p)) + ,(when debug-p + `(format t "making new blank-state~%")) + (setf (aref blank-states num-blanks-active) + (make-blank-state :idx 0 + :limit (i1- (num-children)) + :rack-pos rack-pos + :seq-idx seq-idx) + blank-state (aref blank-states + num-blanks-active)) + (iincf num-blanks-active)) + + (setf move-over-blank-p nil) + + (if (and blank-state (i= tile-id blank-id)) + (progn + ,(when debug-p + `(format t "fast-nth: ~a slow-nth: ~a~%" + (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state)) + (nth-child-letter + (blank-state-idx blank-state)))) + ,(when debug-p + `(assert (i= (nth-child-letter + (blank-state-idx blank-state)) + (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state))))) + (setf letter-id (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state)) + #+nil (nth-child-letter (blank-state-idx blank-state)) + (blank-state-assignment blank-state) letter-id)) + (setf letter-id tile-id)) + + ,(when debug-p + `(format t "b-s: ~a~%" blank-state)) + + (setf (aref word rack-pos) letter-id) + + ,(when debug-p + `(format t "letter-id: ~a tile-id: ~a~%" + (tile-name (aref ,tiles letter-id)) + (tile-name (aref ,tiles tile-id)))) + + (let (#+nil (child-idx (find-child-idx (i1- letter-id))) + (child-idx (fast-child-idx dawg-idx letter-id))) + ,(when debug-p + `(let ((slow-child-idx (find-child-idx (i1- letter-id)))) + (when (iplusp child-idx) + (assert (equal child-idx slow-child-idx))))) + ,(when debug-p + `(format t "child-idx: ~a~%" child-idx)) + (if (iplusp child-idx) + (let* ((child (aref nodes child-idx)) + (new-dawg-idx (child-pointer child)) + (whole-word-p (child-terminates child))) + (progn + ,(when debug-p + `(progn + (if whole-word-p + (format t "~a" (word-text)) + (format t "~a" (string-downcase + (word-text)))))) + + (when whole-word-p + (process-word-in-all-placements)) + + (if (or (izerop new-dawg-idx) + (i= rack-pos max-rack-pos)) + (progn + ,(when debug-p + `(if (izerop new-dawg-idx) + (format t " has no extensions~%") + (format t " is as long as we have ~ + letters for~%"))) + + (blank-hop)) + + (progn + ,(when debug-p + `(format t " has extensions: ~a~%" + (node-string (aref nodes + new-dawg-idx)))) + (iincf seq-idx) + (setf (aref rack-pos-dawg-idxs + (i1+ rack-pos)) + new-dawg-idx))))) + (progn + ,(when debug-p + `(progn + (format t "start of new progn at the bottom~%~ + blank-state: ~a~%" + (when (iplusp num-blanks-active) + (aref blank-states + (i1- num-blanks-active)))))) + (blank-hop)))))) + result))) + +(def-move-finder findloud *standard* *english* + *twl* *vanilla* :all t) +(def-move-finder findquiet *standard* *english* + *twl* *vanilla* :all nil) +(def-move-finder topsquiet *standard* *english* + *twl* *vanilla* :tops nil) +(def-move-finder topvaluequiet *standard* *english* + *twl* *vanilla* :top-value nil) + +(defmacro o (rack) + (let ((s (gensym "s"))) + (if (symbolp rack) + (setf s (symbol-name rack)) + (setf s rack)) + `(findloud nil (new-rack ,s) nil))) + +(defmacro oq (rack) + (let ((s (gensym "s"))) + (if (symbolp rack) + (setf s (symbol-name rack)) + (setf s rack)) + `(findquiet nil (new-rack ,s) nil))) + +(defmacro tq (rack) + (let ((s (gensym "s"))) + (if (symbolp rack) + (setf s (symbol-name rack)) + (setf s rack)) + `(topsquiet nil (new-rack ,s) nil))) + +(defmacro os (rack) + `(mapcar (lambda (move) (move-string move *english*)) (o ,rack))) + +(defmacro oqs (rack) + `(mapcar (lambda (move) (move-string move *english*)) (oq ,rack))) + +(defmacro tqs (rack) + `(mapcar (lambda (move) (move-string move *english*)) (tq ,rack))) + +(defmacro experimental-def-move-finder (fn-name layout tiles + lexicon rules result-type debug-p) + `(defun ,fn-name (board unsorted-rack bag) + ,(if debug-p + `(declare (optimize debug)) + `(declare (optimize (speed 3) (safety 0) (space 1) (debug 0)))) + (declare (ignore board bag) + (type (simple-array tile) ,tiles)) + (let* ((sq-infos (board-sq-infos board)) + (rack (rack-sort unsorted-rack)) + (seq (unique-rack-perms rack)) + (elts (perm-seq-elts seq)) + (dawg (lexicon-dawg ,lexicon)) + (nodes (dawg-nodes dawg)) + (nth-child-letter-table (dawg-nth-child-letter-table dawg)) + (letter2child-table (dawg-letter2child-table dawg)) + (rack-pos-dawg-idxs (make-array (i1+ (rack-size rack)) + :element-type 'fixnum)) + (max-rack-pos (i1- (rack-size rack))) + (seq-idx 0) + (blank-states (make-array (i1+ (rack-size rack)))) + (move-over-blank-p nil) + (blank-state nil) + (num-blanks-active 0) + (blank-id ,(tiles-blank (symbol-value tiles))) + (blank-tile (aref ,tiles blank-id)) + (blank-quantity (tile-quantity blank-tile)) + (blank-designations (make-array blank-quantity :element-type 'fixnum)) + (word (make-array (the fixnum (rack-size rack)) :element-type 'fixnum)) + (letter-muls ,(layout-letter-muls (symbol-value layout))) + (word-muls ,(layout-word-muls (symbol-value layout))) + (center-row ,(layout-center-row (symbol-value layout))) + (center-col ,(layout-center-col (symbol-value layout))) + (bingo-bonus ,(rules-bingo-bonus (symbol-value rules))) + (elt nil) + (rack-pos nil) + (letter-idx nil) + (dawg-idx nil) + (node 0) + (skip-seq-idx nil) + (tile-id nil) + (letter-id +empty+) + (length 0) + (result ,(if (eq result-type :TOP-VALUE) + `MOST-NEGATIVE-FIXNUM + `nil))) + + (declare (ignore blank-designations) + (type (simple-array perm-elt) elts) + (type (simple-array fixnum) nodes) + ;(type (simple-array fixnum) nth-child-letter-table) + (type (simple-array (unsigned-byte 8)) nth-child-letter-table) + (type (simple-array (unsigned-byte 32)) letter2child-table) + (type fixnum node) + (type (simple-array fixnum) rack-pos-dawg-idxs)) + + ,(when debug-p + `(format t "rack has ~a permutations~%" + (length elts))) + + (loop while (i< seq-idx (length elts)) do + (labels ((node-has-child (child-letter) + (logbitp (the fixnum child-letter) node)) + + (find-child-idx (child-letter) + (when (node-has-child child-letter) + (i+ dawg-idx + (node-letter-offset node child-letter)))) + + (fast-child-idx (idx child-letter) + (aref letter2child-table (i+ (i* 32 idx) child-letter))) + + (fast-nth-child-letter (idx n) + (aref nth-child-letter-table (i+ (i* 32 idx) n))) + + (num-children () + (declare (type (simple-vector 28) *mask*) + (type (simple-vector #.(ash 1 13)) + *one-bits-per-13*)) + (let ((first-13 (ilogand node (mask 13))) + (second-13 (iash node -13))) + (i+ (aref *one-bits-per-13* first-13) + (aref *one-bits-per-13* second-13)))) + + (trimmed () + (declare (sb-ext:muffle-conditions + sb-ext:compiler-note)) + (subseq word 0 length)) + + (blank-ps () + (let ((bps (make-array length :initial-element nil))) + (loop + for idx below num-blanks-active + for bs across blank-states + for rack-pos = (blank-state-rack-pos bs) + do (setf (aref bps rack-pos) t)) + bps)) + + (process-word (start-col) + (let* ((word-mul-product 1) + (bps (blank-ps)) + (bingo-p (i= length (rack-capacity rack))) + (score + (loop + with sum = 0 + with row = center-row + for col from start-col + for idx below length + for tile-idx = (aref word idx) + for tile = (aref ,tiles tile-idx) + for tile-score = (tile-score tile) + for letter-mul = (aref letter-muls row col) + for word-mul = (aref word-muls row col) + do + (setf word-mul-product + (i* word-mul-product word-mul)) + (unless (aref bps idx) + (iincf sum (i* letter-mul tile-score))) + finally (return sum))) + (score (i* score word-mul-product)) + (score (if bingo-p + (i+ score bingo-bonus) + score))) + (macrolet ((make-this-move () + `(make-move + :action :place + :bingo-p bingo-p + :score score + :direction :horizontal + :start-row center-row + :start-col start-col + :word (trimmed) + :blank-ps bps + :tiles (trimmed) + :already-on-board-ps + (make-array length + :element-type 'boolean + :initial-element nil)))) + ,(when (eq :TOP-VALUE result-type) + `(setf result (imax result score))) + ,(when (eq :TOPS result-type) + `(let ((top-score (if result + (move-score + (first result)) + MOST-NEGATIVE-FIXNUM))) + (cond ((i> score top-score) + (setf result (list (make-this-move)))) + ((i= score top-score) + (push (make-this-move) result))))) + ,(when (eq :ALL result-type) + `(push (make-this-move) result))))) + + (process-word-in-all-placements () + #+nil + ,(when debug-p + `(format t "processing word in all placements~%")) + (loop + with min-col = (i- center-col (i1- length)) + for start-col from min-col to center-col do + (process-word start-col))) + + (blank-hop () + ,(when debug-p + `(format t "do the blank-hop!~%")) + (setf seq-idx skip-seq-idx + elt (aref elts (if (i< seq-idx (length elts)) + seq-idx + 0))) + (loop + named :blank-hopping + while (iplusp num-blanks-active) do + (let* ((next-rack-pos (if (i< seq-idx (length elts)) + (perm-elt-change-pos elt) + 0)) + (bs (aref blank-states (i1- num-blanks-active)))) + ,(when debug-p + `(format t "num-blanks-active: ~a~%~ + next-rack-pos: ~a~%~ + (blank-state-rack-pos bs): ~a~%" + num-blanks-active next-rack-pos + (blank-state-rack-pos bs))) + (if (i<= next-rack-pos (blank-state-rack-pos bs)) + (progn + ,(when debug-p + `(format t "moving over blank (~a <= ~a)~%~ + (blank-state-idx bs): ~a ~ + (blank-state-limit bs): ~a~%" + next-rack-pos (blank-state-rack-pos bs) + (blank-state-idx bs) (blank-state-limit bs))) + (if (i< (blank-state-idx bs) (blank-state-limit bs)) + (let ((pe (aref elts (blank-state-seq-idx bs)))) + ,(when debug-p + `(format t " advancing blank...~%")) + (iincf (blank-state-idx bs)) + (setf seq-idx (blank-state-seq-idx bs) + move-over-blank-p t + rack-pos (blank-state-rack-pos bs) + length (i1+ rack-pos) + dawg-idx (aref rack-pos-dawg-idxs rack-pos) + node (aref nodes dawg-idx) + letter-idx (perm-elt-pos-value pe) + tile-id (aref (rack-tiles rack) letter-idx) + skip-seq-idx (perm-elt-next pe)) + (return-from :blank-hopping)) + (progn + ,(when debug-p + `(format t " deleting blank...~%")) + (idecf num-blanks-active)))) + (progn + (setf seq-idx skip-seq-idx) + (return-from :blank-hopping)))))) + . + ,(when debug-p + `((word-text () + (apply #'concatenate + (cons 'string + (loop + for idx below length + for tile-idx = (aref word idx) + for tile = (and (iplusp tile-idx) + (aref ,tiles tile-idx)) + collect (if tile + (tile-text tile) + "_"))))) + (node-string (bits) + (apply #'concatenate + (cons 'string + (loop + for letter fixnum below 26 + for tile = (aref ,tiles (i1+ letter)) + when (logbitp letter bits) + collect (tile-text tile))))) + (nth-child-letter (n) + ,(when debug-p + `(format t "looking for ~ath child-letter at ~a (~a)~%" + n dawg-idx (node-string node))) + (loop + with found = 0 + for letter below 26 ;; ick! + when (node-has-child letter) + do (if (i= found n) + (return-from + nth-child-letter + (i1+ letter)) + (iincf found))) + ,(when debug-p + `(format t "did not find ~ath child-letter at ~a (~a)~%" + n dawg-idx (node-string node))))))) + + (declare (dynamic-extent #'node-has-child + #'fast-child-idx + #'find-child-idx + #'fast-nth-child-letter + #'num-children + #'trimmed + #'blank-ps + #'process-word + #'process-word-in-all-placements + #'blank-hop)) + ,(when debug-p + `(declare (dynamic-extent #'word-text + #'node-string + #'nth-child-letter))) + + (unless move-over-blank-p + (setf elt (aref elts seq-idx) + rack-pos (perm-elt-change-pos elt) + letter-idx (perm-elt-pos-value elt) + dawg-idx (aref rack-pos-dawg-idxs rack-pos) + node (aref nodes dawg-idx) + skip-seq-idx (perm-elt-next elt) + tile-id (aref (rack-tiles rack) letter-idx) + letter-id +empty+ + length (i1+ rack-pos))) + + ,(when debug-p + `(format t "====================~%~ + START of the loop~%~ + seq-idx: ~a~%~ + num-blanks-active: ~a~%~ + move-over-blank-p: ~a~%~ + rack-pos: ~a~%~ + ====================~%" + seq-idx num-blanks-active move-over-blank-p + rack-pos)) + + (setf blank-state + (if (izerop num-blanks-active) + nil + (aref blank-states (i1- num-blanks-active)))) + + ,(when debug-p + `(format t "seq-idx: ~a~%" seq-idx)) + (when (and (i= tile-id blank-id) + (not move-over-blank-p)) + ,(when debug-p + `(format t "making new blank-state~%")) + (setf (aref blank-states num-blanks-active) + (make-blank-state :idx 0 + :limit (i1- (num-children)) + :rack-pos rack-pos + :seq-idx seq-idx) + blank-state (aref blank-states + num-blanks-active)) + (iincf num-blanks-active)) + + (setf move-over-blank-p nil) + + (if (and blank-state (i= tile-id blank-id)) + (progn + ,(when debug-p + `(format t "fast-nth: ~a slow-nth: ~a~%" + (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state)) + (nth-child-letter + (blank-state-idx blank-state)))) + ,(when debug-p + `(assert (i= (nth-child-letter + (blank-state-idx blank-state)) + (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state))))) + (setf letter-id (fast-nth-child-letter + dawg-idx + (blank-state-idx blank-state)) + #+nil (nth-child-letter (blank-state-idx blank-state)) + (blank-state-assignment blank-state) letter-id)) + (setf letter-id tile-id)) + + ,(when debug-p + `(format t "b-s: ~a~%" blank-state)) + + (setf (aref word rack-pos) letter-id) + + ,(when debug-p + `(format t "letter-id: ~a tile-id: ~a~%" + (tile-name (aref ,tiles letter-id)) + (tile-name (aref ,tiles tile-id)))) + + (let (#+nil (child-idx (find-child-idx (i1- letter-id))) + (child-idx (fast-child-idx dawg-idx letter-id))) + ,(when debug-p + `(let ((slow-child-idx (find-child-idx (i1- letter-id)))) + (when (iplusp child-idx) + (assert (equal child-idx slow-child-idx))))) + ,(when debug-p + `(format t "child-idx: ~a~%" child-idx)) + (if (iplusp child-idx) + (let* ((child (aref nodes child-idx)) + (new-dawg-idx (child-pointer child)) + (whole-word-p (child-terminates child))) + (progn + ,(when debug-p + `(progn + (if whole-word-p + (format t "~a" (word-text)) + (format t "~a" (string-downcase + (word-text)))))) + + (when whole-word-p + (process-word-in-all-placements)) + + (if (or (izerop new-dawg-idx) + (i= rack-pos max-rack-pos)) + (progn + ,(when debug-p + `(if (izerop new-dawg-idx) + (format t " has no extensions~%") + (format t " is as long as we have ~ + letters for~%"))) + + (blank-hop)) + + (progn + ,(when debug-p + `(format t " has extensions: ~a~%" + (node-string (aref nodes + new-dawg-idx)))) + (iincf seq-idx) + (setf (aref rack-pos-dawg-idxs + (i1+ rack-pos)) + new-dawg-idx))))) + (progn + ,(when debug-p + `(progn + (format t "start of new progn at the bottom~%~ + blank-state: ~a~%" + (when (iplusp num-blanks-active) + (aref blank-states + (i1- num-blanks-active)))))) + (blank-hop)))))) + result))) |