This is the third midterm exam that was given to CS1321X students in
Fall 2002.
CS 1321X
Quiz 3 Fall 2002
There are 100 points possible on this exam. You have 80 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. And
in case you've forgotten, the programming language we use here is Scheme.
1. (10 points) Consider the following two functions:
(define (square-lst lst)
(cond [(null? lst) ()]
[else (cons (square (car lst))
(square-lst (cdr lst)))]))
(define (cube-lst lst)
(cond [(null? lst) ()]
[else (cons (cube (car lst))
(cube-lst (cdr lst)))]))
Notice that these two functions have a common control structure that guides
the recursion. Abstract out this common control structure by writing the
my-map function (using Scheme) described in class and in your posted lecture
notes. Then redefine square-lst and cube-lst using your newly-created my-map
function. (In other words, write three functions: my-map, square-lst, and
cube-lst. The new square-lst and cube-lst functions should have the same
functionality as their namesakes above, but they should use your new my-map
function to do the work.)
2. (10 points) What's the difference between "pass by value" and "pass by
reference" parameter passing? When, and why, does Scheme sometimes look like
it uses "pass by value" and other times it looks like it uses "pass by
reference"?
3. (10 points) Given a choice between using recursion or traditional
iteration in some programming task, what do you gain and what do you give
up when choosing iteration over recursion?
4. (10 points) Describe precisely what the lambda function does. In your
description, give a step-by-step explanation how the following code is
evaluated:
(define square
(lambda (x) (* x x)))
Below is part of the state space for a ripping good game of hexapawn. At the
top is the current state of the game, which shows that white has made an
opening move by pushing a pawn forward to the center of the board. The next
level below that shows all three of black's possible responses, and below
that you see the moves that white could make in response:
W W -
- - W current state (after white's opening move)
B B B
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
W W - W W - W W - black's three
B - W - B W - - B possible moves
- B B B - B B - B
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
W - - W - - W W - - W - - W - - W - W - - W - - white's
W - W B W W B - - W B W - W W W - B - W B - - W possible
- B B - B B - W B B - B B - B B - B B - B B - B replies
_____ _____ _____ _____ _____ _____ _____ _____
Pretend you're a minimaxing, hexapawn-playing Scheme program that is
controlling the black pawns, and your static board evaluation function is
as follows:
The function returns a +10 if the board is such that black wins.
It returns a -10 if white wins. If neither side has won, the
function returns the number of black pawns with clear paths in front
of them minus the number of white pawns with clear paths in front of
them PLUS the result of counting the number of black pawns on the
board and subtracting the number of white pawns. It's the same
function that we discussed in class and in the notes.
5a. (10 points): Apply your static evaluation function to each of the
bottom-level boards and write the value that your function would assign
to each board below that board in the spaces provided in that diagram up
there. (There are 8 values to compute.)
5b. (10 points): On that same diagram, show which values would be
propagated upward by your minimax component. Then clearly indicate which
move should be made by black, according to the minimax strategy.
5c. (10 points): If you generated the state space above in a depth-first,
left-to-right fashion and applied the static board evaluation function to
the bottom-level boards as they were generated, you might be able to use
alpha-beta pruning to reduce some of the work. If alpha-beta pruning is
applicable, check here _____ and draw an X through any bottom-level board
that you wouldn't need to generate. If alpha-beta pruning is not applicable,
then check here _____ and explain below or on the back of this page why it
isn't applicable.
6. (10 points) A game called "Last One Loses" is played as follows:
Two players, A and B, alternate in removing one, two, or three pennies
from a stack initially containing nine pennies. The player who picks up
the last penny loses. Player A always moves first. In the space below,
draw the directed graph representation of the state space (or problem space)
for Last One Loses. Then, using this graph representation, show that B can
always win if bonehead mistakes are avoided. (You don't need to draw parts
of the graph that you've already drawn elsewhere; just reuse appropriate
parts of the graph by drawing pointers from and to the right places.
This will make more sense after you start drawing, I hope.)
7. (10 points): Use your knowledge of Scheme and do to create a function
called factorial which when given a non-negative integer N, returns the
factorial of N. (There are helpful hints about do toward the end of
this quiz.)
8. (10 points): Use your knowledge of Scheme, vectors, and do (and the
factorial function from the previous problem) to create a function called
fact-vector which is given a non-negative integer N as a parameter and
returns a vector of the length N+1 filled with the first N+1 factorial
values. (There are helpful hints about do and vectors toward the end
of this quiz.) For example:
> (fact-vector 0)
#1(1)
> (fact-vector 1)
#2(1)
> (fact-vector 2)
#3(1 1 2)
> (fact-vector 3)
#4(1 1 2 6)
> (fact-vector 4)
#5(1 1 2 6 24)
> (fact-vector 5)
#6(1 1 2 6 24 120)
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: November 11, 2003