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 clearly commented. The five criteria the graders will be looking for with respect to formatting, comments, etc. are listed here. Be sure to have your name in a comment at the top of the file. The example file factorial.rex in the directory /cs/cs60/as/a1 demonstrates appropriate commenting styles (a bit over the top, actually), with comments on the commenting!
This assignment touches on parts of the text through Chapter 3, though the topics needed will be considered 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.
You should submit the file you create (named hw1.rex) by running (at the unix prompt)
% cs60submit 1You will need to do this on turing from the directory in which you have your
hw1.rex file. I'd suggest working in ~/cs60/a01.
(In unix the ~ refers to your home directory.)
rex > add42(-7); 35 rex > add42(190); 232If the user provides an input which is not a number, that's not your problem!
> cd cs60When you list (ls) the files you should see 15 directories named a01 to a15. I'd encourage you to create your hw1.rex in the a1 directory. You can cd to it and then open up emacs, for example.
Now you can start rex back up (from the same directory ~/cs60/a01 in which your file is located). If you can work with multiple windows into turing, it's nice to keep emacs open in one window and use another window for rex.
At the rex prompt, type *i hw1.rex. This will load in the file (the "*i" stands for "include") and you can now use the functions that were defined in that file. As it loads, you will see the results from each statement in the file. In particular, if you have test statements, you will see whether the tests are passed or failed. (See below.) Alternatively, you can type rex hw1.rex at the unix prompt and it will start rex up with the functions defined in the file hw1.rex. Example files are available in the directory /cs/cs60/as/a1. Feel free to load these files and try the example functions there. For example, typing at the unix prompt
> rex /cs/cs60/as/a1/factorial.rexwill make the fac function available. (Try it!)
There is a function named test which allows for easy testing of your functions from within a file. test takes two arguments: the first is a function application and the second is the result of that function application. If, in fact, the first argument evaluates to the second, then the message ok will be printed; otherwise, the message bad will be printed. Thus, if your add42 function is working, you can try
rex > test(add42(-7),35); ok: add42(-7) ==> 35 rex > test(add42(190),231); bad: add42(190) returned 232, should be 231(It shouldn't be 231, but that's the answer we told it to expect in the
test function.)
In general, it is usually much easier to use emacs (or your favorite
text editor) to create and modify files of rex statements and then "include"
them as described above. Even better, in general, is to start rex each time
by typing rex <filename>. That way, you know that your newly
written/changed functions are getting used (provided you saved your changes!)
There are files in the directory
/cs/cs60/as/a1/ named Test#.rex,
which have test statements with
which you can try your functions for each of the assignment's problems. For
example, after typing your add42 function into a file named
hw1.rex, you can try the following (at the unix prompt, not
the rex prompt):
> rex hw1.rex < /cs/cs60/as/a1/Test0.inYou should see that your function succeeded at all of the tests:
hw1.rex loaded 1 rex > ok: add42(-7) ==> 35 2 rex > ok: add42(0) ==> 42 3 rex > ok: add42(101) ==> 143 4 rex > ok: add42(190) ==> 232 5 rex > ok: add42(12345678900) ==> 12345678942 6 rex >One thing that will make typing at the prompt more like editing a file in emacs is the *r command, which toggles emacs-like line input (the arrow keys will work). However, I'd suggest doing all of your editing into a file with emacs and then loading the results into rex either with *i or by typing
> rex (your filename)at the unix prompt. This will load all of your functions in the specified file.
Lots more information on using rex is available at the
rex summary
page.
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.
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 function you may not use is pow, the built-in
power function (or ack, for that matter) -- it would make problems 4-5
too easy! Also, don't use log. (You might want to check your own functions with
these built-in versions, however).
rex > add42List([1, -7, -42, 8]);
[43, 35, 0, 50]
(Hint: 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 arithmetic -- for instance,
you might want to check out superpower(2,5), but
you might have to turn off any built-in memory limits. 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");
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 named wordScore, which takes a word (as a string) and a list letterScores (like scrabbleScores, above) as inputs. wordScore should return the word's score:
rex > wordScore("twelve",scrabbleScores);
12
rex > wordScore("quiz",scrabbleScores);
22
The built-in function explode will be useful for this problem: it
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,letterScores,wordlist) should accept any seven-letter string (of lowercase letters) as the rack, a list of letter scores as letterScores, 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]
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.