- 08-31 - Changed the due date from September 7 to September 9.
- 09-03 - You can add an unlisted number to a phonebook again after it has already been added as listed.
- 09-03 - You can assume the integer passed in to isPalindrome() is non-negative.
Due: September 9, 2021 at 11:59 PM (late September 10, 5% penalty). Note the deadline: just under one week
Points: 80 public, 20 semipublic
This is an individual assignment. You must work on this project alone.
If you have not yet completed project 0, you should do so before starting this project. At the very least, you should have everything related to Ruby installed correctly. If you have any trouble with installation, check Piazza (or create a post if you don't find your problem there), or come to office hours to get help from a TA.
This project aims to give you some experience with basic Ruby functionality, including using basic data types (integers, strings), collections (arrays and hashes), and classes. You will also become familiar with Ruby's basic control constructs for looping and conditional execution, and how to run Ruby unit tests.
You should have cloned the repository in project 0. To download new projects (such as this one), go to the cloned repo in your terminal and run git pull
. This will download the files for this project and update your cloned repository.
You will submit this the same way you submitted project 0: by running gradescope-submit
in the project1a
folder. If you are unable to get this to work, you can just submit both files in the src/ directory manually to the assignment on Gradescope.
Ruby has no built-in way to restrict the types passed to methods. As such, all method types specified in this document are the only ones you need to handle. You may assume that no arguments will be passed outside of the types we specify, and your program may do anything in cases where improperly typed arguments are passed. This is undefined behavior for this program and will not be tested.
The expected types will be represented in the following format at the beginning of each section:
(String) -> Array or nil
The left-hand side of the arrow specifies the parameter types, and the right-hand side specifies the return type. This example describes a method that takes a single String
as an argument and either returns an Array
or nil
. When implementing a method with this signature, you may assume that a String
will be passed in and you are responsible for ensuring that only a Array
or nil
is returned. (Since Ruby is object oriented, the signature also means that a subclass of String
could be passed in, and that a subclass of Array
could be returned.)
Note: Some shorthand is used to avoid verbosity in type siguatures; namely:
Integer
is used to refer to eitherFixnum
orBignum
(i.e., we can think ofInteger
as a superclass of these two).Bool
is used to refer to the eitherTrueClass
orFalseClass
.nil
is used to refer toNilClass
.
Implement part 1 in warmup.rb
. Each of the methods you must implement are described below. We provide you with the signature of each method and a description of its required behavior. For some methods, we state assumptions that you can make about the input. In these cases, it doesn't matter what your code does if the assumption isn't met, since we will never run a test case that contradicts the assumption.
- Description: Returns the first
n
fibonacci numbers. - Type:
(Integer) -> Array
- Assumptions:
n
is non-negative. - Examples:
fib(0) == [] fib(1) == [0] fib(2) == [0, 1] fib(3) == [0, 1, 1] fib(10) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
- Description: Returns
true
ifn
is a palindrome andfalse
otherwise. A palindrome is the same read forward and backward. - Type:
(Integer) -> Bool
- Assumptions:
n
is non-negative;n
will not be provided with any leading 0s. - Hint: It may be easier to do this after converting the provided integer to a String.
- Examples:
isPalindrome(0) == true isPalindrom(1) == true isPalindrome(10) == false isPalindrome(101) == true isPalindrome(120210) == false
- Description: Returns the
n
th largest value in the arraya
ornil
if it does not exist. That the largest value is specified using n = 0. - Type:
(Integer, Array) -> Integer or nil
- Assumptions:
n
is non-negative. - Examples:
nthmax(0, [1,2,3,0]) == 3 nthmax(1, [3,2,1,0]) == 2 nthmax(2, [7,3,4,5]) == 4 nthmax(5, [1,2,3]) == nil
- Description: Returns a one-character string containing the character that occurs with the highest frequency within 's'. If
s
has no characters, it should return the empty string. - Type:
(String) -> String
- Assumptions: Only one character will have the highest frequency (i.e. there will be no "ties").
- Examples:
freq("") == "" freq("aaabb") == "a" freq("bbaaa") == "a" freq("ssabcd") == "s" freq("a12xxxxxyyyxyxyxy") == "x"
- Description: Returns a hash that maps corresponding elements in
arr1
andarr2
, i.e.,arr1[i]
maps toarr2[i]
, for all i. If the two arrays are not the same length, returnnil
. - Type:
(Array, Array) -> Hash or nil
- Examples:
zipHash([], []) == {} zipHash([1], [2]) == {1 => 2} zipHash([1, 5], [2, 4]) == {1 => 2, 5 => 4} zipHash([1], [2, 3]) == nil zipHash(["Mamat", "Hicks", "Vinnie"], ["prof", "prof", "TA"]) == {"Mamat" => "prof", "Hicks" => "prof", "Vinnie" => "TA"}
- Description: Returns an array of arrays; each element of the returned array is a two-element array where the first item is a key from the hash and the second item is its corresponding value. The entries in the returned array must be sorted in the same order as they appear in
hash.keys
. - Type:
(Hash) -> Array
- Examples:
hashToArray({}) == [] hashToArray({"a" => "b"}) == [["a", "b"]] hashToArray({"a" => "b", 1 => 2}) == [["a", "b"], [1, 2]] hashToArray({"x" => "v", "y" => "w", "z" => "u"}) == [["x", "v"], ["y", "w"], ["z", "u"]]
In part 2, you will be implementing a PhoneBook class. It is up to you to decide how to store the data (i.e., how to define a phonebook instance's fields) so that you can correctly implement all the required methods.
Even though the data structure you will implement is up to you, keep the following in mind:
- The Phonebook will hold names and phone numbers, as well as a note on whether each name and phone number pair is listed or not.
- By listed, we mean that they are marked as so (not simply stored). You might want to use a boolean to determine it so.
- The Phonebook might contain listed and unlisted entries. How you should add them will be specified in the
add
method below.
- Description: This is the constructor. You should initialize the fields that you think your class needs for successful evaluation of the remaining methods. We do not test the constructor directly, but we do test it indirectly by testing the remaining methods.
-
Description: This method attempts to add a new entry to the PhoneBook.
name
is the name of the person andnumber
is that person's phone number. Theis\_listed
parameter identifies if this entry should be listed or unlisted in the PhoneBook (true
if listed,false
if unlisted). Returntrue
if the operation was successful, andfalse
otherwise. Here are the requirements for the add method:- If the person already exists, then the entry cannot be added to the PhoneBook.
- If
number
is not in the formatNNN-NNN-NNNN
, the entry cannot be added to the PhoneBook. - A
number
can be added as unlisted any number of times, but can only be added as listed once. This means that ifnumber
already exists and is listed in the PhoneBook, the new entry can only be added if the entry will be unlisted.
-
Type:
(String, String, Bool) -> Bool
-
Assumptions: No phone number will start with 0.
-
Examples:
@phonebook = PhoneBook.new @phonebook.add("John", "110-192-1862", false) == true @phonebook.add("Jane", "220-134-1312", false) == true @phonebook.add("John", "110-192-1862", false) == false @phonebook.add("Ravi", "110", true) == false
Here is another example:
@phonebook2 = PhoneBook.new @phonebook2.add("Alice", "012-345-6789", false) == true @phonebook2.add("Bob", "012-345-6789", false) == true @phonebook2.add("Eve", "012-345-6789", true) == true @phonebook2.add("Rob", "012-345-6789, true) == false @phonebook2.add("Johnny B. Good", "012-345-6789, false) == true
- Description: Looks up
name
in thePhoneBook
and returns the corresponding phone number in the formatNNN-NNN-NNNN
ONLY if the entry is listed. Otherwise, returnnil
. - Type:
(String) -> String or nil
- Examples:
@phonebook = PhoneBook.new @phonebook.add("John", "110-192-1862", false) == true @phonebook.add("Jane", "220-134-1312", true) == true @phonebook.add("Jack", "114-192-1862", false) == true @phonebook.add("Jessie", "410-124-1131", true) == true @phonebook.add("Ravi", "110", true) == false @phonebook.lookup("John") == nil @phonebook.lookup("Jack") == nil @phonebook.lookup("Jane") == "220-134-1312" @phonebook.lookup("Jessie") == "410-124-1131" @phonebook.lookup("Ravi") == nil
- Description: Returns the name associated with a given number only if the entry is listed. Otherwise, return
nil
. - Type:
(String) -> String or nil
- Examples:
@phonebook = PhoneBook.new @phonebook.add("John", "110-192-1862", false) == true @phonebook.add("Jane", "220-134-1312", true) == true @phonebook.add("Jack", "114-192-1862", false) == true @phonebook.add("Jessie", "410-124-1131", true) == true @phonebook.lookupByNum("110-192-1862") == nil @phonebook.lookupByNum("114-192-1862") == nil @phonebook.lookupByNum("220-134-1312") == "Jane" @phonebook.lookupByNum("410-124-1131") == "Jessie"
- Description: Returns an array of all names in the
PhoneBook
who have phone numbers beginning withareacode
, including unlisted names. - Type:
(String) -> Array
- Examples:
@phonebook = PhoneBook.new @phonebook.add("John", "110-192-1862", false) == true @phonebook.add("Jane", "220-134-1312", true) == true @phonebook.add("Jack", "114-192-1862", false) == true @phonebook.add("Jessie", "110-124-1131", true) == true # Note that Jessie's number here is a little different than in the other examples! @phonebook.namesByAc("110") == ["John", "Jessie"] @phonebook.namesByAc("114") == ["Jack"] @phonebook.namesByAc("111") == []