;;;;assign-tasks
;;;
;;; A program to assign a given list of tasks to people
;;; depending on their skills and time they have available.
;;; There is no real error checking that initial parameters
;;; are in the proper format.
;;;
;;; Author: Zach Tomaszewski
;;; Date: 21 October 2002
;;;

;;;assign-tasks
;;; Takes a list of tasks to do: (taskname tasktype tasktime)
;;;  followed by a list of people and their hours: (person . hours)
;;;  followed by a list of people capable of each task type: 
;;;    (tasktype (person person))
;;; Returns a list of assigned tasks: (taskname person)
;;;   if all tasks can be assigned, otherwise return 'FAIL

(defun assign-tasks (tasks people capable)
  (cond
    ((null tasks)())
    (t 
      (assign-one-task
        (car tasks)       ;the one task
        (cadr (assoc (cadr(car tasks)) capable )) ;those capable of it
        (cdr tasks) people capable   ;the rest of the tasks and info
      )
    )
  )
)


;;;assign-one-task
;;;Takes: 
;;;  a single task to assign: (taskname tasktype tasktime)
;;;  a list of people eligible/capable to do that task: (person ...)
;;;  the list of the rest of the tasks to assign: (taskname tasktype tasktime)
;;;  the list of times each person has: (person . hours)
;;;  and the list of people capable of each task type: 
;;;    (tasktype (person person))
;;;Returns:
;;;  the assignment of the current single task (taskname person)
;;;  concatanated to the assignments of rest of the tasks
;;;;  (by calling assign-tasks).
;;;  If assignment of all tasks is impossible, returns fail.

(defun assign-one-task (onetask eligible tasks people capable)

  ;;if eligible is null or no time for the person, we can't assign this task
  (if (or (null eligible) (null (assoc (car eligible) people) ))
    'FAIL
    ;;...otherwise
    ;;if first eligible person has enough time
    ;; and such an assignment doesn't throw everything off
    (if (and (>= (cdr (assoc (car eligible) people)) 
                 (caddr onetask))       
             (not (equal 'FAIL (assign-tasks tasks
                   (reduce-hours (car eligible) (caddr onetask) people) 
                    capable)) 
             )
        )
     ;;then return this match along with the next
        (cons (list (car onetask)(car eligible))
              (assign-tasks tasks 
                  (reduce-hours (car eligible) (caddr onetask) people) 
                   capable)
        )
     ;;else move along the eligible list
        (assign-one-task onetask (cdr eligible) tasks people capable)
    )
  )
)


;;;Given a name, an amount to reduce by, and list of (people . hours) pairs,
;;; this function will return the list with that person's hours reduced.

(defun reduce-hours (name hours people)
  (substitute (cons name (- (cdr (assoc name people)) hours))
             (assoc name people)
              people
  ) 
)