(defun roll ((count i64) (sides i64))
(-> (MSet i64) Intermediates)
(let* ((result (Roll count sides))
(annotation (Annotate result (Annotation::Roll count sides))))
(return result annotation)))
(defun simple_filter ((count i64) (sides i64) (keep_count i64) (kind i64))
(-> (MSet i64) Intermediates)
(let* ((initial (roll count sides))
(filtered (Decision kind
(0 (KeepHigh keep_count &initial))
(1 (KeepLow keep_count &initial))
(2 (DropHigh (- count keep_count) &initial))
(3 (DropLow (- count keep_count) &initial)))))
(PushToList initial &list)
(PushToList filtered &list)
(return filtered (Annotate list (Decision kind
(0 (Annotation::KeepHigh keep_count))
(1 (Annotation::KeepLow keep_count))
(2 (Annotation::DropHigh (- count keep_count)))
(3 (Annotation::DropLow (- count keep_count))))))))
(defun explode ((count i64) (sides i64))
(-> i64 Intermediates)
(let ((iterations (MakeList))
(sum 0)
(remaining_count count))
(do
(UseFuel (saturating_mul count 4))
(let ((iteration (Roll remaining_count sides)))
(+= sum (Summate &iteration))
(PushToList iteration &iterations)
(set remaining_count (Count (FilterSatisfies iteration (lambda ((die i64)) (eq die sides))))))
(while (> remaining_count 0)))
(let ((intermediate (Annotate iterations (Annotation::Explode count sides))))
(return sum intermediate))))
(defun filter_satisfies ((predicate (Function i64 -> bool))
(dice (MSet i64)))
(-> (MSet i64))
(if (> (Length dice) 0)
(let ((idx 0))
(do
(if (not (predicate (index idx dice)))
(SwapRemove idx dice))
(while (> (Length dice) idx)))
dice)
dice))