This assignment is worth 50 points.
You are asked to construct several function definitions in rex and test them. You should submit your functions in a single file named hw1.rex. Your code needs to have an initial comment with the assignment number, your name, and the date. Also, each function should be clearly commented and should be neatly formatted.
The example file fac.rex in the directory /cs/cs60/as/a1 demonstrates appropriate commenting styles, with comments on the commenting! You can examine that file with emacs with the command command
emacs /cs/cs60/as/a1/fac.rex &
This assignment touches on parts of the text up through Chapter 3, though the topics needed will also be covered in class. You should, however, begin reading the book, as there are many more examples and thorough explanations of rex's features and the information structures used here. You may want to try writing some simpler functions on your own as well to get the hang of rex.
If you would like to try some additional practice problems either before or after working on this assignment, there are several (with answers) in the file /cs/cs60/as/a1/practice.probs
There are lots of tests available to make sure that your code is working (and, for example, that you have not made a small change to one of the functions' names, which will cause the grading programs to ignore them). In the directory /cs/cs60/as/a1/ there are lots of test files, named Test0.in through Test26.in. These files will be used in the grading of your HW, so each one your code passes will guarantee it one HW point. A test is passed when lots of OKs show up. If you see the word bad, your code has failed that test.
To use the tests, you should "redirect" them into rex after loading in your file. That is, type
rex hw1.rex < /cs/cs60/as/a1/Test0.inThis checks all of the tests in the file Test0.in. There are about two tests for each of the thirteen problems in the assignment (#14 and #15 are extra credit). I would recommend testing as you go, i.e., after finishing each problem. To look at the test file, you can use emacs or (quicker) just type
cat /cs/cs60/as/a1/Test0.incat is a program that simply prints a file to the screen.
Shortcuts: It would be painful to type the above line in again and again to test your code! Remember that the up arrow returns to a previous command. You can simply use the up arrow, then edit the number to be one greater, and hit return... .
You should submit the file you create (named hw1.rex) by running (at the unix prompt)
% cs60submit hw1.rexYou will need to do this on turing from the directory in which you have your
hw1.rex file.
The graders will test your functions on these and other examples. When the problem states that a function's argument has a given form, you may assume that the test cases will not take any other forms; that is, you do not need to put in error-checking for erroneous argument types. Remember that style and commenting will be worth 20% of the score. Guidelines are here. An well annotated example is in /cs/cs60/as/a1/fac.rex. Here is a brief reminder of one possible format:
// Assignment: CS 60 assignment 1 // Author: Zachary Dodds // Date: 1/19/02 // NOTE TO GRADERS: I haven't slept in 128 hours! // Problem -1: fac returns the factorial of its input // inputs: n, a nonegative integer // // this example uses recursion and rewrite rules to compute factorial fac(0) => 1; fac(n) => n * fac(n-1);
hw1.rex file.
Feel free to use
built-in rex functions (atomic, first, float, length, map, range, reduce,
rest, reverse, and second, along with the arithmetic and logical
operators will suffice, but you may use others). These and other built-in
functions are available from the rex reference card. The
only built-in functions you may not use are log, the
built-in logarithm function,
pow, the built-in
power function, or ack, a built-in "superpower" function
-- these would make problems 4-7
too easy! (You may want to check your own functions with
these built-in versions, which is certainly OK.)
rex > add42List([1, -7, -42, 8]);
[43, 35, 0, 50]
(Hint: Define add42 and use map.)
rex > sum([5, 8, 9]);
22
rex > sum(range(1,10));
55
(Hint: Use reduce.)
rex > average([5, 8, 9]);
7.33333
rex > average(range(1,10));
5.5
You will want to use the float function, along with the
length of the list, in order to obtain floating point
averages. Note that
rex > 22/3;
7
rex > 22/float(3);
7.33333
rex > power(3,4);
81
rex > power(10,3);
1000

rex > superpower(2,3);
16
rex > superpower(3,3);
7625597484987
(Rex supports infinite-precision integer arithmetic -- for instance,
you might want to check out superpower(2,5), but
you might have to turn off any built-in memory limits. (Ask...)
The result has 19,730 digits!)
rex > log2(16);
4
rex > log2(31);
4
rex > log2(32);
5
rex > log2(1);
0
rex > superlog(5,25);
2
rex > superlog(7,343);
3
Note that superlog does not have the same relationship
with log2 that superpower has with power.
rex > superreverse([ [1,2,3], [4,5,6], [7,8,9] ])
[ [3,2,1], [6,5,4], [9,8,7] ]
rex > superreverse([['o','l',['I']],['e','v'],[['e','x'],'r']]);
[[[I], l, o], [v, e], [r, [e, x]]
rex > duperreverse([1, [2, 3], [4, [5, 6, [7, 8], 9] ] ]);
[[[9, [8, 7], 6, 5], 4], [3, 2], 1]
You will want to use the predicate atomic to implement this
function.
rex > bowl( [5, 5], [2, 7] );
rex > bowl( [3, 9] );
Just for the sake of discussion, we will call each
of bowl's imput list(s)
a frame. The score of a
frame, in general, is just the sum of the two integers in the frame.
Your function bowl should return the score of
the first input frame. (If there is only one input frame,
just return its score.)
There is a special case to consider, however:
If the two integers in a frame add up to 10, then
the first integer in the next frame gets added into its
score. If there is no next frame, you ignore this rule.
The following examples should make this clear, as they are simpler than the wordy explanation above:
rex > bowl( [5, 5], [2, 7] );
12
rex > bowl( [4, 6], [1, 0] );
11
rex > bowl( [4, 6] );
10
rex > bowl( [4, 5] );
9
rex > bowl( [5, 3], [1, 0] );
8
rex > bowl( [0, 7] );
7
Notice that the first result above is 12 because the
first frame's integers add to 10 and the following integer
(from the next frame) is 2.
Hint: Try using multiple rules and pattern matching to simplify your code.
If the input is the empty list, superbowl should return 0. Thus, correct runs include
rex > superbowl([ ]);
0
rex > superbowl([ [2, 8] ]);
10
rex > superbowl([ [10, 0], [2, 7] ]);
21
rex > superbowl([ [10, 0], [2, 7], [1, 2] ]);
24
rex > superbowl([ [10, 0], [2, 8], [1, 2] ]);
26
Notice that the last result is 26 because of the following:
scrabbleScores =
[
['a',1,9],
['b',3,2],
['c',3,2],
['d',2,4],
['e',1,12],
['f',4,2],
['g',2,3],
['h',4,2],
['i',1,9],
['j',8,1],
['k',5,1],
['l',1,4],
['m',3,2],
['n',1,6],
['o',1,8],
['p',3,2],
['q',10,1],
['r',1,6],
['s',1,4],
['t',1,6],
['u',1,4],
['v',4,2],
['w',4,2],
['x',8,1],
['y',4,2],
['z',10,1]
]
This list is available in the file /cs/cs60/as/a1/scrabbleScores.rex .
You can include it (and thus use scrabbleScores) by adding the line
sys(in,"/cs/cs60/as/a1/scrabbleScores.rex");
in your file (or, in theory, at the rex prompt).
Make sure that the above line is
in your hw1.rex file! That way, the variable scrabbleScores
will be bound to the above list and you can use it as necessary.
Write a function wordScore(w,L), which takes a word w (a string) and a list L (which has a structure like scrabbleScores, above) as inputs. wordScore should return the word's score:
rex > wordScore("quiz",scrabbleScores);
22
rex > wordScore("twelve",scrabbleScores);
12
We will only test your wordScore function with the
scrabbleScores list, above, but you could imagine
other word-scoring schemes (the next assignment will look at some of these).
Hints: The built-in functions assoc and explode will be useful for this problem. assoc will be covered in some detail in class -- in short, assoc(f,L) returns the first member of L whose first element is f. (All members of L must be lists.)
explode takes a string as input and outputs the same string and a list of characters, e.g.,
rex > explode("rex"); // in case you're thinking regicide by now...
[ r, e, x ]
where those three characters are literal characters and not
variables. Note that when outputting characters, rex does not print
the single quote that is necessary for inputting characters. Thus,
if you ever want to transform a list of characters into a string, you need
to type
rex > implode([ 's', 't', 'a', 'r' ]);
star // actually a black hole...
In fact, your thinking at this point may have veered more toward
the topic of four-letter words. A list of all scrabble-acceptable ones
appears in /cs/cs60/as/a1/fourLets.rex.
Write a function named bestThree that finds the highest-scoring three-letter word from a rack of letters. bestThree(rack,L,wordlist) should accept any seven-letter string (of lowercase letters) as the rack, a list of letter scores L (we will use only scrabbleScores), and any list of strings as wordlist and then return the highest-score achievable with that rack, along with the word achieving that score. There may be several correct answers, in which case bestThree should return one of them. Make sure the output is a list of the maximum score followed by a word (from wordlist) achieving that score.
In the process of writing bestThree you will want to write several helper functions along the way. Those are up to you... .
By including the line
sys(in,"/cs/cs60/as/a1/threeLets.rex");
in your hw1.rex file, the
variable ospd3 will be bound to a list of all legal three-letter
words. (The name ospd3 stands for the Official Scrabble Player's Dictionary's
three-letter words.) Be sure to do this.
Some input/output examples:
rex > bestThree("aaeiijx",scrabbleScores,ospd3);
[10, axe]
rex > bestThree("abcdabc",scrabbleScores,ospd3);
[7, cab]
rex > bestThree("eiilrrx",scrabbleScores,ospd3);
[10, rex]
One caution: because bestThree is somewhat compute-intensive,
there may be a bit of a wait for it to return an answer. My solution
requires about 5 seconds; yours may be faster or slower depending
on your approach.
For example, two differences between scrabbleScore and hardScrabble are
rex > scrabbleScore("fuzzy",scrabbleScores);
29
rex > scrabbleScore("pizzazz",scrabbleScores);
45
rex > hardScrabble("fuzzy",scrabbleScores);
19
rex > hardScrabble("pizzazz",scrabbleScores);
Impossible word!
(Note that a wordlist is not used here to determine if the input word
is actually in the dictionary.)
rex > realbowl([ [10, 'x'], [10, 'x'], [10, 'x'], [10, 'x'], [10, 'x'], [10, 'x'],
[10, 'x'], [10, 'x'], [10, 'x'], [10, 'x'], [10, 'x'], [10, 'x']
]);
300
rex > realbowl([ [10, 'x'], [4, 6], [5, 0] ]);
40
Note that realbowl does handle inputs that aren't real bowling
games, e.g., anything with [10, 0] in it.