Skip to content

Commit c6dde73

Browse files
committed
Update the pyramid-flags calculation algorithm.
This is a slightly slower but simpler recursive process to calculate all the 1430 valid pyramid-flags values.
1 parent c0f3dde commit c6dde73

1 file changed

Lines changed: 19 additions & 33 deletions

File tree

src/pyramid-solver.lisp

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -92,39 +92,25 @@ The bits refer to the pyramid cards in this order:
9292
"Return a vector of all 1430 valid PYRAMID-FLAGS values.
9393
The rule is a pyramid card can't be removed unless all the cards covering it
9494
from below are removed first."
95-
(labels ((power-set (list)
96-
"Return a list of all subsets of elements in the list."
97-
(loop with length = (length list)
98-
for flags from 0 below (ash 1 length)
99-
collect (loop for index from 0 below length
100-
when (logbitp index flags)
101-
collect (elt list index))))
102-
(optional-masks (bits num-bits)
103-
"Return a list of masks indicating previous row optional cards."
104-
(loop for i from 0 to (- num-bits 2)
105-
for mask = #b11 then (ash mask 1)
106-
unless (logtest mask bits)
107-
collect (ash 1 i)))
108-
(previous-rows (bits num-bits)
109-
"Return all valid card existence bit flags for the previous row."
110-
(loop with all-bits-on = (1- (ash 1 (1- num-bits)))
111-
for masks in (power-set (optional-masks bits num-bits))
112-
collect (logandc2 all-bits-on (reduce #'logior masks))))
113-
(pyramid-flags (&rest row-flags)
114-
"Return a PYRAMID-FLAGS given card existence bits for each row."
115-
(reduce #'logior (mapcar #'ash row-flags '(0 1 3 6 10 15 21)))))
116-
(let ((all '()))
117-
;; for all possible combinations of cards on the bottom row, calculate
118-
;; all possible combinations of cards for each previous row, then combine
119-
;; them all into PYRAMID-FLAGS values
120-
(dotimes (r7 (ash 1 7) (sort (coerce all 'vector) #'<))
121-
(dolist (r6 (previous-rows r7 7))
122-
(dolist (r5 (previous-rows r6 6))
123-
(dolist (r4 (previous-rows r5 5))
124-
(dolist (r3 (previous-rows r4 4))
125-
(dolist (r2 (previous-rows r3 3))
126-
(dolist (r1 (previous-rows r2 2))
127-
(push (pyramid-flags r1 r2 r3 r4 r5 r6 r7) all)))))))))))
95+
(labels ((make-pyramid-flags (pyramid)
96+
(reduce #'logior (mapcar #'ash pyramid '(0 1 3 6 10 15 21))))
97+
(valid-row-p (row row-size next-row)
98+
(loop for i from 0 below row-size
99+
always (or (logbitp i row)
100+
(zerop (mask-field (byte 2 i) next-row)))))
101+
(add-row (row-size pyramids)
102+
(loop for row from 0 below (ash 1 row-size)
103+
nconc (loop for pyramid in pyramids
104+
when (valid-row-p row row-size (first pyramid))
105+
collect (cons row pyramid))))
106+
(build-flags (row-size pyramids)
107+
(if (zerop row-size)
108+
(sort (map 'vector #'make-pyramid-flags pyramids) #'<)
109+
(build-flags (1- row-size) (add-row row-size pyramids)))))
110+
;; This needs to be fast or there will be delays during compilation.
111+
;; Basically this builds valid pyramids recursively bottom-up as lists of
112+
;; row flags, then converts each pyramid into a pyramid-flags value.
113+
(build-flags 6 (loop for row from 0 below (ash 1 7) collect (list row)))))
128114

129115
(defvar *pyramid-flags* (all-pyramid-flags)
130116
"All valid PYRAMID-FLAGS values.")

0 commit comments

Comments
 (0)