CS 106 Winter 2018
Lab 01: Arrays and Strings
Summary
This lab will allow you to practice with manipulation of arrays and strings, and the relationship between the two.
To begin, download the starter code from the link above. Unzip it to obtain a folder titled L01. You'll build on the starter code in that folder, and create a couple of additional sketches that you can also put in there.
Question 1 Singles
In this question you will practice writing a few short functions that work with strings and arrays. You'll put your functions together into a single sketch, but the goal is not to make that sketch actually do anything—it will simply hold a few self-contained functions. Of course, you should test that your functions actually work. You can do that by creating a setup() function that calls your functions with a few different arguments and displays the results.
In the L01 folder, create a new, empty sketch called Singles. Inside that sketch, write the following functions:
Write a function repeat() that takes two values as input: a String and an integer that's at least 0. It returns a new String in which the provided string has been repeated the given number of times. So, for example, repeat( "cat", 5 ) would return "catcatcatcatcat". Repeating a string zero times should return the empty string "".
(Hint: you'll need a local variable to hold the value you're trying to create, and a for loop to build onto that variable with copies of the passed-in string.)
Write a function isIncreasing() that takes an array of integers as input and returns a boolean value. The function checks if the array of integers is strictly increasing: that is, if each number in the array is strictly larger than the one before it. For example, the array { -3, 4, 9 } is strictly increasing, but { 1, 4, 2 } and { 3, 5, 5, 6 } are not.
(Hint: the general idea is to use a for loop to walk over the array, comparing each element with the one immediately after it. But because we're comparing pairs of elements, you'll need to stop looping one step early. Still, you'll only need about 5–7 lines of code for the function body.)
Write a function countOccurrences() that takes two values as input: an array of Strings and a single search String in a separate parameter. The function returns the number of times that the search string occurs in the array. For example, if arr holds the array { "apple", "pear", "peach", "apple", "apple" }, then countOccurrences( arr, "apple" ) would return 3, and countOccurrences( arr, "durian" ) would return 0. Be careful with the spelling of the function name!
Write a function doubleOrNothing(). It takes an array of integers as input and returns a new array of integers, of the same length as the input. In the output, every positive number in the input array is doubled, and every negative number in the input array is replaced by zero. For example, if arr holds the array { 1, 2, -5, 8, -3, 12 }, then doubleOrNothing( arr ) would return the array { 2, 4, 0, 16, 0, 24 }.
Note that these are "pure functions". Everything described as an "input" above should be passed to the function as a parameter (not via a global variable, or an external file, or user interaction in the sketch window). Everything described as "returned" or "output" should be produced via a return statement in the function body (not displayed in the sketch window or written to the console using println()). (If you include a setup() function for testing purposes, that function can print outputs from test calls to the functions.)
If you want to practice solving self-contained problems like these, many more are available on the course web page in a set of practice programming exercises. These exercises are good practice for exams!
Question 2 Text Generation
In this question, you will generate random text that resembles a source text. The technique is similar to the one used to "write" the computer-generated chapter The Handsome One from the hypothetical novel Harry Potter and the Portrait of what Looked Like a Large Pile of Ash. This is primarily an exercise in installing a library and using a couple of functions in it: most of the work is done for you.
Open the provided sketch GenerateText in the L01 folder. You will see a very simple setup() function that prints out every string in an array of strings. The array itself is kept in the separate tab called Text (it's a bit long, so it's nice to keep it out of the way). The array contains the individual lines from a well-known poem.
To complete the exercise, follow these steps. They're all fairly fast, but are explained in minute detail here.
- Delete the for loop in setup(), or comment it out. It was there only for demonstration purposes.
- Download and install the "RiTa" library. In Processing's menu, select "Sketch → Import Library... → Add Library...". You'll get a new window with a list of libraries supported by Processing. Type "Rita" into the "Filter" text box at the top of the window to show the RiTa library. Select it and click the "Install" button at the bottom of the window to install it in your copy of Processing.
- Tell the GenerateText sketch to use this library. Add the line import rita.*; to the top of the sketch, above the setup() function.
- In setup(), add a new line of code that declares a local variable of type String. In the same line, initialize the variable to hold all the lines of the array lines, condensed down into a single String. To do this, use the function join(), which is built in to Processing. Find the documentation for join() in Processing's online reference page; use a string containing a single space, " ", as the extra text to place between strings in the array.
- Below that, add a second local variable declaration, this time of an instance of the class RiMarkov. This new class is provided by RiTa, and made available by the import statement in Step 3. The declaration should initialize the variable to a new instance of RiMarkov, with an "n-factor" of 2 passed in as the argument to its constructor.
- In a third line of code, feed the string created in Step 4 into the generator created in Step 5. You'll want to call the loadText() method on the RiMarkov variable you created above, passing it the text as an argument. Remember that this must use the syntax of a method call, which requires an instance of a class, followed by a period, followed by the name of the method.
- In a fourth line of code, use the generateSentences() method of RiMarkov to ask RiTa to generate five sentences based on your source text (by passing the number 5 to the method). Place that method call inside a call to println, to take the returned text and immediately write it to Processing's console so that you can see it.
If all goes well, you'll end up with a setup() function containing four lines of code, which prints a random re-interpretation of the source text to the console window.
You're welcome to change the source text to any other piece of text you like, as long as it's long enough to generate interesting output (be sure to test it). You can also experiment with generating different numbers of sentences and using different n-factors. A higher n-factor produces more believable text, but the text will repeat larger sections of the source word-for-word.
Question 3 String Art
Despite the theme of L01, in this question the "strings" are modelling actual physical pieces of string, not fragments of text. You'll create a drawing from lines arranged in a similar configuration as the design pictured above.
- Open the sketch StringArt in the L01 folder. Go ahead and run it. You'll see that it draws a set of points arranged in a square. Take a moment to study the code to figure out how the points are represented. They're stored in two arrays: one holds the x coordinates, and the other holds the y coordinates. Both arrays are created and initialized in the helper function initPoints(), which is called in setup().
- Before setup(), declare an integer global variable called skip. Initialize it to have some integer value between 20 and 40.
In draw(), add code to draw lines like the ones in the string art design above. Specifically, draw a line connecting every point stored in the two arrays to the point that's skip steps further along in the arrays. That is, draw a line from point 0 to point skip, from point 1 to point skip+1, from point 2 to point skip+2, and so on.
It's clear that you'll need some kind of for loop here. The problem is that we want to treat the arrays as "circular", so that array references can "wrap around" the end of the array and start at the beginning again. For example, if we're connecting point 75 to point 98 and point 76 to point 99, we would continue by connecting 77 to 0, 78 to 1, and so on. The elegant solution is to use the % operator to compute array indices modulo the length of the arrays; that way, any array indices you generate that are larger than 100 will automatically have 100 subtracted from them.
This step should require you to add a total of about 6–8 lines of code to draw().
- Optional: There are lots of ways to experiment with this sketch. try changing some of the global variables to generate squares with more or fewer points, or different skip amounts. Vary the colours of the lines, or superimpose multiple patterns with different colours and skip values. Include interactive controls to vary the skip amount, either using keys to add or subtract 1, or using the mouse position to set it every frame. Try to change the layout of the points to something other than a square. We'll accept just about any variation on string art, as long as the loop in the previous step is present in your code.
Submission
When you are ready to submit, please follow these steps.
Please ensure that any sketches you submit compile and run. It's better to submit a sketch that runs smoothly but implements fewer required features than one that has broken code for all features. If you get partway into a feature but can't make it work, comment it out so that the sketch works correctly without it.
If necessary, review the Code Style Guide and use Processing's built-in auto format tool. You do not need to use the precise coding style outlined in the guide, but whatever style you use, your code must be clear, concise, consistent, and commented.
If necessary, review the How To Submit document for a reminder on how to submit to LEARN.
Make sure to include a comment at the top of all source files containing your name and student ID number.
Create a zip file called L01.zip containing the entire L01 folder and all its subfolders.
Upload L01.zip to LEARN. Remember that you can (and should!) submit as many times as you like. That way, if there's a catastrophe, you and the course staff will still have access to a recent version of your code.
If LEARN isn't working, and only if LEARN isn't working, please email your ZIP file to the course account (see the course home page for the address). In this case, you must mail your ZIP file before the deadline. Please use this only for emergencies, not "just in case". Submissions received after the deadline may receive feedback, but their marks will not count.