;; Quicksort Implementation
;; Demonstrates list operations, filtering, and recursive algorithms

(import assert :refer :all)
(import binding :refer :all)
(import control :refer :all)
(import display :refer :all)
(import looping :refer :all)
(import threading :refer :all)

;; ============================================================================
;; Classic Quicksort
;; ============================================================================

(define quicksort
  (lambda (lst)
    (if (null? lst)
        (list)
        (let* ((pivot (car lst))
               (rest-lst (cdr lst))
               (smaller (filter (lambda (x) (< x pivot)) rest-lst))
               (greater (filter (lambda (x) (>= x pivot)) rest-lst)))
          (append (append (quicksort smaller)
                         (list pivot))
                  (quicksort greater))))))

(println "Quicksort Examples:")
(assert-equal (list 1 1 2 3 4 5 6 9) (quicksort (list 3 1 4 1 5 9 2 6)))
(println (string-concat "Sort [3 1 4 1 5 9 2 6]: " (quicksort (list 3 1 4 1 5 9 2 6))))
(assert-equal (list 1 2 3 4 5) (quicksort (list 5 4 3 2 1)))
(println (string-concat "Sort [5 4 3 2 1]: " (quicksort (list 5 4 3 2 1))))
(assert-equal (list 1) (quicksort (list 1)))
(println (string-concat "Sort [1]: " (quicksort (list 1))))
(assert-equal (list) (quicksort (list)))
(println (string-concat "Sort []: " (quicksort (list))))

;; ============================================================================
;; Three-way Partition Quicksort (handles duplicates better)
;; ============================================================================

(define quicksort-3way
  (lambda (lst)
    (if (null? lst)
        (list)
        (let* ((pivot (car lst))
               (rest-lst (cdr lst))
               (smaller (filter (lambda (x) (< x pivot)) rest-lst))
               (equal (filter (lambda (x) (= x pivot)) rest-lst))
               (greater (filter (lambda (x) (> x pivot)) rest-lst)))
          (append (append (quicksort-3way smaller)
                          (cons pivot equal))
                  (quicksort-3way greater))))))

(println "\nThree-way Quicksort:")
(assert-equal (list 1 1 2 3 3 4 5 5 6 9) (quicksort-3way (list 3 1 4 1 5 9 2 6 5 3)))
(println (string-concat "Sort [3 1 4 1 5 9 2 6 5 3]: "
              (quicksort-3way (list 3 1 4 1 5 9 2 6 5 3))))

;; ============================================================================
;; Using partition to split list
;; ============================================================================

(define partition-by-pivot
  (lambda (pivot lst)
    (let ((smaller (filter (lambda (x) (< x pivot)) lst))
          (greater (filter (lambda (x) (>= x pivot)) lst)))
      (list smaller greater))))

(println "\nPartition Example:")
(let ((result (partition-by-pivot 5 (list 3 7 2 9 1 5 8 4))))
  (assert-equal (list 3 2 1 4) (car result))
  (assert-equal (list 7 9 5 8) (car (cdr result)))
  (println (string-concat "Partition by 5: smaller=" (car result)
                " greater=" (car (cdr result)))))

;; ============================================================================
;; Demonstrating list operations
;; ============================================================================

(println "\nList Operations Demo:")

;; take and drop
(define data (list 10 20 30 40 50))
(println (string-concat "Original: " data))
(assert-equal (list 10 20 30) (take 3 data))
(println (string-concat "Take 3: " (take 3 data)))
(assert-equal (list 40 50) (drop 3 data))
(println (string-concat "Drop 3: " (drop 3 data)))

;; reverse
(assert-equal (list 50 40 30 20 10) (reverse data))
(println (string-concat "Reversed: " (reverse data)))

;; map to transform
(assert-equal (list 20 40 60 80 100) (map (lambda (x) (* x 2)) data))
(println (string-concat "Double all: " (map (lambda (x) (* x 2)) data)))

;; reduce to aggregate
(assert-equal 150 (reduce + data))
(println (string-concat "Sum: " (reduce + data)))
(assert-equal 12000000 (reduce * data))
(println (string-concat "Product: " (reduce * data)))

;; ============================================================================
;; Merge Sort for comparison
;; ============================================================================

(define merge
  (lambda (left right)
    (cond
      ((null? left) right)
      ((null? right) left)
      ((< (car left) (car right))
       (cons (car left) (merge (cdr left) right)))
      (else
       (cons (car right) (merge left (cdr right)))))))

(define mergesort
  (lambda (lst)
    (if (<= (length lst) 1)
        lst
        (let* ((mid (/ (length lst) 2))
               (left (take mid lst))
               (right (drop mid lst)))
          (merge (mergesort left) (mergesort right))))))

(println "\nMergesort Example:")
(assert-equal (list 1 1 2 3 4 5 6 9) (mergesort (list 3 1 4 1 5 9 2 6)))
(println (string-concat "Sort [3 1 4 1 5 9 2 6]: " (mergesort (list 3 1 4 1 5 9 2 6))))

(define sorted-small (quicksort (list 3 1 4)))
(define merge-sorted (mergesort (list 3 1 4 1 5 9 2 6)))
(assert-equal (list 1 3 4) sorted-small)
(assert-equal (list 1 1 2 3 4 5 6 9) merge-sorted)

(println "\nExample complete!")
