CS 1321X - Sample Final Exam

CS 1321X - Sample Final Exam


This is the final exam that was given to CS1321X students in
Fall 2002.  

CS 1321X
Final Exam
Fall 2002

Please write your name on the upper right hand corner of this page.  There 
are 170 points possible on this exam.  You have 170 minutes to complete it 
and turn it in.  Put only what you want to be graded on the front sides of 
the pages, and use the back sides of the pages as scratch paper.  If you 
run out of room on the front side of the page, you can put part of your 
answer on the back of that same page, but make sure you note on the front 
of the page that there's stuff to be graded on the back.  And please strive 
for legibility, because we don't give credit for stuff we can't read.  
All programs are to be written in Scheme, unless the instructions for a 
specific problem say to write the program in Python.

For any problem, make sure that you stay within the constraints and follow 
the specifications given in that problem.  There are a couple of pages at 
the end of this exam to supplement your memory about iteration and vectors 
in Scheme.  You may remove these pages from the rest of the exam.  You don't 
have to comment the code that you write for this exam.


 1.  (10 points)  Given the creation of this constant:

(define  *code-list*
  '((a n) (b o) (c p) (d q) (e r) (f s) (g t) (h u) (i v) (j w) (k x) (l y) (m z)
    (n a) (o b) (p c) (q d) (r e) (s f) (t g) (u h) (v i) (w j) (x k) (y l) (z m) (_ _)))

create a Scheme function called replace-char which takes two arguments.  
The first argument should be either a letter of the alphabet or an 
underscore.  The second argument should be the constant defined above.  
Your replace-char function should lookup the character that was passed as 
the first argument in the association list that was passed as the second 
argument and return whatever character is associated with the character 
that was passed as the first argument.  In other words, replace-char 
works like this:

> (replace-char 'a *code-list*)
N
> (replace-char 'b *code-list*)
O
> (replace-char 'c *code-list*)
P
>
 :
 :
> (replace-char 'y *code-list*)
L
> (replace-char 'z *code-list*)
M
> (replace-char '_ *code-list*)
_
>
 
You don't need to worry about what happens if replace-char is passed a 
character that isn't in the association list.  


2.  (10 points)  Assume that you now have a working version of replace-char.  
Don't rewrite replace-char in the space below, but use replace-char and 
augmenting recursion to write a little encryption program called crypto-1 
that takes a message represented as a list of characters and the association 
list defined in Problem 1 and returns an encrypted message like this:

> (crypto-1 '(b e e f c a k e) *code-list*)
(O R R S P N X R)
> (crypto-1 '(p _ q h z c f _ o v t _ p b e r) *code-list*)
(C _ D U M P S _ B I G _ C O R E)
> 

Also, you are to define only one new function.  Don't bother with 
abstraction here.  Just write one new function.


3.  (10 points)  Rewrite your encryption program from Problem 2 so that it 
uses tail recursion instead of augmenting recursion.  You can call 
replace-char again, but don't rewrite it here, regardless of how you 
implemented it in Problem 1.  Call your new encryption program crypto-2.  
Also, you are to define no more than two new functions in the space below, 
including the one called crypto-2.  You can ignore abstraction again.  


4.  (10 points)  OK, this is the last time with the encryption thing.  
Rewrite your encryption program one more time, and this time call it 
crypto-3.  The new wrinkle here is that you are to use map as your control 
structure.  And don't call replace-char this time.  Instead, use a lambda 
function that does the same thing as replace-char.  As in the previous 
problems, forget about abstraction here.  Just define one new function, 
which of course is called crypto-3.


5. (10 points)  Scheme provides a function that takes a list as an argument 
and converts that list to a vector as shown:

> (list->vector '(a b c d e))
#5(a b c d e)
> (list->vector '())
#0()
>

Using Scheme, create your own version of list->vector and call it 
my-list->vector.


6. (10 points)  Scheme provides a function that takes a vector as an 
argument and converts that vector to a list as shown:

> (vector->list #5(a b c d e))
(a b c d e)
> (vector->list #0())
()
> 

Using Scheme, create your own version of vector->list and call it my-vector->list.


7.  (10 points)  Here are some questions you might be able to answer (with 
no more than two sentences each, please) even if you can't write an iota 
of Scheme code:

a) What's functional programming?

b) What's a side effect?

c) What's abstraction?

d) What's reference?

e) What's synthesis?

f) What's the difference between a procedure and a process?  

g) What's the "shape" of a process?  

h) How does the difference between tail recursion and augmenting recursion 
affect the shape of a process?  


8.  (10 points)  Let's say that Dr. Scheme doesn't have a built-in and 
operator.  Would the following function be a good substitute for and 
(assuming it was sufficient for and to accept only two arguments)?  Explain.

(define (and operand1 operand2)
  (cond [(not operand1) #f]
        [(not operand2) #f]
        [else #t]))


9.  (10 points)  You may not believe it, but some of you aren't really 
expending much effort at using meaningful, helpful names, comments, or 
abstraction when constructing the Scheme functions that we have to grade.  
Now it's time for us to turn the tables.  Take a good look at the 
following four functions:

(define (lista list1)
  (listb list1 () () ()))

(define (listb list1 list2 list3 list4)
  (cond ((null? list1) (list list2 list3 list4))
        (else (listc (cdr list1) 
                     (append list2 (list (car list1))) list3 list4))))

(define (listc list1 list2 list3 list4)
  (cond ((null? list1) (list list2 list3 list4))
        (else (listd (cdr list1) 
                     list2 (append list3 (list (car list1))) list4))))

(define (listd list1 list2 list3 list4)
  (cond ((null? list1) (list list2 list3 list4))
        (else (listb (cdr list1) 
                     list2 list3 (append list4 (list (car list1)))))))
 

Now tell us what will be returned when the following call to lista is 
evaluated (and think of what your grader goes through when you turn in 
code that looks like this):

> (lista '(s g r p h u a o l c s e e t s))

 





Below is a highly-abstracted map of routes between some selected cities 
in Georgia, including estimated driving distances between these cities.  

[** sorry, the map isn't reproduced here in this sample exam, but you 
could recreate it from the information below **] 

Here's an association list that encodes the information contained in the 
map above:

(define *map*
  '((atlanta (macon 82) (perry 108) (butler 90))
    (macon (atlanta 82) (perry 25))
    (butler (atlanta 90) (albany 77))
    (perry (atlanta 108) (macon 25) (tifton 76))
    (tifton (valdosta 50) (perry 76) (albany 43))
    (valdosta (tifton 50))
    (albany (tifton 43) (butler 77))
   )
)


10.  (20 points):  Using Scheme, construct a function which takes as 
parameters the names of two cities on the map from the previous page, 
along with the association list bound to the variable *map*.  This 
function uses depth-first search to find one path without cycles which 
connects one city to the other along with the total driving distance for 
that path.  Call this function find-one-path.  One example of a function 
invocation would be this:

> (find-one-path 'atlanta 'valdosta *map*)

and it would return one of the following results: 

(233 (atlanta macon perry tifton valdosta))      or
(234 (atlanta perry tifton valdosta))            or
(260 (atlanta butler albany tifton valdosta))

(Which result is actually returned?  It would depend on how you implement 
your search; it doesn't really matter which one is returned, just so long 
as one of these is returned.)


11.  (10 points)  Explain what a state space search is.  Describe the three 
pieces of information that should be passed to a state space search 
procedure for the search to be successful.  Finally, explain why it's 
useful for computer science types like us to know about state space searches.  


12.  (10 points)  In the context of object-oriented programming, explain 
what a class is and what an object is.  How are they related?  And while 
you're at it, explain what inheritance is and why it's useful.


13.  (20 points)  Forget vending machines.  I've decided to follow a 
different career path.  I want to set up my own Internet casino.  Once 
again, however, I'd like to simulate its operation before I fully commit 
to the venture.  So as I explore my online blackjack possibilities, I'll 
need a generator function (i.e., lexical closure) that will deal cards 
for blackjack.  Define a function called make-card-dealer which is passed 
one argument, a list representing a deck of cards, and returns a lexical 
closure which simulates the dealing of cards from the deck of cards by 
returning symbols representing the cards, one card at a time each time the 
lexical closure is called.  If there are no more cards in the deck, the 
symbol 'no_more_cards is returned.  Use Scheme when defining this function.

Here's how the whole thing should work.  First, I'll call make-card-dealer 
and pass it a very small deck of cards (as a list) containing the Ace of 
Hearts, the 3 of Clubs, the 9 of Diamonds, and the Queen of Spades.  I'll 
give the lexical closure that is returned its own unique name, deal-card.  
Then each time deal-card is called, it returns a card like this:

> (deal-card)
ah
> (deal-card)
3c
> (deal-card)
9d
> (deal-card)
qs
> (deal-card)
no_more_cards
>

You may use side effects here, and thanks in advance for helping me with my 
project.


14.  (10 points)  As you might guess, many students complain about the 
plethora of parentheses found in Scheme.  So that we can help these 
weaklings recover from severe brain strain, I'd like you to write a 
Scheme function that, when passed a list as an argument, will return 
the number of parentheses found in the list.  Call this function 
count-parens.  Don't do any error-checking, and don't worry about 
dotted pairs.  You can assume that anything passed to your functions 
will be a valid, well-formed list.  You want examples?  Here they are:

> (count-parens '() )
2
> (count-parens '(()) )
4
> (count-parens '(a (b (c)) d) )
6
> (count-parens '(define (sqr x) (* x x)) )
6
> (count-parens '(a (b (c (d (e) f) g) h) (i (j (k) l) m) n) )
16
> 


15.  (10 points)  Here's my definition of the Coke Machine class, written 
in Python.  We talked about it in class on Thursday, and it's also 
discussed in the lecture notes:

class CokeMachine:
   def __init__(self):
      totalmachines = 0
      CokeMachine.totalmachines = CokeMachine.totalmachines + 1
      self.numcans = 20
      print "Adding another Coke machine to your empire"
   def BuyCoke(self):
      if self.numcans > 0
         self.numcans = self.numcans - 1
         print "Have a nice frosty Coke!"
         print "%3d frosty cans of Coke remaining." % (self.numcans)
      else
         print "Sorry, out of Coke."
   def LoadCoke(self loadcans):
      self.numcans = self.numcans + loadcans
      print "%3d cans of Coke added" % (loadcans)
      print "%3d cans of Coke now available" % (self.numcans) 

OK, I lied.  It's not exactly like what we talked about in class and in 
the notes, because this version is broken.  As we discussed, I want it to 
add more Cokes to the machine when I invoke LoadCoke, and I want it to 
simulate the purchase of a Coke when I invoke BuyCoke, and I want it to 
keep track of how many Coke machines I have in my empire.  But things 
aren't working the way I want them to.  Explain what's wrong and how to 
fix it.  (Hint: there's more than one problem with this program.)

----------
Hints on do:

Scheme provides you with one slightly complicated iterative form.
It's just called "do", and it looks like this:


 (do (([var-1] [init-expr-1] [update-expr-1])
      ([var-2] [init-expr-2] [update-expr-2])
                   :
                   :
      ([var-n] [init-expr-n] [update-expr-n]))
     ([test-expr] [action-expr-1] ... [action-expr-m])
                   :
         [zero or more expressions]
                   :
                                )

Here's how "do" works:

1.   each [var-i] is bound to its corresponding [init-expr-i]
     (in "parallel", just like with "let"---that is, there's
     no guarantee of the order the bindings are completed,
     so don't encode dependencies of any kind in this part
     of the "do" form).

2.   [test-expr] is evaluated. If the result is non-#f, then
     the [action-expr-1] through [action-expr-m] are evaluated
     in left-to-right fashion. The "do" form returns the value
     of [action-expr-m] and the iteration is terminated. If
     there are no action expressions, what the "do" form
     returns is unspecified (!).

3.   if evaluating [test-expr] returns #f, then execute the
     body of code.

4.   when the body of code has been executed, update each
     [var-i] by binding it to the value obtained by evaluating
     the corresponding [update-expr-i]. The [update-expr-i]
     are optional, so if it's not there, then the various
     [var-i] are never changed. Also, these bindings are done
     automatically by "do", so there's no need to include your
     own "set!" in the update expressions. Finally, these
     updates, as well as the initializations, are done in
     an unspecified order, so you can't count on any
     dependencies (i.e., this happens before that). You
     can however count on some protection in that Scheme binds
     the variables to fresh locations, does the updates to
     those fresh locations, and then binds the updated values
     to the variable.

5.   go to 2


-----
Hints on vectors:

>  (define x (vector 10 100 90 50 45))

>  x
#5(10 100 90 50 45)

>  (define y (make-vector 6))

>  y
#6(0)

>  (define y (make-vector 6 'foo))

>  y
#6(foo)

>  (vector-ref x 2)
90

>  (vector-length x)
5

>  (vector-set! x 4 65)

>  x
#5(10 100 90 50 65)

>  (vector-set! x 2 '(foo bar))

>  x
#5(10 100 (foo bar) 50 65)

>  (vector-ref x 5)
vector-ref: index 5 out of range [0, 4] for vector: #5(10 100 (foo bar) 50 65)







Copyright (c) 2003 by Kurt Eiselt.  All rights reserved, with 
the exception of stuff that belongs to somebody else.

Last revised: December 2, 2003