Comp 110 On Point Functions

On Point Functions

In this problem set you will write a collection of functions to work with Cartesian coordinate points. Each "point" in our program will be modeled using a List of numbers with a pair of values representing the x-coordinate and y-coordinate.

The learning objectives for this problem set are to:

  1. Gain comfort and familiarity with writing and calling functions
  2. Gain comfort and familiarity in working with Lists
  3. Experience process abstraction by first writing simple functions followed by more complex functions which make use of the simple functions
  4. Experience representation abstraction by using the generic concept of a List to represent a Cartesian coordinate Point

This problem set is broken into 3 sections: walk, run, and sprint. Each section is progressively more challenging. Start early. You are encouraged to complete each segment and check your work via the grader before continuing on to the next section.

Part 0. Starting the Dev Environment

As with in lecture, begin by opening up VSCode, ensuring your project is still open, and then running the following two commands in the VSCode Integrated Terminal:

  1. npm run pull
  2. npm start

The first command "pulls" the latest files needed for COMP110 into your repo, if any. The second command starts the development environment and will open your web browser to the local server. 

Part 1. Setting up an App

In the same directory used in lecture:

  1. Right click on the "src" folder
  2. Select "New Folder"
  3. Name the new folder: ps01-on-point-functions
    1. Note: capitalization and punctuation are important!
  4. Right click on the folder you just created
  5. Select "New File"
  6. Name the new file: index-app.ts
    1. Note: capitalization and punctuation are important!
    2. Note: the i in index is lowercase!

Part 2. Starting your Code

2.0 Honor Code Header

All problem sets begin with an Honor Code pledge. Notice this header is contained within block comment tags discussed in Lecture 1. You can copy paste the pledge below and fill in your name and ONYEN.

 * Author:
 * UNC Honor Pledge: I certify that no unauthorized assistance has been received
 * or given in the completion of this work. I certify that I understand and
 * could now rewrite on my own, without assistance from course staff,
 * the problem set code I am submitting.

2.1 Imports

The next step after ensuring the honor code header is to import the functions we'll use from the introcs library (i.e. printimage, and so on) and its List library. The first line of code to add to your app is the following:

import { print, promptNumber } from "introcs";
import { List, cons, first, rest } from "introcs/list";

2.2 The main Function

Your program's execution will begin in a special function named `main`. From this function, you will make use of the rest of the functions you will write (below) by calling them and working with their return values.

export let main = async () => {
   // TODO: Your function calls go inside of this block
// TODO: Define your functions here

Note: You should define the following functions before the call to main();

Part 3. Walk

In this section of the problem set we will establish some simple functions that will help us when writing the more complex functions which follow. Simple functions like these are often aptly called helper functions.

What is a "point"? For the purposes of our program, a point is represented as a List of 2 numbers. Trivia: In computer science we like to call these 2-tuples.

3.1 point - The goal of the point function is to make it easy to "construct a point". Here is an example usage:

let p0: List<number> = point(3, 4);
print(p0); // Prints: 3 → 4 → null

To begin, declare a function outside of the main function named point. It must take in two numbers as inputs, x and y, and return a List of numbers containing x and y in the correct order. Hint: use cons to construct the List inside of the point function.

Testing: How can you test whether you've correctly implemented the point function? Inside of your main function, try declaring a variable to store a List of numbers and assign it the result of calling point. Then try printing your variable. Is it as you expect? (Hint: see the example usage above.)

3.2 getX - The goal of the getX function is to return the x-coordinate component of a point. Here is example usage:

let p0: List<number> = point(3, 4);
let x: number = getX(p0);
print(x); // Prints: 3

Declare another function outside of the main function named getX. As shown above, it must take in a "point" as an input (critical question: what type are we using to represent a point?) and return the x value of that point. Hint: refer to lecture 5 for a refresher on how to access the first element of a List.

Testing: Make use of the getX function inside of your main function to convince yourself you are correctly returning the x-component of a point. See the above example usage for an idea on how to do this.

3.3 getY - The goal of the getY function is to return the y-coordinate component of a point. Here is example usage:

let p0: List<number> = point(3, 4);
print(getY(p0)); // Prints: 4

Declare another function outside of the main function named getY. As shown above, it must take in a "point" as an input and return the y value of that point. The y-component is stored in the 2nd value of a point List. How can you use a combination of the first and rest functions to access the 2nd value in a List?

Testing: Make use of your getY function from within the main function, like you did with getX, to convince yourself it is correctly implemented.

Grading Checkpoint

Before continuing to the jog section of this problem set, you should export your functions (described below) and submit your work in progress for grading. Once you've cleared all the test cases for Walk, continue on to jog.

Exporting Functions for Grading

In order for the grader to test your implementations, you will need to export your functions. This simply means adding the keyword "export" before "let <function name>", just like the main function. Here is an example:

export let point = (x: number, y: number): List<number> => { // ...

We will explore "exporting" and "importing" in more depth later this semester.

Be sure to export pointgetX, and getY before submitting for grading!

Part 4. Jog

In Jog, you will need to determine the correct types of each function definitions's parameters and return type based on the example usages.

4.1 pointToString - The goal of the pointToString function is to make it easy to get a nice textual representation of a point. Here is an example usage:

let p0: List<number> = point(3, 4);
let s: string = pointToString(p0);
print(s); // Prints: "(3, 4)"

Declare a function named pointToString that can be used as shown above. The formatting of the returned string is specifically: "(<x>, <y>)" where there is a space following the comma.

Implementation hint: you will need to use string concatenation (lecture 2) to generate this string. You are highly encouraged to call the getX and getY helper functions you wrote in the Walk section to help you implement pointToString.

4.2 inverse - The goal of the inverse function is to produce an inverse point, where x and y are flipped. For example:

let p0: List<number> = point(3, 4);
let p0Inverse: List<number> = inverse(p0);
print(pointToString(p0Inverse)); // Prints: (4, 3)

Declare a function named inverse that can be used as shown above. Hint: You are highly encouraged to compose calls to the point, getX, and getY functions you wrote in the Walk section to implement this function.

4.3 slope - The goal of the slope function is to calculate the slope of a line between two points. For example:

let result: number = slope(point(0, 0), point(1, 1));
print(result); // Prints 1

Notice the slope function must take in 2 points. Given two points, where p0 is (x0, y0) and p1 is (x1, y1), the formula for computing a slope is: (y1 - y0) / (x1 - x0)

4.4 add - The goal of the add function is to compute the addition of two Cartesian coordinate points. For example:

let result: List<number> = add(point(1, 2), point(4, 1));
print(pointToString(result)); // Prints (5, 3)

How can you make use of helper functions you've already written to simplify the implementation of add?

4.5 distance - The goal of the distance function is to compute the distance between two points. For example:

let result: number = distance(point(1, 2), point(3, 4));
print(result); // Prints 2.8284271247461903

The distance between two points formula requires squaring two values and taking a square root. Here's how you can do each of them:

// The "exponentiation operator" is **
print(3 ** 2); // Prints 9
print(3 ** 3); // Prints 27
// The "square root" function is Math.sqrt
print(Math.sqrt(9)); // Prints 3
print(Math.sqrt(4)); // Prints 2

Grading Checkpoint

Before continuing to the sprint section of this problem set, you should export your functions from jog (described above) and submit your work in progress for grading. Once you've cleared all the test cases for Jog, continue on to Sprint.

Part 5. Sprint

Up until now we've blissfully assumed that anytime a function like pointToString is called it is being given a List of numbers with exactly two numbers in it. What happens if you were to call pointToString with an empty List? Your program will crash!

In the final segment of this problem set we will 1. write a function named isPoint to tell us true/false whether a List of numbers is actually a Point and 2. improve our functions from jog to not crash when given a List that is not a "point" with exactly 2 numbers in it.

5.1 isPoint - This function will test whether a given List of numbers is a point, or more specifically, a List with exactly two numbers in it. For example:

print(isPoint(null)); // false
print(isPoint(cons(1, null))); // false
print(isPoint(point(1, 2))); // true
print(isPoint(cons(0, point(1, 2)))); // false 

The isPoint function should return true if and only if the List of numbers it is given has exactly two numbers in it. It should return false otherwise. Note: you should not use recursion to implement this function.

Hint: How can you tell if a List has exactly two numbers in it? How can you tell if a list has 0 elements in it? What about 1? You've reached the last value of a List when the rest of the List is null.

5.2 Avoid Errors on Bad Input DataNote: this final step involves modifying functions you've already implemented! Consider backing your program up at this point by making a copy of it.

The last step of this problem set is to improve each of your functions from the jog section by making them more resilient to errors caused by bad inputs. You should make use of the isPoint helper function you just wrote above. For each of the following descriptions, when we say "is not a point" we specifically mean calling isPoint with the input List will return false.

pointToString - If the input List is not a point, return "Error! Not a point." Example:

print(pointToString(point(1, 2))); // Prints "(1, 2)"
print(pointToString(null)); // Prints "Error! Not a point."

inverse - If the input List is not a point, return null. Example:

print(inverse(point(1, 2))); // Prints: 2 → 1 → null
print(inverse(cons(1, null))); // Prints: null

slope - If either of the input Lists are not points, return NaN (NaN is special constant in the programming language that stands for Not-a-Number).

print(slope(null, null)); // Prints NaN

add - If either of the input Lists are not points, return null.

print(add(point(1, 2), null)); // Prints null

distance - Like slope, if either of the input Lists are not points, return NaN.

print(distance(cons(1, null), point(2, 3))); // Prints NaN

Final Grading Checkpoint

Be sure to export your isPoint function before submitting for grading. After completing the Sprint portion of this problem set, you are 100% complete! Great work!

Recap Conceptual Questions

Come talk to us in office hours about these questions if you do not feel confident in your answers! Note: you do not need to hand these in, these are for review purposes.

0. Without submitting to grading, what was the best way to test the correctness of your functions?

1. What actually is a "point"?

2. After you implemented the walk functions: point, getX, and getY, when you knew you were working with a point List, did you need to use the built-in List functions cons, first, or rest anymore?