Saturday, 31 March 2012

Exercise 161: Design a programe that sorts lists of game players by score.



Exercise 161: Design a program that sorts lists of game players by score:
(define-struct gp (name score))
; GamePlayer is a structure:
;  (make-gp String Number)
; interp. (make-gp p s) represents player p who scored
; a maximum of s points



This question (and solution) is again fairly similar to exercises 160 and 159. It's almost as though they wanted to drive home how similar these sorts of problems are.


Accordingly my answer is similar to the last, but we will still play along and create the solution from scratch...


; this struct is supplied by the question.
(define-struct gp (name score))


; start by creating a number of structs for easy testing etc
(define FIRST (make-gp "dave"  0 ))
(define SECOND (make-gp "bob" 10))
(define THIRD (make-gp "frank" 20))
(define FOURTH (make-gp "tom" 30))






; some tests to make sure we are doing things right.
(check-expect (sort-> empty) empty)
(check-expect (sort-> (list THIRD FOURTH FIRST)) 
              (list FOURTH THIRD FIRST))
(check-expect (sort-> (list THIRD SECOND FIRST)) 
              (list THIRD SECOND FIRST))
(check-expect (sort-> (list FIRST SECOND THIRD)) 
              (list THIRD SECOND FIRST))






This is the basic sort function - as you can see it is more or less identical to the last solution.



; List-of-gps -> List-of-gps
; produces a version of a gps (game player score), sorted by score in 
; descending order

(define (sort-> gps)
  (cond
    [(empty? gps) empty]
    [else (insert (first gps) (sort-> (rest gps)))]))


; Gps, List-of-Gps -> List-of-Gps 
; a helper function to do the actual insert
; insert n into the sorted list of gps's
(define (insert n alogps)
  (cond [(empty? alogps) (cons n empty)]
        [else (cond [(higher-score? n (first alogps)) (cons n alogps)]
                    [else (cons (first alogps) 
                                (insert n (rest alogps)))])]))


; utility function to determine which of two games had the higher score
; we could do this inline, but this lends itself to more clarity i think
(define (higher-score? game-1 game-2)
  (>= (gp-score game-1) (gp-score game-2)))

Tuesday, 27 March 2012



Exercise 160: Design a program that sorts lists of mail messages by date:
(define-struct mail (from date message))
; Mail Message is a structure:
;  (make-mail String Number String)
; interp. (make-mail f d m) represents text m sent by
; fd seconds after the beginning of time
Also develop a program that sorts lists of mail messages by name. To compare two strings alphabetically, use the string<? primitive.
***
This exercise was pretty easy - the answer to most of this was given more or less directly in the previous example of sorting a list of numbers. To make this more challenging I tried to do this without referring back to the previous example.




First I defined a series of structs that contain some predefined emails. This is just to make to check-expects easier to code and to read.




; Number List-of-numbers -> List-of-numbers

(define-struct mail (from date message))
(define FIRST (make-mail "dave"  0 "hello"))
(define SECOND (make-mail "john" 10 "hello"))
(define THIRD (make-mail "andrew" 20 "hello"))
(define FOURTH (make-mail "andrew" 40 "hello"))


These check-expects are pretty similar to the previous example - I've just changed them to look at mails instead.


; List-of-mails -> List-of-mails
; produces a version of alom, sorted by date in descending order
(check-expect (sort-date-> empty) empty)
(check-expect (sort-date-> (list THIRD FOURTH FIRST)) 
              (list FOURTH THIRD FIRST))
(check-expect (sort-date-> (list THIRD SECOND FIRST)) 
              (list THIRD SECOND FIRST))
(check-expect (sort-date-> (list FIRST SECOND THIRD)) 
              (list THIRD SECOND FIRST))

Sort-date is again almost identical to the standard previous example. The only difference is that we are sorting by date and inserting by date.

(define (sort-date-> alom)
  (cond
    [(empty? alom) empty]
    [else (insert-date (first alom) (sort-date-> (rest alom)))]))



Here we insert our date in to the already sorted list. To simplify this I have made a helper function more-recent? which will compare the dates on two emails and let us know which is more recent.


; insert n into the sorted list of date alon
(define (insert-date n alon)
  (cond [(empty? alon) (cons n empty)]
        [else (cond [(more-recent? n (first alon)) (cons n alon)]
                    [else (cons (first alon) 
                                (insert-date n (rest alon)))])]))


This is the helper function to determine which of two emails is more recent. We could do this inline in the insert-date method, but this lends itself to more clarity. 

(define (more-recent? email-1 email-2)
  (>= (mail-date email-1) (mail-date email-2)))



The sort order is not specified, so I will assume we are sorting from most recent -> least recent                                

(check-expect (insert-date FIRST empty) (list FIRST))
(check-expect (insert-date FIRST (list SECOND )) 
              (list SECOND FIRST))
(check-expect (insert-date SECOND (list FIRST)) 
              (list SECOND FIRST))
(check-expect (insert-date SECOND (list THIRD FIRST)) 
              (list THIRD SECOND FIRST));;;




; For the second part of the question we need to sort by name. The easiest way to do this would be to pass the insert and comparison methods into our sort function so that the same function could sort both names and dates. However we haven't been told how to do this in the text yet, so I assume they don't want us to do this.


As this is so similar to sorting by date I won't document what I am doing in as much detail.


I have created some more structs for this - I could have rigged the original ones so that they were both alphabetically and date sorted, but creating new ones seems to be more honest.

(define NFIRST (make-mail "andrew"  20 "hello"))
(define NSECOND (make-mail "bob" 410 "hello"))
(define NTHIRD (make-mail "charlie" 20 "hello"))
(define NFOURTH (make-mail "dave" 4 "hello"))

; List-of-mails -> List-of-mails
; produces a version of alom, sorted by name in descending order
(check-expect (sort-name-> empty) empty)
(check-expect (sort-name-> (list NTHIRD NFOURTH NFIRST)) 
              (list NFOURTH NTHIRD NFIRST))
(check-expect (sort-name-> (list NTHIRD NSECOND NFIRST)) 
              (list NTHIRD NSECOND NFIRST))
(check-expect (sort-name-> (list NFIRST NSECOND NTHIRD)) 
              (list NTHIRD NSECOND NFIRST))

(define (sort-name-> alom)
  (cond
    [(empty? alom) empty]
    [else (insert-by-name (first alom) (sort-name-> (rest alom)) )]))

; insert n into the sorted list of mails alom
(define (insert-by-name n alom)
  (cond [(empty? alom) (cons n empty)]
        [else (cond [(alphabetically-earlier? n (first alom)) 
                     (cons n alom)]
                    [else (cons (first alom) 
                                (insert-by-name n (rest alom)))])]))

; sort order not specified, so will assume sort from most recent -> least recent                                
(check-expect (insert-by-name NFIRST empty) (list NFIRST))
(check-expect (insert-by-name NFIRST (list NSECOND ))
              (list NSECOaND NFIRST))
(check-expect (insert-by-name NSECOND (list NFIRST)) 
              (list NSECOND NFIRST))
(check-expect (insert-by-name NSECOND (list NTHIRD NFIRST))
              (list NTHIRD NSECOND NFIRST))

; utility function to determine which of two emails is more recent
(define (alphabetically-earlier? email-1 email-2)
  (string>? (mail-from email-1) (mail-from email-2)))


Thursday, 22 March 2012

Exercise 159: You know about first and rest from BSL, but BSL+ comes with even more selectors than that....


Exercise 159: You know about first and rest from BSL, but BSL+ comes with even more selectors than that. Determine the values of the following expressions:


  1. (first (list 1 2 3))
  2. (rest (list 1 2 3))
  3. (second (list 1 2 3))

Find out from the documentation whether third, fourth, and fifth exist.



This is a very straight forward exercise. As always with exercises of this type the hardest thing is making yourself do the exercise rather than just pasting the expressions into racket and seeing what they evaluate to.

I did not do as well as I expected - I got the first and third questions wrong. I was expecting them to return a list instead of the element.

A quick look at the documentation shows that not only do third, fourth and fifth exist, but so do sixth, seventh, eighth, nineth and tenth.

;(first (list 1 2 3))
(check-expect (first (list 1 2 3))
              1)


;(rest (list 1 2 3))
(check-expect (rest (list 1 2 3))
              (list 2 3))


;(second (list 1 2 3))
(check-expect (second (list 1 2 3))
              2)
     

Friday, 16 March 2012

Exercise 158: Determine the values of the following expressions...


Exercise 158: Determine the values of the following expressions:

  1. (list (string=? "a" "b") (string=? "c" "c") false)
  2. (list (+ 10 20) (* 10 20) (/ 10 20))
  3. (list "dana" "jane" "mary" "laura")

This is a pretty straight forward exercise. The hardest part here is to avoid the temptation to paste these directly in to the racket interpreter. I got 2/3 correct on my first pass though.


;1) (list (string=? "a" "b") (string=? "c" "c") false)
(check-expect (list (string=? "a" "b") (string=? "c" "c") false)
              (list false true false))
              
;2) (list (+ 10 20) (* 10 20) (/ 10 20))
(check-expect (list (+ 10 20) (* 10 20) (/ 10 20))
              (list 30 200 0.5))


;3) (list "dana" "jane" "mary" "laura")
(check-expect (list "dana" "jane" "mary" "laura")
              (list "dana" "jane" "mary" "laura"))

Tuesday, 13 March 2012

Exercise 157b: On some occasions lists are formed with cons and list. Reformulate the following lists using list exclusively


Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using list exclusively:;


;(cons "a" (list 0 false))
;
;(list (cons 1 (cons 13 empty)))
;
;(cons (list 1 (list 13 empty)) empty)
;
;(list empty empty (cons 1 empty))
;
;(cons "a" (cons (list 1) (list false empty)))

Whoops! Completely missed that second part about doing this also exclusively using list. Luckily this is a lot easier than doing them using cons exclusively. The tricky part about this exercise was doing it all in your head before pasting the source expression into racket - as soon as you do that, racket gives the answer formatted using list. Doh!



;1 Reformulate: (cons "a" (list 0 false))
(check-expect (cons "a" (list 0 false))
              (list "a" 0 false))


  
;2 Reformulate (list (cons 1 (cons 13 empty)))
(check-expect (list (cons 1 (cons 13 empty)))  
              (list (list 1 13) ))
              
;3 Reformulate (cons (list 1 (list 13 empty)) empty)
(check-expect (cons (list 1 (list 13 empty)) empty)
              (list (list 1 (list 13 empty))))


;4 Reformulate
;(list empty empty (cons 1 empty))
(check-expect (list empty empty (cons 1 empty))
              (list empty empty (list 1)))




;5 Reformulate (cons "a" (cons (list 1) (list false empty)))
(check-expect (cons "a" (cons (list 1) (list false empty)))
              (list "a" (list 1) false empty))

Tuesday, 6 March 2012

Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using cons and empty exclusively


Exercise 157: On some occasions lists are formed with cons and list. Reformulate the following lists using cons and empty exclusively



;(cons "a" (list 0 false))
;
;(list (cons 1 (cons 13 empty)))
;
;(cons (list 1 (list 13 empty)) empty)
;
;(list empty empty (cons 1 empty))
;
;(cons "a" (cons (list 1) (list false empty)))


This exercise was pretty straight forward. I just built up the lists from scratch only using cons.

;1 Reformulate: (cons "a" (list 0 false))
(check-expect (cons "a" (cons 0 (cons false empty)))
              (cons "a" (list 0 false)))




;2 Reformulate: (list (cons 1 (cons 13 empty)))
(check-expect (list (cons 1 (cons 13 empty)))  
              (cons (cons 1 (cons 13 empty)) empty) )
    
          
;3 Reformulate (cons (list 1 (list 13 empty)) empty)
;  this one is a little more interesting - we are making 
;  a list of empty lists - easy enough to do though with 
;  a (cons empty empty)
(check-expect (cons (list 1 (list 13 empty)) empty)
              (cons (cons 1 (cons (cons 13 
                            (cons empty empty)) empty)) empty))


;4 Reformulate: (list empty empty (cons 1 empty))
(check-expect (list empty empty (cons 1 empty))
              (cons empty (cons empty (cons 
                                      (cons 1 empty) empty))))




;5 Reformulate: (cons "a" (cons (list 1) (list false empty)))
(check-expect (cons "a" (cons (list 1) (list false empty)))
              (list "a" (list 1) false empty))