#lang racket
(require csc151)
(require csc151/counters)
(provide (all-defined-out))

;;; File:
;;;   insertion-sort-lab.rkt
;;; Authors:
;;;   Janet Davis
;;;   Titus Klinge
;;;   Samuel A. Rebelsky
;;;   Jerod Weinman
;;;   YOUR NAME HERE
;;; Summary:
;;;   Starting code for the lab on insertion sort.

; +---------------------+------------------------------------------------------
; | Procedures Provided |
; +---------------------+

;;; Procedure:
;;;   insert-number
;;; Parameters:
;;;   sorted, a list of real numbers
;;;   new-element, a real number
;;; Purpose:
;;;   Insert new-element into sorted.
;;; Produces:
;;;   new-ls, a new list of real numbers
;;; Preconditions:
;;;   sorted is a list of numbers arranged in increasing order.   That is,
;;;   (<= (list-ref sorted i) (list-ref sorted (+ i 1)))
;;;   for all reasonable values of i.  [Unverified]
;;; Postconditions:
;;;   * new-ls is a list of numbers arranged in increasing order.
;;;   * new-ls is a permutation of (cons new-element sorted).
(define insert-number
  (lambda (sorted new-element)
    (cond 
      [(null? sorted) 
       (list new-element)]
      [(<= new-element (car sorted)) 
       (cons new-element sorted)]
      [else 
       (cons (car sorted) 
             (insert-number (cdr sorted) new-element))])))

;;; Procedure:
;;;   numbers-insertion-sort
;;; Parameters:
;;;   numbers, a list of real numbers
;;; Purpose:
;;;   Sorts numbers
;;; Produces:
;;;   sorted, a list of real numbers
;;; Preconditions:
;;;   [none]
;;; Postconditions:
;;;   * sorted is a list of real numbers.
;;;   * sorted is organized in increasing order.  That is, 
;;;     (<= (list-ref sorted i) (list-ref sorted (+ i 1)))
;;;     for all reasonable values of i.
;;;   * sorted is a permutation of numbers.
(define numbers-insertion-sort
  (lambda (numbers)
    (let kernel ([unsorted numbers]  ; The remaining unsorted values
                 [sorted null])      ; The sorted values
      (if (null? unsorted) 
          sorted
          (kernel (cdr unsorted) (insert-number sorted (car unsorted)))))))

;;; Procedure:
;;;   list-insertion-sort
;;; Parameters:
;;;   lst, a list to be sorted
;;;   may-precede?, a binary predicate
;;; Purpose:
;;;   Sort lst.
;;; Produces:
;;;   sorted, a list.
;;; Preconditions:
;;;   * may-precede? can be used with the elements of lst. That is for
;;;     all values a and b in lst, (may-precede? a b) successfully
;;;     returns a truth value.
;;;   * may-precede? is transitive.  That is, for all values a, b, and 
;;;     c in lst, if (may-precede? a b) and (may-precede? b c), then
;;;     (may-precede? a c).
;;;   * may-precede? is sensible.  That is, for all values a and b,
;;;     either (may-precede? a b), (may-precede? b a), or both.
;;; Postconditions:
;;;   * sorted is sorted.  That is, for all reasonable i,
;;;     (may-precede? (list-ref lst i) (list-ref lst (increment i)))
;;;   * sorted is a permutation of lst.
(define list-insertion-sort
  (lambda (lst may-precede?)
    (letrec ([insert
              (lambda (lst val)
                (cond
                  [(null? lst)
                   (list val)]
                  [(may-precede? val (car lst))
                   (cons val lst)]
                  [else
                   (cons (car lst) (insert (cdr lst) val))]))]
             [kernel
              (lambda (unsorted sorted)
                (if (null? unsorted) 
                    sorted
                    (kernel (cdr unsorted) (insert sorted (car unsorted)))))])
      (kernel lst null))))

;;; Procedure:
;;;   list-keyed-insertion-sort
;;; Parameters:
;;;   lst, a list
;;;   get-key, a procedure
;;;   may-precede?, a binary predicate
;;; Purpose:
;;;   Sort lst.
;;; Produces:
;;;   sorted, a list
;;; Preconditions:
;;;   * get-key? can be applied to each element of lst.
;;;   * may-precede? can be used with the values returned by get-key. That is 
;;;     for all values a and b in lst, (may-precede? (get-key a) (get-key b)) 
;;;     successfully returns a truth value.
;;;   * may-precede? is transitive.  That is, for all keys a, b, and 
;;;     c, if (may-precede? a b) and (may-precede? b c), then
;;;     (may-precede? a c).
;;;   * may-precede? is sensible.  That is, for all keys a and b,
;;;     (may-precede? a b) holds, (may-precede? b a) holds, or both
;;;     hold.
;;; Postconditions:
;;;   * sorted is sorted by key using may-precede?.  That is, for all i 
;;;     such that 0 <= i < (- (length lst) 1),
;;;     (may-precede? (get-key (list-ref sorted i))
;;;                   (get-key (list-ref sorted (+ i 1))))
;;;   * sorted is a permutation of lst.
(define list-keyed-insertion-sort
  (lambda (lst get-key may-precede?)
    (list-insertion-sort lst
                         (lambda (v1 v2)
                           (may-precede? (get-key v1) (get-key v2))))))

;;; Procedure:
;;;   vector-insert!
;;; Parameters:
;;;   vec, a vector of values
;;;   new-element, a value
;;;   boundary, an index into the vector
;;;   may-precede?, a binary predicate
;;; Purpose:
;;;   Insert new-element into the portion of vec between 0 and
;;;   boundary, inclusive.
;;; Produces:
;;;   [Nothing; called for side effects.]
;;; Preconditions:
;;;   * 0 <= boundary < (vector-length vec)
;;;   * The elements in positions 0..boundary-1 of vec are sorted.
;;;     That is, (may-precede? (vector-ref vec i) (vector-ref vec (+ i 1)))
;;;     for all 0 <= i < boundary-2.
;;;   * may-precede? is transitive and sensible.
;;; Postconditions:
;;;   * The elements in positions 0..boundary of vec are sorted.
;;;     That is, (may-precede? (vector-ref vec i) (vector-ref vec (+ i 1)))
;;;     for all 0 <= i < boundary.
;;;   * The elements in positions 0..boundary of vec after insert! finishes
;;;     are a permutation of new-element and the elements that were in 
;;;     positions 0..(boundary-1) before the procedure started.
(define vector-insert!
  (lambda (vec new-element boundary may-precede?)
    (let kernel ((pos boundary))
      (cond 
        ; If we've reached the left end of the vector, we've run out of
        ; elements to shift.  Insert the new element.
        [(zero? pos)  
         (vector-set! vec pos new-element)]
        ; If we've reached a point at which the element to the left
        ; is smaller, we insert the new element here.
        [(may-precede? (vector-ref vec (- pos 1)) new-element)
         (vector-set! vec pos new-element)]
        ; Otherwise, we shift the current element to the right and
        ; continue.
        [else
         (vector-set! vec pos (vector-ref vec (- pos 1)))
         (kernel (- pos 1))]))))

;;; Procedure:
;;;   vector-insertion-sort!
;;; Parameters:
;;;   vec, a vector 
;;;   may-precede?, a binary predicate
;;; Purpose:
;;;   Sorts the vector.
;;; Produces:
;;;   [Nothing; sorts in place]
;;; Preconditions:
;;;   vec is a vector.
;;;   may-precede? can be applied to any two elements of vec.
;;;   may-precede? is transitive.
;;; Postconditions:
;;;   The final state of vec is a permutation of the original state.
;;;   vec is sorted.  That is, 
;;;     (may-precede? (vector-ref vec i) (vector-ref vec (+ i 1)))
;;;     for all reasonable values of i.
(define vector-insertion-sort!
  (lambda (vec may-precede?)
    (let ([len (vector-length vec)])
      (let kernel ([boundary 1]) ; The index of the first unsorted value
        (when (< boundary len) ; If we have elements left to sort
          (vector-insert! vec 
                          (vector-ref vec boundary) 
                          boundary
                          may-precede?)
          (kernel (+ boundary 1)))))))

; +------+---------------------------------------------------------------------
; | Data |
; +------+

;;; Values:
;;;   grinnell-directory
;;;   grinnell-directory-annotated
;;; Type:
;;;   List of lists.
;;; Note:
;;;   * Each sublist is of length at least four and contains a last
;;;     name, a first name, a username, a phone number, and an
;;;     optional sequence of annotations.
;;;   * The
;;; Contents:
;;;   A list of people at Grinnell with contact information and some
;;;   useful attributes.
(define grinnell-directory
  (list
   (list "Rebelsky"        "Samuel"  "messy-office" "4410")
   (list "Klinge"          "Titus"   "cauldron"     "3271")
   (list "Osera"           "Michael" "peter"        "4010")
   (list "Weinman"         "Jerod"   "map-reader"   "9812")
   (list "Osera"           "PM"      "type-snob"    "4010")
   (list "Curtsinger"      "Charlie" "systems-guy"  "3127")
   (list "Vostinar"        "Anya"    "cache"        "4306")
   (list "Rebelsky"        "Spam"    "emailer"      "4410")
   (list "Osera"           "MP"      "fast-typist"  "4010")
   (list "Dahlby-Albright" "Sarah"   "cheery-coach" "4362")
   (list "Osera"           "Peter"   "michael"      "4010")
   (list "Rodrigues"       "Liz"     "vivero"       "3362")
   (list "Rebelsky"        "Essay"   "muser"        "4410")
   (list "Barks"           "Sarah"   "stem-careers" "4940")
   (list "Kington"         "Raynard" "the-prez"     "3000")))

(define grinnell-directory-annotated
  (list
   (list "Rebelsky"        "Samuel"  "messy-office" "4410"
         "CSC" "151prof" "DigHum" "Professor")
   (list "Osera"           "Michael" "peter"        "4010"
         "CSC" "fictitious")
   (list "Klinge"          "Titus"   "cauldron"     "3271"
         "CSC" "Assistant" "151prof")
   (list "Weinman"         "Jerod"   "map-reader"   "9812"
         "CSC" "Chair" "Associate" "NSF Grant")
   (list "Osera"           "PM"      "type-snob"    "4010"
         "Assistant" "NSF Grant" "Tutorial" "CSC")
   (list "Curtsinger"      "Charlie" "systems-guy"  "3127"
         "CSC" "Assistant" "Tutorial" "ASFAC")
   (list "Vostinar"        "Anya"    "cache"        "4306"
         "CSC" "Assistant" "Interdisciplinary")
   (list "Rebelsky"        "Spam"    "emailer"      "4410"
         "CSC" "fictitious")
   (list "Osera"           "MP"      "fast-typist"  "4010"
         "CSC" "fictitious")
   (list "Dahlby-Albright" "Sarah"   "cheery-coach" "4362"
         "Statistics" "CSC" "Outreach")
   (list "Osera"           "Peter"   "michael"      "4010"
         "CSC" "fictitious")
   (list "Rodrigues"       "Liz"     "vivero"       "3362"
         "LIB" "DigHum" "Assistant" )
   (list "Rebelsky"        "Essay"   "muser"        "4410"
         "CSC" "fictitious")
   (list "Barks"           "Sarah"   "stem-careers" "4940"
         "CLS" "STEM" "Neuroscience")
   (list "Kington"         "Raynard" "the-prez"     "3000"
         "Bigwig")))

; +-------+--------------------------------------------------------------------
; | Added |
; +-------+

