Java Python CISC181(S21) Lab 3
This lab requires that you download the file Lab03.zip from onQ. Don't be dismayed by the length of the lab: The text is mostly explanatory. You will have to pay attention to what you're doing, however.
Submission guidelines
The problems on this lab require a mix of solution types. Part 1 requires you to type a solution into text boxes on this document and to edit an HTML file. Part 2 requires you to copy and edit another HTML file. Place the following into a zip file called Lab03_solutions.zip:
· Your completed Lab03.docx file
· Your completed beancounter.html file
· Your completed binary_search.html file
Upload that .zip file to onQ by the lab's due date and time.
Part 1 (10 marks)
Programming requires that you type everything to an exact specification, and this is not as easy as it may seem. Professional programmers frequently work in pairs, partly so that one programmer can spot typographical errors or omissions made by the other programmer. Unfortunately, working on this lab by yourself, you do not have the luxury of the extra pair of eyes, but you do have the advantage of being able to copy and paste some code from this document.
As with Lab 2, for this lab you will need a plain text editor; ideally one that knows just a little about the web markup language, HTML (which we will look at in more detail later in the course) and JavaScript. program code. My preference, again, is for Visual Studio Code. You will not lose points on this lab for using a different editor, but you should not try using Microsoft Word or any program like it that inserts formatting codes into its documents.
JavaScript. is a programming language that all modern web browsers understand. As a programming language, it has its strengths and weaknesses, but one of its strengths is its ubiquity; it is everywhere! All but the very simplest websites use it extensively, so it is worth your while to understand a bit about it.
I have written a JavaScript. program for this lab and built it into the webpage beancounter.html which you can extract to a folder on your computer from Lab03Files.zip (available from onQ). Have a look at it by dragging it from a file listing on your computer onto an open web browser. The program will run automatically, waiting for you to place a fake coffee shop order. It should look very much like this:
Okay, start your text editor and then open beancounter.html in it. It's quite a long file. On my Windows machine, the top part of the file looks like this in Visual Studio Code:
On a Mac, in a different editor, or even in the same programs but with a different configuration, the file may look a little different, but here are some things to note:
· Good code editors try to make the programmer's job easier by colouring certain kinds of elements differently from others. Thus, for example, all the numbers are a sort of pink (fuchsia, maybe?) in VS Code.
· The file's text begins with the line "<!DOCTYPE html>". The editors use line numbering to identify this as line 1. If the editor you are using does not show line numbers by default, see if there is an option to turn them on. (If there is no such option, there may be an indicator somewhere on your editor's interface showing you the number of the line that is currently being edited.)
· The file has two large sections of note. The first lies between the <script> and </script> tags (lines 6 and 164, respectively) and is where most of the JavaScript. code can be found. The second sits lower down inside the <form> and </form> tags (lines 172 and 223), and it provides both the raw elements of the user interface (the button inputs and text box outputs) and some values for many of the JavaScript. variables. Think of the form, therefore, as providing the input and output devices for the program found within the <script> and </script> tags. When you load the page into a web browser – whether from a distant server or from your own computer – the browser interprets the form. and some style. information it retrieves from the server.
· Styling for the user interface – details of colour, how the boxes and buttons are drawn and placed, etc. – are contained in a file on the sites.cs.queensu.ca server that is imported on line 5. We will learn a bit about styling HTML and about HTML itself later in the course.
SAVE YOUR WORK IN YOUR EDITOR FREQUENTLY! Ctrl-S (holding down your Control or Ctrl key and pressing S) will likely do this quickly and easily. If you really mess up, it may be best to start again with a freshly extracted copy of beancounter.html. When you are asked to do any editing, make the changes in your text editor, save your work, then refresh your browser window or drag the revised file to your browser again to see how those changes are reflected in the running program.
1. (1 mark) The program has a keypad to enter quantities, and it runs subtotals (updated using the button marked "Enter") so that the user can, for example, enter complex orders like "2 espressos, 3 short lattes with two espresso shots, 4 tall cappuccinos, and 4 grande Americanos." Use the program to enter this order,
· click on "2" on the keypad
· then click on "ESPRESSO" (in the "Drink Type" box)
· then click on "Enter" (in the "Calculations" box)
· then click on "3" on the keypad
· then click on "Short" (in the "Cup Size" box)
· then click on "2" (in the "Shots (of espresso)" box)
· then click on "LATTE"
· then click on "Enter"
· … and so on…
· then, finally, click on "Total"
How much, tax included, is 2 espressos, 3 short lattes with two shots of espresso, 4 tall cappuccinos, and 4 grande Americanos? (Note: Espresso only comes in one size, so if you place an order for espresso, the "Cup Size" will be ignored.)
Go here, http://sites.cs.queensu.ca/courses/cisc181/lab03-01.txt to check your answer, and if you do not get the same amount, try clicking on the "Clear" button and starting over. It is rather important to the rest of the lab that you understand how to use the program.
2. (1 mark) cupSize is the name (or identifier) of a variable in my JavaScript. program, and clicking on any of the buttons labeled "Short," "Tall," or "Grande" causes that variable to be loaded with a different value. A JavaScript. variable should be declared in a var statement before it is used. Note the line numbers that your editor puts down the left side of the code in its editing window. Which line is the variable cupSize declared on? (Hint: Look for the "var" keyword in front of the identifier "cupSize.").
3. (1 mark) When a variable is declared, it may also be initialized (given its initial – meaning first – value) using the assignment operator (an equals sign). What is the initial value of cupSize?
4. (2 marks) Nationalist sentiments being what they are, Head Office wants us to "Canadianize" our product line, and of course, our Canadian sales taxes are different from the American taxes built into the program currently, so that needs to be changed, too. As you make each change, test it in your browser. For both marks, your program must run correctly after making these changes. Here are the changes you are to make:
a) The drink known as Americano is to become Canadiano. (Note that there are nine occurrences of Americano, spelled with upper- and/or lower-case letters, forming parts of identifiers in some cases, in the program and the form. Make sure you change them all, preserving the case, upper and/or lower, of the characters as you go.) Your editor likely has a search-and-replace feature that lets you specify whether you want to consider character case in your search. Make sure you select that option. Getting the character case incorrect may mean the difference between your program working and not working.
b) There is a variable called taxRate that is currently being initialized to 0.0848 (which is the tax rate for some American state). This value should be changed to 0.13, representing Ontario's 13% Harmonized Sales Tax (HST). (Note that Ontario charges a reduced tax rate for total restaurant orders of $4.00 or less, but we will not worry about that.)
Having made these changes, save your work, then "Preview" your revised document, and tell me the cost, tax included, of 2 espressos, 3 short lattes with two shots of espresso, 4 tall cappuccinos, and 4 grande Canadianos?
Check your answer using a calculator or a spreadsheet program (like Excel) before continuing.
5. This is the trickiest part of the lab. For full marks, your program must run correctly after making these changes. Try to preserve the indenting patterns used in the original code.
You are going to introduce a new control on the interface and change the program logic to work with the information it provides. As with all the foregoing, make sure everything is typed exactly as shown, paying special attention to the names of elements like "staffDiscount" with mixed upper- and lowercase letters.
Here is the idea: Head office has decided to offer employees a discount on purchases. It is to be applied to the subtotal amount when the user clicks on the "Total" button and will show up as a separate line item in the "Amounts Owing" box as "Staff Disc". The system user indicates whether a staff discount is to apply to a purchase by means of a checkbox control placed to the right of the "Enter" button. If this control is checked…
… then the discount will be applied when the user clicks on "Total." If it is left unchecked (the default state)…
… then the discount will not be applied.
I have already made some adjustments to the styling of the web page to accommodate the new control and its output field. Here is what you need to do to incorporate them and make them work:
a) (1 mark) We'll make changes to the interface first, starting with the checkbox and its label. Find this line down in the <body>…</body> section of the HMTL:
<input type="button" id="enterItem" value="Enter">
Insert these four lines immediately below it:
<label for="staffDiscountCheckbox">
<input type="checkbox" id="staffDiscountCheckbox">
Staff discount
</label>
Try to preserve the indenting at that point in the file. Save your work and preview it to see that the checkbox and its "Staff discount" label appear as in the second image above. (You should be able to check and uncheck it at this time, but it will not affect calculations yet.)
b) (1 mark) Now we will add the output box for the staff discount amount in the "Amounts Owing" area. Find this HTML:
<label for="subtotal">Subtotal</label>
and insert the following lines below it:
<input class="number" type="text" id="staffDiscount" value="$0.00" readonly>
<label for="staffDiscount">Staff Disc</label>
Save your work and look at it in your browser to see that the "Staff Disc" label and its field appear under the "Subtotal" field in the "Amounts Owing" section of the interface. At this stage, the interface is complete, but the new additions still do not affect the operation of the program because you have not done any actual programming with them. That comes next.
c) (1 mark) Head office has said that it wants to experiment with the concept by first giving a 6% discount to staff. As this might change in future, it makes sense for you to introduce a variable that is declared and initialized near the top of the program, perhaps where a great many other variables are declared and initialized. So, find where the variable called price is declared and initialized to 0.00 up in the JavaScript. code, and insert a declaration and initialization for a new variable, staffDiscountRate, below it as follows:
var staffDiscountRate = 0.06;
Save your work.
d) (2 marks) When the user clicks on the "Total" button, the function called total() is executed, causing calculations to happen and numbers to appear in the "Tax" and "Total" fields. This is where we are going to add the logic to test whether the user has "checked" the "Staff discount" checkbox, and, if so, make the amount showing beside "Staff Disc" change from $0.00 to whatever the calculated discount should be, and then to have this amount be used in the "Tax" and "Total" calculations. First, find the code for a function called calculateTotal(), then replace that code with this,
function calculateTotal () {
var staffDiscount = 0.00;
if (document.getElementById("staffDiscountCheckbox").checked) {
staffDiscount = Math.round(subtl * staffDiscountRate * 100)/100;
}
document.getElementById("staffDiscount").value = "$" + formatPrice(staffDiscount);
var taxes = Math.round((subtl - staffDiscount) * taxRate * 100)/100;
document.getElementById("tax").value = "$" + formatPrice(taxes);
document.getElementById("amountOwing").value =
"$" + formatPrice(subtl - staffDiscount + taxes);
}
Having made these changes, save your work, then refresh your browser window and find out the cost, tax included, of 1 espresso, 2 short lattes with three shots of espresso, 3 tall cappuccinos, and 3 grande Canadianos, first without a staff discount, and then with?
(without staff discount) (with staff discount)
Part 2 (15 marks)
As was the case with Part 1, this portion of the lab will again have you making some changes to a JavaScript. program using a program editor such as Visual Studio Code. This time, however, you are going to be working from a pseudocode algorithm that you have seen before, that is, the one presented in the Algorithms module for binary search, to implement the algorithm in JavaScript. so that it works on real data.
To begin:
· Extract the linear_search.html file from Lab03Files.zip to a convenient place for working on it, like your computer's desktop.
· Open linear_search.html in your editor.
Here is the algorithm for binary search in pseudocode. You will be referring to it a lot while you gradually turn it into JavaScript. code that can be compiled and executed in your browser.
let n be the length of the list of numbers
let a be the list of numbers (a0, a1, a2, ..., an-1)
let val be number being searched for
let low be 0
let high be n - 1
while low ≤ high
let mid be floor((low + high)/2)
if amid = val
report position of val as mid
stop
if amid < val
let low be mid + 1
otherwise
let high be mid - 1
report val is not in the list
Something to keep in mind: The indenting in the pseudocode, above, is significant. It shows us which statements belong to the while loop, and which belong to the two if statements and the otherwise statements. Importantly, it tells us that the report statement is not in the while loop. Your final JavaScript. code should retain this indenting structure. It will help you (and a TA!) to spot potential problems in your code.
Since there are two levels of indenting in this pseudocode, your finished code should contain corresponding JavaScript. blocks, each of which begins with a "{" curly bracket and ends with a "}" curl CISC181(S21) Lab 3Java y bracket. To make it more obvious where the blocks are, I have expanded my pseudocode below to include "{" and "}" block markers and made them bold so they are easier to see…
let n be the length of the list of numbers
let a be the list of numbers (a0, a1, a2, ..., an-1)
let val be number being searched for
let low be 0
let high be n - 1
while low ≤ high {
let mid be floor((low + high)/2)
if amid = val {
report position of val as mid
stop
}
if amid < val {
let low be mid + 1
}
otherwise {
let high be mid – 1
}
}
report val is not in the list
Refer to the above pseudocode frequently during this lab, as it accurately reflects the indenting and correct placement of the curly brackets in the JavaScript. program you are about to create.
We're going to start with a big advantage: An existing program that demonstrates a linear search. It's in the Lab03.zip file, stored as linear_search.html, so extract it, open it in your text editor, and have a look at it there or on the next page.
<!DOCTYPE html>
<html>
<head>
<title>Linear Search demo</title>
<script>
// Test lists
var word_list = ["cat", "duck", "frog", "rat", "unicorn"];
var number_list = [-12, -7, 0, 4, 5, 10];
function find(a, val) {
var n = a.length, i = 0;
while (i < n && a[i] != val) {
i = i + 1;
}
}
function report_result(a, val) {
var list = a.join(", ");
if (pos < a.length) {
alert(val + " is at position " + pos + " in " + list + ".");
} else {
alert(val + " is not in " + list + ".");
}
}
// Test code
report_result (word_list, "cat"); // found
report_result (word_list, "cow"); // not found
report_result (word_list, "rat"); // found
report_result (number_list, 0); // found
report_result (number_list, 10); // found
report_result (number_list, -11); // not found
</script>
</head>
<body>
</body>
</html>
The first thing you should notice about this file is that it is a lot shorter than the beancounter.html file from Part 1. Yay!
Drag the linear_search.html file from a file listing onto an open browser so you can see how it looks when it is working. It just produces a series of pop-up messages showing where test values were (or were not) found in the test arrays.
From the code, you'll see that it uses two so-called array variables, word_list, and number_list, to test its six-line find function (the code in the middle). You can see other array variables being used in an example in the Programming 2 slides. The object of this exercise is to change the code in the find function so instead of performing a linear search, it performs a binary search.
From the Algorithm module's slides, you will learn that for a binary search to work, the data it is searching through must already be sorted. Happily, the six strings in the word_list array and the six values in the number_list array are already sorted! (If they weren't, we could apply the exchange sort algorithm to them to get them sorted.)
Save the file under the new name, binary_search.html. Now to make a purely cosmetic change.
· Change the contents of the <title> tags from "Linear Search demo" to "Binary Search demo". (This changes what appears in your web browser's tab.)
Before we start messing with the actual code, I'll explain a very little bit about how the find function works. It does a linear search, using a variable called i (for "index") to keep track of which element of the array called a (just like in the pseudocode!) is being compared with the search value (called val) during a specific execution of the while loop. i has an initial value of 0, because array positions start at 0 in JavaScript, as mentioned in the slides. The while loop will exit for one of two reasons:
· the value of i is no longer less than the length of the array, in which case the linear search has not found value val in a, or
· value val has been matched to an element of array a, in which case the value of i is the position of value val in a.
So, what does that mean? It means that if variable i ends up with a value less than the length of the list being searched (a), the search value, val was, indeed found in the list. Otherwise (the value of i reached the length of the list being searched), the value val is not one of the elements of the list a and the search failed. The rest of the program learns of this by way of the statement
return i;
in the find function. return causes the function to end and for any value that follows the word "return" to be given back to whichever statement called the find function. In this test program, that happens to be the statement
var pos = find(a, val);
in the report_result function. (I chose the variable name pos because, as you may have suspected, it is short for "position", as in the position at which value val was found.)
Okay, this all means that if we're going to use the same test code when we create our binary search version of find, we need to make sure it returns either the position (or index) of the search value in the list/array being considered, or the length of the list if the search value isn't in the list.
Back to the code:
· Delete all the statements in the block of the find function but leave its opening and closing curly brackets in place.
function find(a, val) {
}
Everything else you must do for this lab will go on new lines between those curly brackets.
Now let's look back at that pseudocode. It starts off by creating a bunch of what look like variables, two of which (conveniently!) have the same names we've been using, a to represent the array or list containing the various sorted values, and val representing the value we want the function to search for. Now, the Programming 1 slides talk about information being conveyed to functions by way of arguments, which are the things that go inside the round brackets in a function call like
report_result (word_list, "cat");
Inside the function itself, the values of the arguments become the values of the corresponding parameters, which is what the a and val are in
function find(a, val) {
So that means, we already have our a and our val from the pseudocode and don't need to recreate them with variable declarations. We DO need to do that, however, for the other variable-like things in the pseudocode, namely n, low, high, and – when we get to it – mid.
Start with n. It's needs to be initialized (have its first value set) to the length of a. You can see from the original code that there are a couple of references to a.length. Length is a property of arrays in JavaScript, and a.length computes to the length of a. That means your line declaring n, the first line inside those curly brackets, should be
var n = a.length;
(and yes, I know, we already had a statement that contained that, and I told you to erase it. What can I say? Sometimes it pays to start over.)
All right, so that's how you declare a variable. Now,
· do the same for low and high, letting the pseudocode guide you as to what their initial values should be. Remember the var keyword, and the semicolons (;) statement terminators at the end of each line.
You should be ready to write your while loop. For guidance to the syntax, look at the while loop in the original code. It has a reasonably elaborate Boolean expression in its round brackets. Your replacement will be much simpler. Note that the "less than or equal to" operator you'll need is this: <=, a less than sign immediately followed by an equals sign. Remember the while loop's opening and closing curly brackets! All right,
· create the first and last lines of your while loop with its opening and closing curly brackets (which you'll fill in later). Remember to put your Boolean expression in round brackets.
Notice from the pseudocode that all the statements in it are indented at least one level. Make sure yours match! It just makes the code tidier and easier to understand.
Inside your while loop:
· Declare and initialize the mid variable. For this, you'll need to know how to do a floor operation in JavaScript. (If you're not sure what floor functions do, Google it!) It happens that JavaScript. has a library of mathematics functions called Math, and one of those functions is called floor! Here's how you'd get the floor you're looking for:
Math.floor((low + high) / 2)
(Note the round brackets around the low + high. They're important!) So, when you are declaring your mid variable, initialize it with the expression I've given you above.
Next, the pseudocode has an if compound (multi-line) statement. JavaScript. has one of those, too, of course, and its syntax can be seen in the report_result function in the original code. The pseudocode doesn't call for an else part as is used in report_result, so you can ignore that for now. Anyway, continuing inside the while loop:
· Create the first and last lines of the first if statement with its opening and closing curly brackets. Like while, if requires a Boolean expression that must be enclosed in round brackets. To compare two values for equality in JavaScript, you don't use an equals sign, you use two of them together like this:
==
To write
amid
in JavaScript, you'd use this array notation
a[mid]
resulting in the complete Boolean expression:
a[mid] == val
Now we go inside the curly brackets of the if, indenting the contents another level as indicated in the pseudocode.
· The two statement in the pseudocode,
report position of val as mid
stop
get replaced with just one: a return of mid. See the syntax of the return statement in the original linear search version of the find function.
Okay, that's the end of the first if statement, so move past its closing curly bracket and onto the second if statement. This one uses an otherwise clause in the pseudocode, and for that in JavaScript, you use else instead as you can see in the report_result function. So:
· Create your second if and an else (in place of the pseudocode's otherwise). If you've already declared a variable, don't use the var keyword with it again, just assign a new value to it as in
low = mid + 1;
Remember that the Boolean expression of the if (the else doesn't have or need one) needs to go in round brackets and your indenting should match the pseudocode. It's your choice if you write
} else {
or
}
else {
JavaScript. doesn't care (and neither do I! Some code styling is at the programmer's discretion).
Nearly there, folks! All that's missing is a return statement, after the closing while curly bracket but BEFORE the closing function curly bracket. This is the return that needs to indicate to the rest of the program that val does not occur in the array, so the value returned should be, if you recall, the length of the array, a. And somewhere back there a couple of pages is that information. So:
· Write the last statement of your find function. It returns the length of array a.
Save your work, then refresh your browser window to see if your program works. If it doesn't, you may have to close your browser window and open it again. Before you try running it a second time, check your code against the pseudocode first to see if you've missed anything. In my own attempt, I ended up with a find function that was 17 lines long, top to bottom. Depending how you write your else, you may end up with 18 lines instead, but it shouldn't be longer than that unless you've got some blank lines. The 15 marks Part 2 of this lab is worth corresponds to each of the 15 essential lines of code inside your find function's opening and closing curly brackets