; Scheme and the Art of Programming
; Chapter 6

; -- Exercise 6.1 
; Define a predicate substring? with two parameters, sstr and strng, 
; that tests whether the string sstr is a substring of strng.

(define (substring? sstr strng)
  (cond
   ((> (string-length sstr) (string-length strng)) #f)
   ((string=? sstr (substring strng 0 (string-length sstr))) #t)
   (else (substring? sstr (substring strng 1 (string-length strng))))))

(substring? "s a s" "This is a string.")
; Value: #t

(substring? "ringer" "This is a string.")
; Value: #f

(substring? "" "This is a string")
; Value: #t


; -- Exercise 6.2
; Define a procedure string-reverse that takes a string as its 
; argument and returns a string that is the given string with 
; its characters in reverse order.

(define (substring-ref strng n) (substring strng n (+ n 1)))

(define (string-reverse strng)
  (if (= 0 (string-length strng)) ""
      (string-append (string-reverse (substring strng 1 (string-length strng)))
		     (substring-ref strng 0))))

(string-reverse "Jack and Jill")
; Value: "lliJ dna kcaJ"

(string-reverse "mom n dad")
; Value: "dad n mom"

(string-reverse "")
; Value: ""


; -- Exercise 6.3
; Define a predicate palindrome? that tests whether a given 
; string is a palindrome.

(define (palindrome? strng) (string=? strng (string-reverse strng)))

(palindrome? "able was I ere I saw elba")
; Value: #t

(palindrome? "mom and dad")
; Value: #f


; -- Exercise 6.4
; An example of the use of implicit begins in cond clauses is below:
(define writeln 
  (lambda data 
    (for-each display data)
    (newline)))
; Safe recursive programs contain a terminating condition which 
; eventually halts the computation.  No one has, as yet been 
; able to demonstrate that mystery is safe.  Nor has a positive 
; integer argument been found for which mystery is unsafe.
(define mystery
  (lambda (pos-int)
    (letrec ((helper
	      (lambda (n count)
		(cond
		 ((= n 1)
		  (newline)
		  (writeln "It took " count " steps to get to 1."))
		 ((even? n)
		  (writeln count ". We divide " n " by 2.")
		  (helper (/ n 2) (+ count 1)))
		 ((odd? n)
		  (writeln count ". We multiply " n " by 3 and add 1.")
		  (helper (+ (* n 3) 1) (+ count 1)))))))
      (helper pos-int 0))))

(mystery 9)
; 0. We multiply 9 by 3 and add 1.
; 1. We divide 28 by 2.
; 2. We divide 14 by 2.
; 3. We multiply 7 by 3 and add 1.
; 4. We divide 22 by 2.
; 5. We multiply 11 by 3 and add 1.
; 6. We divide 34 by 2.
; 7. We multiply 17 by 3 and add 1.
; 8. We divide 52 by 2.
; 9. We divide 26 by 2.
;10. We multiply 13 by 3 and add 1.
;11. We divide 40 by 2.
;12. We divide 20 by 2.
;13. We divide 10 by 2.
;14. We multiply 5 by 3 and add 1.
;15. We divide 16 by 2.
;16. We divide 8 by 2.
;17. We divide 4 by 2.
;18. We divide 2 by 2.


; -- Exercise 6.5
; Write an interactive program that prompts for a number 
; and then prints out the square and the square root of 
; that number.

(define (display-root)
  (display "Please enter a number: ")
  (let
      ((number (read)))
    (display "Square = ")(display (* number number))(newline)
    (display "Square root = ") (display (sqrt number)) (newline)))


; -- Exercise 6.6
; Write a program that prompts for an amount of money, and 
; tells the user how this amount is made up of 100 dollar, 
; 20 dollar, 10 dollar and 1 dollar bills and of quarters, 
; dimes, nickels, and pennies.

(define (display-change)
  (display "For what amount do you want change? $")
  (let
      ((money (read)))
    (letrec
	((hundreds (floor (/ money 100)))
	 (twenties (floor (/ (- money (* hundreds 100)) 20)))
	 (tens     (floor (/ (- money (+ (* hundreds 100) (* twenties 20))) 10)))
	 (ones     (remainder money 10)))
      (display "Hundreds: ") (display hundreds) (newline)
      (display "Twenties: ") (display twenties) (newline)
      (display "Tens: ") (display tens) (newline)
      (display "Ones: ") (display ones) (newline))))


; -- Exercise 6.7
; A Reverand Zeller developed a formula to compute the day 
; of the week for any given day of the Gregorian Calendar. 
; The input to the algorithm is specified in the following 
; manner:
; m is the month of the year, with March as m = 1.  January 
; and February are months 11 and 12 of the previous year.
; d is the day of the month.
; y is the year of the century.
; c is the previous century.

(define (day-of-week m d y c)
  (letrec
      ((A (floor (/ (- (* 13 m) 1) 5)))
       (B (floor (/ y 4)))
       (C (floor (/ c 4)))
       (D (- (+ A B C d y) (* 2 c)))
       (R (remainder (/ D 7))))
    (cond
     ((= R 1) (display "Monday"))
     ((= R 2) (display "Tuesday"))
     ((= R 3) (display "Wednesday"))
     ((= R 4) (display "Thursday"))
     ((= R 5) (display "Friday"))
     ((= R 6) (display "Saturday"))
     ((= R 7) (display "Sunday")))))
