CSC 161 Grinnell College Fall, 2012
 
Imperative Problem Solving and Data Structures
 
 

Supplemental Problems

Supplemental Problems extend the range of problems considered in the course and help sharpen problem-solving skills. To support this objective, all Supplemental Problems are to be done individually.

Problems numbered 6 or higher may be turned in for extra credit.

Quick links: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 15

Format:

In turning in any programs for the course, please follow these directions:
  1. The first six lines of any C program should be comments containing your name, your mailbox number, this course number (161), and an identification of assignment being solved. For example:
    
        /******************************************
         * Henry M. Walker                        *
         * Box:  Science                          *
         * Supplemental Problem 1 for CSC 161     *
         * Assignment for Wednesday, September 12 *
         ******************************************/
    
    Also, a comment is needed for every definition of a C function, stating both pre- and post-conditions for that program unit.

  2. Email your program to me (walker@cs.grinnell.edu), as follows:
    • The subject line should include "CSC 161", the assignment name, and your name (when the program involves work with a collaborator, put both names in the subject line).
    • Include the C program as an attachment. If the program involves several files, attach all relevant (.c and .h) files. (Include only the source code (e.g., .c and .h files; do not include compiled code.)
    • Include an attachment that shows test runs of the program.
    • To count as being submitted on time, the time stamp on the email must be before the start of the class in which the work was due.
  3. Turn in a printed copy of your program and relevant output.
    • A printed copy of the program should be on top. (Since your name, box, etc. are required to be at the start of the program, this printout will identify that this is your work.)
    • If your work involves several files, list the main program first; then list any supplementary files.
    • Compile your program with the gcc command, and run it.
      • If the program does not use the Scribbler 2, include the full range of test cases that demonstrate the correctness of your program. (You should print the full interaction from the terminal during the test runs.)
      • If the program uses the Scribbler 2, include a description of what test runs you used and what results you obtained.
    • Either write on your printout or include a separate statement that argues why your program is correct, based upon the evidence from your test runs.

Some Grading Notes:


Classifying SAT and ACT Scores

  1. Each fall, the Departments of Computer Science and Mathematics and Statistics provide recommended placements for incoming students in first courses in computer science, mathematics, and statistics. Overall, the process involves about 125 rules within a reasonably complex system.

    One of the early steps in this process involves the classification of standardized scores, based on student scores on the SAT and/or ACT. The following edited table suggests the basic framework for a classification.

    Category SAT Range ACT Range
    Superior 700– 31–
    Excellent 640–690 28–30
    Strong 600–630 26–27
    Good 550–590 24–25
    Adequate 480–540 20–23
    Participating –470 –19

    Although this table provides a starting point, students scores sometimes differ substantially from one test to another. This leads to the following rules for determining the actual category for a student' standardized scores.

    • If a student takes the SAT or the ACT, but not both, then the above table provides the classification.
    • If a student takes both the SAT and ACT,
      • the student's classification is the higher of the two categories from the above table, EXCEPT
      • if the categories differ by three or more levels, then the top category is lowered by one.
    • If a student has not taken either the SAT or ACT, the category is specified as "Unknown".

    Examples:

    • A student with a 650 SAT or 28 ACT (or both) would be placed in category "Excellent" for standardized scores.
    • A student with a 650 SAT and 24 ACT would be placed in category "Excellent", based on the 650 SAT. (The 24 ACT is two categories lower than the 650 SAT, and two categories is not enough to lower the classification.)
    • A student with a 650 SAT and a 23 ACT would be placed in category "Strong". (The "Excellent" category from the SAT would be lowered by one, since the 23 ACT is three categories lower.)

    Write a program that computes the appropriate category for a specified SAT and ACT score. Rather than read SAT or ACT scores from the keyboard, the program should assign an SAT and ACT score to variables at the very beginning of the program. If the student has not taken an SAT or an ACT test, then the variable for that test should be set to 0.

Computing a Polynomial

  1. A polynomial function has the form

    p(x) = anxn + an-1xn-1 + ... + a2x2 + a1x + a0

    Write a function compute_poly that takes three parameters:

    • an x value,
    • an integer n which gives the largest power of x with a non-zero coefficient, and
    • an array a of n+1 coefficients (a0, a1, ..., an-1, an).

    and returns the value of the polynomial p(x).

    Notes:

    • compute_poly should make only one pass through the list of coefficients.
    • Both the number x and the elements of the array a should be real numbers (e.g., of type double) rather than integers.
    • The number x may be used in a multiplication operation no more than n times in the entire computation. (Thus, recomputing xi from scratch for each of the n terms is not acceptable for this problem.)
    • Since the pow function in the math.h library requires many multiplication operations, use of pow in this problem would violate the condition that no more than n multiplications are allowed in the entire solution to this problem. (To be specific, use of pow in this program will yield an automatic score of 0 for this program.)
    • As a hint, you may want to search for discussion of Horner's Rule either in a book on numerical analysis or on the Web.
    • Be sure that the array element a[n] is used as the coefficient of xn (not the coefficient of x0).
    • You will need to include compute_poly in a main program for testing.
    • Be sure your testing covers an appropriate range of cases.

Grading Passwords

  1. Since many modern computer systems use passwords as a means to provide protection and security for users, a major issue can be the identification of appropriate passwords. The main point should be to choose passwords that are not easily guessed, but which the user has a chance of remembering. For example, passwords related to birthdays, anniversaries, family names, or common words are all easily guessed and should be avoided.

    Some common guidelines suggest that a password should contain at least 6 characters and include characters from at least three of the following categories:

    • uppercase letters
    • lowercase letters
    • digits
    • punctuation (considered to be anything not a letter or a digit)

    Other guidelines indicate that elements of passwords should be pronounceable. One simple measure of this guideline suggests that any group of letters in a password should contain both vowels and consonants.

    This supplemental problem asks you to write and test a procedure

    
       char gradePassword (char * password)
    

    that assigns a grade to the given password, as follows:

    • Assign 1 point for each of the following elements in the password:
      • password contains at least 6 characters
      • password contains at least 1 vowel
      • password contains at least 1 consonant
      • password contains at least 1 upper-case letter
      • password contains at least 1 lower-case letter
      • password contains at least 1 numeric character
      • password contains at least 1 punctuation mark
    • Assign a letter grade to the password by applying the sum of the points above to the following.
      • 6 or 7 points: A
      • 5 points: B
      • 4 points: C
      • 3 points: D
      • 0 or 1 or 2 points: F

A Simple Route Cipher

  1. When sending a message from one place to another, it is common for the sender to encode the message before it is sent with the understanding that the receiver would know how to decode the message when it is sent. With this encoding process, anyone intercepting the message in transit would not be able read the text.

    For encoding, one approach is a substitution cipher, in which each letter in original message is replaced by another letter. (For example, each "a" in the message might be replaced by "d" and each "t" might be replaced by "w". This type of cipher is commonly used in many word puzzles in newspapers and puzzle books.

    A second approach for encoding is called transposition, in which the characters of the original message are rearranged in a different order. This problem implements a simple type of transition cipher, called a route cipher. (Historically, the Union forces in the American Civil War used a variation of a route cipher, called the Union Route Cipher.)

    Encoding: In a simple route cipher, letters of a message are placed into a rectangular table. As an example, suppose the cipher is based on a table of 5 rows and 9 columns, and suppose we wish to encode the text "this short example illustrates a route cipher". The first step of a route cipher is to insert the message row-by-row into the table, on character at a time.

    t h i s   s h o r
    t   e x a m p l e
      i l l u s t r a
    t e s   a   r o u
    t e   c i p h e r

    With this arrangement, the encoded message is obtained by retrieving the letters according a designated path or route from the rectangle. For this problem, we will retrieve the letters from the table column by column. For example, reading column-by-column from the above table, we obtain the coded message "tt tth ieeiels sxl c auaisms phptrholroereaur".

    Decoding: Given an encoded message, the receiver places the text character-by-character into the rectangle according the prescribed path (e.g., column by column). With the letters in the rectangle, the original message can be restored by reading the rectangle row-by-row.

    Extensions: In the basic encoding approach, the original message is placed in a rectangle of a designated size. If the rectangle has r rows and c columns, this approach works well if the message has length r*c, the size of the rectangle. Extensions are needed if the original message has length other than r*c characters.

    • If the original message has less than r*c characters, additional characters might be added to get the needed number. For example, we might add letters of the alphabet a, b, c, d, e, ... at the end of message as needed to fill the rectangle.
    • If the original message has more than r*c characters, the message is divided into blocks of r*c characters, and each block is encoded separately.

    As another example, suppose the rectangle is specified with 3 rows and 4 columns, and suppose we want to encode the message "this extended example shows the full algorithm".

    Encoding follows these steps:

    1. Divide the message into blocks of 3*4 = 12 characters. The last block would have only 10 characters, so "a" and "b" have been added to complete the block.

      t h i s   e x t e n d e
      d   e x a m p l e   s h
      o w s   t h e f u l l
        a l g o r i t h m a b
    2. Place each block into a rectangle, row-by-row:
      t h i s       d   e x       o w s           a l g
        e x t       a m p l       t h e       o r i t
      e n d e       e   s h       f u l l       h m a b
    3. Read characters from each block, column-by-column:
      "t ehenixdste"   "dae m epsxlh"   "otfwhusel  l"   " oharmliagtb"

      Combining the encoded blocks gives:
      "t ehenixdstedae m epsxlhotfwhusel  l oharmliagtb"

    Problem:

    • Write a program that reads the rectangle size (a row and a column) and the text of a message and prints the encoded message.
    • Explain how the above program can also be used for decoding and illustrate your explanation with an example.

    Reference: A nice treatment of transposition ciphers may be found in Abraham Sinkov, "Elementary Cryptanalysis: A Mathematical Approach", The New Mathematical Library, Random House and the Mathematical Association of America, 1968, Chapter 5. A revised edition of the book is available in Abraham Sinkov and Todd Feil, "Elementary Cryptanalysis Second Edition", The New Mathematical Library, Mathematical Association of America, 2009.

Word-Find Puzzle

  1. This exercise is based on a programming problem by Marge Coahran.

    This problem asks you to write a program that solves a "word-find" puzzle similar to puzzles that can be found in newspapers and magazines. An example is given below.

    The input data for your program will be a 16 x 16 grid of characters (the puzzle board) followed by a list of words. The object of the puzzle is to search the puzzle board for the words in the word list. Words may appear in the puzzle board horizontally or vertically (but not diagonally). Horizontal words will run left to right; vertical words will run top to bottom. Words will not "wrap around" in either direction, so for example, a word could not occupy columns {15,16,1,2}. Each word will appear at most once in the puzzle board.

    An example data file is available at /home/walker/161/problems/puzzleboard for your use, but your program should work on any input file that conforms to the following specifications.

    Puzzle Specifications

    The puzzle board will be given first. It will consist of a matrix of 16 x 16 upper-case letters, with a single space between each character on each row. Next the file will contain a list of upper-case words, each on a separate line, and each of which could fit within the puzzle board. The number of words is not specified, so your program should read until the end of the file is reached. There will be no blank lines anywhere in the file.

    Your program should specify the input file name as a command-line parameter, and the program should print the name of the file as part of its output.

    Your program should output a "key" to the word-find puzzle as shown in the example below. Essentially, the key is a copy of the puzzle board matrix that contains only the words which your program has found. All other characters of the board should be removed.

    Anti-hint: There are C library functions called strstr(), strchr(), and strrchr(), which you are NOT ALLOWED to use in this program. These functions would take away too much of your fun.

    Test Cases

    As part of your write up, please describe a set of cases that would be appropriate for testing this program. (Since designing these puzzles is non-trivial, you need not submit a puzzle of your own containing your tests, but describe what situations you would want to test.) It would also be wise of you to modify the example below if there are test cases missing from it, to allow you to thoroughly test your code.

    An (overly-simplified) list of test cases might look something like this:

    • include a horizontal word
    • include a vertical word

    Example

    Consider the input:

    
    G R N L R S Y S T E M E E O M R
    O C O M P U T E R E H I A I C U
    R A I M P R O G R A M A N R R R
    Q M E M O R Y A N T C R N T T M
    L A O N E T W O R K R O H H E U
    G T R Y S T R I N G I A E G Q E
    R R R N E A N Y L Y I L E E U R
    T R P T A R E C O S S G I T A A
    R L T P A R N A G O M E R U T S
    E I H H T A G L I K L B S R I C
    N T E Y T Y I C C M C R M I O H
    Y R O S A H N U U G R A E D N E
    P G R I N N E L L U U C A R S M
    C G Y C E K E U R S S B A S L E
    C N S S R E R S O U R R T P R B
    C N P O C N R M R U A I G A S O
    THEORY
    STRING
    ARRAY
    APPLE
    GRINNELL
    COMPUTER
    PHYSICS 
    CALCULUS
    ALGEBRA
    TIGER 
    SCHEME 
    NETWORK
    PROGRAM
    HOUSE 
    EQUATION
    MEMORY
    SLEEP 
    LOGIC 
    SYSTEM
    PIANO 
    

    When given this input, the program should print:

    
              S Y S T E M 
      C O M P U T E R 
            P R O G R A M 
      M E M O R Y
          N E T W O R K         E
            S T R I N G   A     Q
              A     L     L     U
              R   C O     G     A
        T P   R   A G     E     T S
        H H   A   L I     B     I C
        E Y   Y   C C     R     O H
        O S       U       A     N E
      G R I N N E L L             M
        Y C       U               E
          S       S
    

Any of the following problems may be done for extra credit. As noted in the course syllabus, however, a student's overall problems' average may not exceed 120%.

Unusual Canceling

  1. The fraction 64/16 has the unusual property that its reduced value of 4 may be obtained by "canceling" the 6 in the numerator with that in the denominator. Write a program to find the other fractions whose numerators and denominators are two-digit numbers and whose values remain unchanged after "canceling."

    Of course, some fractions trivially have this property. For example, when numerator and denominator are multiples of 10, such as 20/30, one can always "cancel" the zeroes. Similarly, cancellation is always possible when the numerator and denominator are equal, as in 22/22. Your program should omit these obvious cases.

    Note: An extensivie discussion of this problem may be found at Lucky fractions: Where bad arithmetic gives the correct answer by Tom Osler, Rowan University.

Alphabetizing Numbers

  1. Write a C program that generates the names of the numbers from zero to two hundred and prints them in alphabetical order.

    Notes:

    • All numbers should be written as lower-case names.
    • The program should be as compact as possible and utilize logic rather than brute force. (For example, a program consisting of 200 printf statements will earn very little credit.)
    • The program should run efficiently. (For example, few points will be given for a program utilizing a bubble sort.)

Common Letters

  1. Write a program that reads two strings and counts how many letters the strings have in common. To determine common letters, each letter of one word should be matched with exactly one letter of the second word. the case of the letters (upper case versus lower case) should be ignored.)

    Examples:

    • "room" and "tool" have two letters in common (each "o" in "room" is matched with a separate "o" in "tool").
    • "fewer" and "red" have two letters in common (the "e" in "red" matches one of the "e"s in "fewer" and both words contain one "r").
    • "Mississippi" and "Iowa" has just one letter in common (the "I" of Iowa matches one of the "i"s in "Mississippi").

Printing Cross Words

  1. Consider the problem of printing two words, the first word vertically (one letter per line) and the second word horizontally, so the words cross at a common letter. For example, if the first word is FUNCTIONAL and the second is SCHEME, then the desired output is:

    
     F
     U
     N
    SCHEME
     T
     I
     O
     N
     A 
     L
    
    

    In this problem, you are to write a program that reads two words from a terminal window and prints them in the crossed pattern shown above (assuming they have a letter in common). If the words have more than one letter in common, then they may be printed with the crossing at any common letter. If the words have no letters in common, then the program should print an error message.

Simulation of Hi Ho! Cherry-O

  1. This problem explores statistics for the game of Hi Ho! Cherry-O. For our purposes, we will follow the description of the game as described in Wikipedia. Note, however, that the number of cherries on a player's tree is always between 0 and 10. If one spins a bird or dog and the number of cherries on the tree is 8 or fewer, then the number of cherries on the tree goes up by 2. However, if one spins a bird or dog and the number of cherries on the tree is 9 or 10, then the number of cherries on the tree goes to 10 (not higher).

    The game progresses in rounds, during which each player in turn spins a game spinner that has seven outcomes (as described in the Wikipedia article). In our simulations, we will assume that each outcome of the spinner arises randomly with equal probability.

    Within this framework, the specific purpose of this supplemental problem is general statistics on how many rounds the game is likely to continue, based on the number of people playing the game. The required work for this problem involves three C procedures, combined within a main program.

    • Procedure turn simulates one turn of a player; that is, it takes a number init_cherries as parameter, and adjusts the number of cherries on the tree appropriately — using C's rand function to determine the outcome of the spinner.
    • Procedure playGame has players, the number of players, as input parameter, and returns the number of rounds taken until some player wins.
    • Procedure playNGames has two parameters: players, the number of players in a game, and games, the number of games to be simulated. playNGames returns a list with the maximum, minimum, and average number of rounds taken by the players over the full number of games.

    Hints: Although you are free to approach this problem however you want, the following pieces might help.

    • Write a procedure init_games that takes a number of players as parameter and generates a list of that number of 10's (the initial number of cherries on the trees for each of those players).
    • Write a procedure play_round that takes a list of tree-cherry numbers as parameter, plays one round for each player, and returns a list of new totals for the number of cherries for each player.
    • Write a procedure check_win that takes a list of tree-cherry numbers as parameter and checks if any of the players has won.

Dealing Bridge Hands

  1. Write a program that simulates the dealing of a deck of cards to give four bridge hands. The program should print both the cards held for each hand and the point-count for bidding.

    A simple scoring system gives an ace 4 points, a king 3 points, a queen 2 points, and a jack 1 point, with an extra point given if a hand contains all aces and a point deducted if it contains no aces. Points also are given for distribution, with a point given if a hand contains only 2 cards in a suit (a doubleton), 2 points given if a hand contains a single card in a suit (a singleton), and 3 points given if a hand has no cards in some suit.

Information on the 1997-1998 Iowa Senate

  1. File /home/walker/151s/labs/ia-senate contains information about the members of the 1997-1998 Iowa Senate. After a title line and a blank line, a typical line has the following form:
    
    Angelo          Jeff        44      Creston           IA 50801
    Kramer          Mary        37      West Des Moines   IA 50265
    Lundby          Mary        26      Marion            IA 52302-0563
    
    Thus, a typical line gives the last name, the first name, the district number, the town of residence, the state (always IA), and the town's zip code. The information in these lines is arranged in columns.

    Design and write a Scheme program that reads in data from this file and creates two output files, senators-by-district and senators-by-zip-code, in the current working directory. The senators-by-district file should contain the same data as the source file, in the same format, but with the lines arranged by senate district (column 3). The other file, senators-by-zip-code, should contain a list of all senators in the following format

    
     Angelo
    Creston, IA 50801
    
    A blank line should appear after each senator and city address. In this format, the name appears on a first line (first name, then last), and the city, a comma, the state, and zip code is on the next line -- separated by single spaces in the format shown. Note that a variation of this format (with a street address, if available) might be used for a mailing label.

File Analysis

  1. Write a C program that takes the name of a file as a command-line argument, opens the file, reads through it to determine the number of words in each sentence, displays the total number of words and sentences, and computes the average number of words per sentence. The results should be printed in a table (at standard output), such as shown below:

    
         This program counts words and sentences in file "comp.text ".
    
         Sentence:  1    Words: 29
         Sentence:  2    Words: 41
         Sentence:  3    Words: 16
         Sentence:  4    Words: 22
         Sentence:  5    Words: 44
         Sentence:  6    Words: 14
         Sentence:  7    Words: 32
    
         File "comp.text" contains 198 words words in 7 sentences
         for an average of 28.3 words per sentence.
    

    In this program, you should count a word as any contiguous sequence of letters, and apostrophes should be ignored. Thus, "word", "sentence", "O'Henry", "government's", and "friends'" should each be considered as one word.

    Also in the program, you should think of a sentence as any sequence of words that ends with a period, exclamation point, or question mark.

    Exception: A period after a single capital letter (e.g., an initial) or embedded within digits (e.g., a real number) should not be counted as being the end of a sentence.
    White space, digits, and other punctuation should be ignored.

Parenthesis Checking

  1. Write a program that reads a line of text from the terminal and checks if the parentheses in the line are balanced.

    Notes

    1. The program should distinguish among three types of parentheses, { }, [ ], ( ).
    2. Parentheses checking should involve working from the inside of nested parentheses to the outside.
    3. In each case, the appropriate right parenthesis should be matched with a left parenthesis of the same type.

    Examples

    1. ( these { parentheses[] match } perfectly ) !!!
    2. (the {right [parentheses ) on } this line ] are in the wrong order.
    3. this ( line { is missing } one (round ) right parenthesis.

    Comments on a solution to the problem: This problem can be solved reasonably easily using a single left-to-right scan of a line, if left parentheses are placed on a stack as they are encountered. Then, when a right parenthesis is found, the stack can be popped and one can check if the right parenthesis has the same type as the left one.

    Programming Note: Your program should use a self-contained Stack library package, as described in the lab on Stacks and Queues with Linked Lints and implemented as lists.

Recording and Retrieving Golf Scores

  1. The reading on doubly-linked lists presents this problem: "In recording scores for a golf tournament, we enter the name and score of the player as the player finishes. This information is to be retrieved in each of the following ways:

    • Scores and names can be printed in order by ascending or by descending scores.
    • Given the name of a player, other players with the same score can be printed."

    This supplemental problem asks you to solve this problem using a doubly linked list. Some details follow.

    • The program should maintain a doubly-linked list of nodes.
    • Each node should contain a player's name as a string and the int score that the player obtained in a round of golf.
    • The doubly-linked list should begin empty.
    • A menu for the program should include five options:
      1. Enter the name/score of a player
      2. Enter the name of a player and obtain a listing of those players who have the same score as the given player. (If the specified player is not found, the program should print that no players have been found.)
      3. List the players in ascending order of golf scores.
      4. List the players in descending order of golf scores.
      5. Exit the program.
    • Nodes in the linked list should be ordered in ascending order of score. (For players with the same score, any ordering of nodes is fine.)
    • Printing of nodes should start at one end of the list and proceed linearly to the other end using a simple iterative loop that takes advantage of the ordering in the doubly-linked list — recursion and doubly-nested loops should not be used.
    • To find players with the same score, the program should start searching at one end of the list and proceed linearly toward the other end. If the player is found, processing should follow "previous" links to find the first player with the given score. Then processing should follow "next" links to print subsequent players with the same score.

    Note: This program may utilize any code developed in the lab for doubly-linked lists (with appropriate citation). Since that lab does not place nodes in order (menu option a) or move back and forth from a given node (menu option b), those parts of this problem should not be based on the collaborative lab.