CS 136 Assignment 5

Due Wednesday, June 17 at 5:30 PM sharp.

Please read the preamble in Assignment 1.

In this assignment, Only the C language features introduced up to the end of Section 07 are allowed.


You are not allowed to use recursion or arrays in this assignment.


NOTE: In this assignment, you must assert your preconditions (requirements).


Unless otherwise stated, you do not have to worry about unexpected EOFs.


Assignment 5 Problem 0. [1*4 Marks for correctness]

Problem 0 is a "warm-up" question. You are allowed to collaborate with your fellow classmates and discuss the solution on piazza.
  1. [1 Mark. File: randnum.c]
    Write a C module randnum.c that provides a randnum function:
    int randnum(void);
    That returns a random integer between 5 and 20 (inclusive). You must use the built-in rand() function and must use an initial seed of 1234 (seed only once).
    See Problem 3 for more information

    Example:
    The first two calls to randnum() must return 19 and 8.

  2. [1 Mark. File: repeat.c]
    Write a C program repeat.c that reads in (e.g., from the keyboard) an integer n followed by a character c and then prints the character c a total of n times, followed by a newline. You must use scanf to read in the integer, as well as to read in the next non-whitespace character. The space ' ' and newline '\n' are the only whitespace characters you must consider. You may assume that n is a positive integer.

    Example:
    (repeat.in)
    (repeat.expect)

  3. [1 Mark. File: addsqr.zip containing addsqr.in and addsqr.expect]
    We have provided you with addsqr.h and test-addsqr.c from slides 17 and 18 of Section 07, as well as an implementation file addsqr.c. You are to create the Seashell test files addsqr.in and addsqr.expect. Your files must match the input and expected output from slide 19 of Section 07. There is a newline after the "x" command. All .in and .expect files must have newlines on the end of every line, including the last line.

    Note: Yes, this is pretty basic. This warm-up is to familiarize you with Seashell's automated testing system. Be careful when dealing with whitespace, especially newlines.
  4. [1 Mark. File: train.c]
    You are given a program train.c that draws a train using ASCII characters. Modify this program to be more interactive. The resulting program must, before printing, read in three integers. These integers are printed on the train, one on each car. The printed integers must be right aligned, with one space between the integer and the character '|' at the end of the car. There are two space characters after the train, all lines have the same number of characters, and all lines end with a newline character.

    Example:
    (train_1.in)
    (train_1.expect)

    (train_2.in)
    (train_2.expect)

  5. You can assume that the integers will not be longer than 5 digits.

    Tip: to avoid worrying about whitespace, use multiple calls to scanf to read in integers one at a time.
    Tip: printf can automatically pad integers with spaces so that they are right-aligned! The placeholder "%2d" will add a space to the left of this integer if it is a single digit number. "%5d" will add 4 spaces to a single digit, 3 to a two digit number, etc. (You probably want to use "%5d" for this question).


Assignment 5 Problem 1. [2*5 Marks for correctness]

  1. Write a C module exponent.c that provides the following function, implemented with iteration, not recursion:

    // exponent(a,b) returns a raised to the power of b (a^b)
    // requires: a>0 and b>0
    int exponent (int a, int b) {
      if (b==1) {
        return a;
      }
      return a * exponent(a, b-1);
    }

  2. Write a C module palindrome.c that provides the function is_palindrome from A2P2, implemented with iteration, not recursion.


Assignment 5 Problem 2. [10 Marks correctness]

Background: You wish to help your sibling (in grade 3) with their multiplication skills.

Write a C module mtable.c that provides a function:

// requires: 1 <= w <= 14 and 1 <= h <= 70
void mtable(int w, int h);

that prints a multiplication table with w columns and h rows. Each row must be exactly 5*(w+1) characters wide, followed by a newline. See the provided examples for more details.

Examples:
mtable(2,3) produces output identical to the table in this file: mtable1.txt.
mtable(10,10) produces output identical to the table in this file: mtable2.txt.

Spacing details: If you prefer a description to an example: The table contains h rows (row 1 through row h), as well as a "header row" and a "dash line". In total there are h+2 lines of text. All rows, including the header row, are divided into w+1 cells. Each cell contains exactly five characters. The first cell per line ends with space and then a pipe character (the verical line, '|'). All other cells end with a single space. All numbers, as well as the label "X", must be located immediately before the space at the end of their cell. You must add spaces before the number to ensure that the cell is exactly 5 characters wide. There is a newline character immediately after the last space in the last cell per line. The "dash line" located between the header row and row 1 contains exactly 5*(w+1) dash characters, followed by a newline.

Tip: Do the warm-ups first! There is a tip that applies to this question as well.

Assignment 5 Problem 3. [25 Marks correctness]

Background:
A PseudoRandom Number Generator (PRNG) generates a sequences of integers that appears random, but is mathematically deterministic. The output of a PRNG depends on an initial "seed" value, and for a given seed it always produces the same sequence.

The rand() function in stdlib.h returns a pseudo-random integer between 0 and the constant RAND_MAX (inclusive). The function srand(int seed) initializes the PRNG.

In practice, the current time is often used seed a PRNG. For this assignment, to have consistent Marmoset testing, you are required to set the seed to the value of 1234 (i.e., srand(1234);).

When we use a PRNG, we often desire a sequence of integers within a particular interval [a,b]. Since rand() generates numbers in the interval [0,RAND_MAX], it is common practice to use the modulo (%) operator to map the PRNG sequence to a different range. For example, (rand() % 10) produces a random integer in the interval [0,9].

You still wish to help your sibling with their multiplication skills.

Write a C program mgame.c that is an interactive teaching aid to help grade 3 students with their multiplication skills. The program must operate as follows:

step 1: (multiplication question)
Generate a random number y and then a random number z in the range [1,10] (inclusive).
If you seeded correctly and compute y and z correctly, the first time you run your program, y should be 5, and z should be 10.
You must then prompt the user with "y X z = ", for example:
"5 X 10 = " (space after =, no newline)
and then read in an integer response (with scanf). If the response is correct, proceed to step 4, otherwise proceed to step 2.

step 2: (first guess is incorrect)
Generate a random number r in the range [0,2] and display the corresponding message:
0: "Incorrect.\n"
1: "That is not right.\n"
2: "That is wrong.\n"
and then re-prompt the user for a second chance and read in another response:
"Try again: y X z = " (space after =, no newline)
If the response is correct, proceed to step 4.

step 3: (second guess is incorrect)
Increment the number of incorrect answers, and display the following message:
"Sorry. The correct answer is y X z = %d\n"
proceed to step 5.

step 4: (response is correct)
Increment the number of correct answers, and then generate a random number r in the range [0,2] and display the corresponding message:
0: "Give me five!\n"
1: "Keep up the good work!\n"
2: "Way to go!\n"

step 5: (continue ?)
Prompt the user with:
"Would you like to continue (y/n)? " (space after ?, no newline)
and then read in a response (with scanf) until a 'y' or 'n' is read. If 'y', proceed to step 1.

step 6: (game over)
Display the following statistics:
"----- Session Summary -----\n"
"Correct answers: %d\n"
"Incorrect answers: %d\n"
"Percentage correct: %.2f%%\n"
Note that the percentage of correctly answered questions must be calculated using a float, and must be displayed to two decimal places using the placeholder above.

If implemented correctly, you should be able to duplicate the following interactions (bold denotes input, otherwise output):

5 X 10 = 50
Give me five!
Would you like to continue (y/n)? y
8 X 1 = 81
Incorrect.
Try again: 8 X 1 = 8
Keep up the good work!
Would you like to continue (y/n)? y
9 X 3 = 93
That is not right.
Try again: 9 X 3 = 39
Sorry. The correct answer is 9 X 3 = 27
Would you like to continue (y/n)? n
----- Session Summary -----
Correct answers: 2
Incorrect answers: 1
Percentage correct: 66.67%

Assignment 5 Problem 4. [14 Marks correctness]

Write a C program call.c that translates alphabetic phone numbers into numeric form.
Your program must continue to call scanf() until an EOF is encountered.

For each character of input, your program must print the character, UNLESS it is one of the following upper-case letters, in which case the corresponding number must be printed.

ABC DEF GHI JKL MNO PQRS TUV WXYZ
2 3 4 5 6 7 8 9

Example:
input: CALLATT, 1-800-COL-LECT
output: 2255288, 1-800-265-5328


Assignment 5 Problem 5. [20 Marks correctness]

In this question, you will implement an interactive Rock-Paper-Scissors-Lizard-Spock game (see the webpage for details), which allows a human player to compete against a computer "bot".

To avoid ambiguity, we will use the letter K to represent SpocK.

You must write the module rpslk.c that implements the interface provided in rpslk.h.

We have provided you with play-rpslk.c to start the game. It requires a rpslk-bot module which is also provided for you. The rpslk-bot ("game") module requires your rpslk module.

Download the rpslk-bot.h interface file and the following implementation file: rpslk-bot.o (Seashell), rpslk-bot.o (Virtual Box RunC) or rpslk-bot.o (Mac Lab RunC) and place all of the files in the same folder as your module.

At the start of the game, the user will be prompted to set the bot's challenge rating. This will be done by calling your get_challenge_rating() function. Your function should print the following message and read in an integer with scanf:

"Choose a challenge rating (1 - 1000000): " (space after :, no newline)

You do not have to check for invalid inputs. The bot will handle this for you.

Pro Tip: If a user enters a rating of 1, the bot will always lose. If a user enters a rating of 1000000, the bot will never lose :). The challenge rating is also used by the bot as a seed.

At the start of each round, the game module will call your get_player_throw() function to prompt the user for his/her throw. Your function must print the following message:

"What do you throw (r/p/s/l/k)? " (space after ?, no newline)

Your function should then use scanf until a valid character (r/p/s/l/k) is read.

After the player has entered his/her choice, the game module will call your rpslk_winner function that will decide who wins the round, update the game statistics, and display the victory message.

If the player threw "rock" and the bot threw "paper", The corresponding victory message is:

"Paper covers rock. Bot wins!\n"

The provided messages.txt includes the various victory messages (you can copy these strings into your code to avoid typos).

After each round, the game module will call your get_play_again_response() function to prompt the user to play again (similarly to get_player_throw):

"Would you like to play again (y/n)? " (space after ?, no newline)

If the player chooses 'n', the game module will call your print_game_summary() function to print a game summary, which includes the number of rounds won by the player, the number of rounds won by the computer, and the overall winner of the game. For example, if the player wins 8 rounds and the bot (computer) wins 10 rounds, your program should print the following summary (see the messages file):

----- Game Summary -----
Player won 8 rounds...
Bot won 10 rounds...
Player and bot tied 0 rounds...
Bot wins!

Have fun!

Note: You cannot predict the bot's actions, so you cannot use the SeaShell testing framework. The only way you would know the "expected" output would be to run your code. It is pointless to run your code and then copy its output into a .expect file. It will obviously pass, but it might not actually be the correct output.

Assignment 5 Problem 6. [15 Marks correctness]

Cyber Salmon is a computer science student at the University of Waterloo. He landed a co-op job as a timekeeper at a cutting edge software development company after his 1B semester. The semester just ended and he is being tossed into the "real world". His first project is to implement a timekeeper module in C.

Here is what Salmon has written:

Unfortunately, Salmon did not think that testing was very important during his first two academic semesters. He made it through CS 135 and CS 136 by relying on the public tests available on Marmoset to ensure the correctness of his modules/programs. He never bothered to test his own code! But the company that he is working for does not have Marmoset! Oh noes!

So, Salmon is hoping that you can help him ensure the correctness of his C module. He has provided you with an interactive testing module, test-timekeeper (test-timekeeper.c). Fortunately, the company he is working for uses Seashell in their C development environment. He asks that you write an input file (.in file) and a corresponding comparison file (.expect file) for his interactive testing module (test-timekeeper).

For this question you must submit test-timekeeper.zip which contains all of the following files:

  1. test-timekeeper.in
  2. test-timekeeper.expect

Your input file and comparison file should be written in such a way that a correct implementation of the timekeeper module would pass all of your tests and an incorrect implementation of the timekeeper module would fail one or more of your tests.

You cannot modify test-timekeeper.c! On Marmoset we will be using the same interactive testing module.