CMSI 185
Final Exam Preparation

Logistics

The final will be on Tuesday, December 15, 2020, at 2:00 p.m.

You will have two hours. It will be open book, open notes, open computer, open everything. It will have 20 multiple-choice questions worth 5 points each. The ground rules are that you may use any source, online or offline, during the exam, except (1) other students’ exam work, and (2) sources where you can ask questions and have them answered by a human. That means you can use books, notes, CodePen, and web searches, but you cannot post questions to a forum or any question-answer site, nor solicit answers or help from any human, nor can you pull information off of other students’ exams. An additional rule is that you may not broadcast answers either by voice, text, electronic message, coughing, hand signals, or any other medium.

The exam may be difficult to finish, so the best grades will naturally go to those students whose programming skills have risen to the point where most of the programming patterns we've encountered in the class are trivial to recall and use to create scripts.

A Review of Topcs

The exam will cover everything we've done in class. Everything is on the table. To preare, it’s best to review the main points of what you should have learned in this class.

Good Programming Practice

JavaScript Technical Stuff

You are expected to know what each of these terms mean, and to give an example of each:

Values
Types
    Null vs. Undefined
    Boolean
    Number
    String
    Object
        -- know lots of object functions
    Array
        -- know lots of array functions
Expressions
    Operators
        Precedence
        Associativity
    Errors (Exceptions)
        Try
        Catch
        Throw
Statements
    Declaration
        Let
        Const
    Assignment
    Conditional Statements
        If
        Switch
        (Conditional Statement vs. Conditional Expression)
    Iteration
         Definite Iteration (For)
             For-of vs. For-in
             For-each
         Indefinite Iteration (While)
Functions
    Defining functions
    Calling functions -- running functions, invoking functions
    Parameter
    Argument
    Validation
    Mutators vs. Non-mutators
    "Modules"
    Objects with Functions inside
    Function-oriented vs. Object-oriented
        receiver
        method
    Constructors
    Prototypes
    Classes

Programming Skills

Writing 2-D p5.js scripts
Writing 3-D p5.js scripts
Working with QUnit tests
Using fetch

Don’t worry, you won’t be tested on GitHub.

Practicing

I’ve made available three modes of practice to help you!

  1. Practice Problems from the course website
  2. A Practice Final Exam on BrightSpace
  3. Practice Functions, with a test script

There class has an emphasis on writing functions and classes, so here are some functions for you to practice, with a test script!

/*
 * Returns an array with the minimum number of U.S. quarters, dimes, nickels, and pennies,
 * respectively, that make the given amount. Precondition: the amount is a nonnegative
 * safe integer.
 */
function change(amount) {
  .
  .
  .
}

/*
 * Returns the string just like s except with Basic Latin vowels removed.
 */
function stripBasicLatinVowels(s) {
  .
  .
  .
}

/*
 * Returns a random permutation of the given string. This is a direct implementation
 * of the Fisher-Yates shuffle, which is awesome. Don't use the random technique! See
 * https://stackoverflow.com/q/962802/831878
 */
function scramble(s) {
  .
  .
  .
}

/*
 * Produces successive powers of two, up to the given limit, passing each to a callback.
 */
function powersOfTwo(limit, callback) {
  .
  .
  .
}

/*
 * Produces successive powers of a given base, up to the given limit, passing each to a
 * callback. Precondition: base is strictly greater than 1.
 */
function powers(base, limit, callback) {
  .
  .
  .
}

/*
 * Returns the interleaving of two arrays. The lengths of the arrays do not need to be
 * the same.
 */
function interleave(a, b) {
  .
  .
  .
}

/*
 * Returns an array with its elements stuttered.
 */
function stutter(a) {
  .
  .
  .
}

/*
 * Returns an object providing a count of the number of times each word (consisting of
 * Latin letters and apostrophes only) appears in the string.
 */
function wordCount(s) {
  .
  .
  .
}

// Here are some tests. You will need to import QUnit.

QUnit.test("Change Tests", t => {
  t.deepEqual(change(97), [3, 2, 0, 2]);
  t.deepEqual(change(8), [0, 0, 1, 3]);
  t.deepEqual(change(250), [10, 0, 0, 0]);
  t.deepEqual(change(0), [0, 0, 0, 0]);
  t.deepEqual(change(144), [5, 1, 1, 4]);
  t.deepEqual(change(100000000000), [4000000000, 0, 0, 0]);
});

QUnit.test("Strip Vowels Tests", t => {
  t.deepEqual(stripBasicLatinVowels("Hello, world"), "Hll, wrld");
  t.deepEqual(stripBasicLatinVowels(""), "");
  t.deepEqual(stripBasicLatinVowels("AaBbCcDdEeFfIiOoUu"), "BbCcDdFf");
  t.deepEqual(stripBasicLatinVowels("cA"), "c");
  t.deepEqual(stripBasicLatinVowels("\u00E9"), "\u00E9");
  t.deepEqual(stripBasicLatinVowels("zz\u00E9"), "zz\u00E9");
  t.deepEqual(stripBasicLatinVowels("uUeeeEEiIioooouuuAAAUUOO"), "");
});

QUnit.test("Scramble Tests", (t) => {
  const anagram = (s, t) => {
    return s.split('').sort().join('') === t.split('').sort().join('');
  };
  const data = ["a", "rat", "JavaScript testing", "", "zzz", "^*&^*&^▱ÄÈËɡɳɷ"]
  data.forEach(s => {
    t.ok(anagram(s, scramble(s)));
  });
});

QUnit.test("Powers of Two Tests", t => {
  function powersOfTwoToArray(limit) {
    const result = [];
    powersOfTwo(limit, x => {
      result.push(x);
    });
    return result;
  };
  t.deepEqual(powersOfTwoToArray(-5), []);
  t.deepEqual(powersOfTwoToArray(0), []);
  t.deepEqual(powersOfTwoToArray(1), [1]);
  t.deepEqual(powersOfTwoToArray(63), [1, 2, 4, 8, 16, 32]);
  t.deepEqual(powersOfTwoToArray(64), [1, 2, 4, 8, 16, 32, 64]);
});

QUnit.test("Powers Tests", t => {
  function powersToArray(base, limit) {
    const result = [];
    powers(base, limit, x => {
      result.push(x);
    });
    return result;
  };
  t.deepEqual(powersToArray(5, -5), []);
  t.deepEqual(powersToArray(8, 0), []);
  t.deepEqual(powersToArray(100, 1), [1]);
  t.deepEqual(powersToArray(100, 99), [1]);
  t.deepEqual(powersToArray(100, 100), [1, 100]);
  t.deepEqual(powersToArray(3, 242), [1, 3, 9, 27, 81]);
  t.deepEqual(powersToArray(3, 243), [1, 3, 9, 27, 81, 243]);
});

QUnit.test("Interleave Tests", t => {
  t.deepEqual(interleave([], []), []);
  t.deepEqual(interleave([1, 4, 6], []), [1, 4, 6]);
  t.deepEqual(interleave([], [2, 3]), [2, 3]);
  t.deepEqual(interleave([1], [9]), [1, 9]);
  t.deepEqual(interleave([8, 8, 3, 9], [1]), [8, 1, 8, 3, 9]);
  t.deepEqual(interleave([2], [7, "8", {}]), [2, 7, "8", {}]);
});

QUnit.test("Stutter Tests", t => {
  t.deepEqual(stutter([]), []);
  t.deepEqual(stutter([true]), [true, true]);
  t.deepEqual(stutter([2, "x"]), [2, 2, "x", "x"]);
  t.deepEqual(stutter([3, [4], 5]), [3, 3, [4], [4], 5, 5]);
  t.deepEqual(stutter([1, [[[2]]], 3]), [1, 1, [[[2]]], [[[2]]], 3, 3]);
});

QUnit.test("Word Count Tests", t => {
  t.deepEqual(wordCount(""), {});
  t.deepEqual(wordCount("  hi    hi bye/HI    bye  "), { hi: 3, bye: 2 });
  t.deepEqual(wordCount("if you dog a  .,? . dog"), {
    dog: 2,
    a: 1,
    you: 1,
    if: 1
  });
  t.deepEqual(wordCount("a\n\n   \n\rA $$%"), { a: 2 });
  t.deepEqual(wordCount("^*&^*&^▱ÄÈËɡɳɷ"), {});
});