;; My solution (named interp-dave). 
;; Used to compare with student's interp function.
;; helper function is named getval

;; getval consumes either a list or a number and produces a number.
;;
;;  (getval e) determines whether e is a number or a list.
;;  if it is a number, the number is returned.
;;  if e is a list, getval evaluates the list by calling
;;     interp on it and returns the value produces by interp

(define (getval e)
  (cond
    [(list? e) (interp e)]
    [(number? e) e]
    [ else 
      (error 'geval "Unknown thingy!")]))

;; ============================================================
;; NOTE: for grading this is called interp-dave, but this is the
;; same function as interp...

;; interp consumes a list and produces a number.
;;
;; (interp l) evaulate lists that contain elements according to the
;;  rules below. Note that each list l described some computation to
;;  be performed, interp does this computation.
;;
;;  valid lists contain 3 elements. The middle element must be one of
;;   the following: 'plus, 'minus, 'times, 'div. These correspond to the
;;   arithmetic operations addition, subtraction, multplication and division.
;;
;;   the first and last elements of l must either be numbers, or lists
;;   which follow the same rules as the format for l. 
;;
;; sample usage:
;;   (interp '(3 plus 5))

(define (interp-dave l)
  (cond 
   ;; doing addition? if so use getval to evaluate the first and third
   ;;  elements of l, then do the addition
   [(symbol=? (first (rest l)) 'plus)
	(+ (getval (first l)) (getval (third l)))]
   ;; doing subtraction? if so use getval to evaluate the first and third
   ;;  elements of l, then do the subtraction
   [(symbol=? (first (rest l)) 'minus)
	(- (getval (first l)) (getval (third l)))]
   ;; doing multiplication? if so use getval to evaluate the first and third
   ;;  elements of l, then do the multiply
   [(symbol=? (first (rest l)) 'times)
	(* (getval (first l)) (getval (third l)))]
   ;; doing division? if so use getval to evaluate the first and third
   ;;  elements of l, then do the divide
   [(symbol=? (first (rest l)) 'div)
	(/ (getval (first l)) (getval (third l)))]
   [ else 
	 ;; oops - unknown operator
      (error 'interp "Unknown operator")]))



;;
;; =============================================================
;; CODE BELOW IS USED FOR TESTING INTERP FUNCTIONS
;; 

;; code to generate random expressions and test student's interp function
;; num prob is the probability of generating a random number in an expression
;;  rather than generating a nested expression. Set to 20% now.

(define numprob 20)

;;
;; generate_quiz5_test consumes a number and produces a list.
;;
;;  (generate_quiz5_test num) generates a list that can be fed to
;;   an interp function. The list may include nested lists (expressions),
;;   the maximum depth of these expressions is controlled by num.
;;
;;  This function generates a single (non-nested) expression if num is 0.
;;  In this case it randomly picks an operator and two numbers in the range
;;  [-500,-1],[1,500] - it avoids zero so we don't have to worry about possible
;;    division by 0.
;;
;;  If num is > 0, the list generated will have a random operator, and with probability
;;  numprob (defined above) will generate a random number as the left/right values of the
;;  expression. With probability 100-numprob, the left(right) will not be a number, but will
;;  instead be another expression (created recursively with num set to num-1).

(define (generate_quiz5_test num)
  (cond
   ;; hit max depth - generate leaf expression
   [(= num 0) (quiz5_random_expression)]
   [ else
     ;; not maximum depth - generate a possibly complex expression
     (list
      ;; first element is a number with probability numprob,
      ;;    an expression with probability 100-numprob.
	  (cond
	   [ (< numprob (random 100))
		 (generate_quiz5_test (- num 1))]
	   [ else (random-num) ])
          ;; pick random operator
	  (random-op)
          ;; third element follows same strategy as the first
	  (cond
	   [ (< numprob (random 100))
		 (generate_quiz5_test (- num 1))]
	   [ else (random-num) ]))]))

;; generates a flat (non-nested) random expression
(define (quiz5_random_expression )
  (list
   (random-num)
   (random-op)
   (random-num)))

;; generates 1 or -1 randomly (used to generate random numbers that can't be 0)
(define (randomsign)
  (cond
    [(even? (random 2)) 1]
    [ else -1]))

;; avoid zero (so we don't divide by 0!)
(define (random-num)
  (* (randomsign) (+ 1 (random 500))))

;; pick an operator randomly
(define (random-op)
  (list-select '(plus minus times div) (random 4)))

;; used to pick random operator from list
(define (list-select alist pos)
  (cond
    [(empty? alist) (error 'list-select "Problem selecting an operator")]
    [(= 0 pos) (first alist)]
    [ else
	 (list-select (rest alist) (- pos 1))]))
;;
;;
;; main testing function - runs both interp-dave and interp on an 
;; expression and compares the results.

(define (quiz5-runtest exp)
  (= (interp-dave exp)
     (interp exp)))

;; result of this should be 10 trues
(quiz5-runtest (generate_quiz5_test 1))
(quiz5-runtest (generate_quiz5_test 2))
(quiz5-runtest (generate_quiz5_test 3))
(quiz5-runtest (generate_quiz5_test 4))
(quiz5-runtest (generate_quiz5_test 5))
(quiz5-runtest (generate_quiz5_test 6))
(quiz5-runtest (generate_quiz5_test 7))
(quiz5-runtest (generate_quiz5_test 8))
(quiz5-runtest (generate_quiz5_test 9))
(quiz5-runtest (generate_quiz5_test 10))

;; make sure they check the operator (should generate an error)
(interp '(4 blah 22))