In this lab you will gain more experience in manipulating different data types in C, you will revisit the modulus operator (that you have learned in previous CS courses), and you’ll perform a series of bit manipulations. You’ll write a main program that prompts the user for inputs, and which then invokes the functions that you’ll write. I. Modulus by Brute Force to Convert to a Different Base The Objectives of this part of the lab are the following: • Become comfortable with using a char pointer • Perform modular arithmetic • Continue to develop skills at writing C functions As was the case for lab 1, ask the TAs lots of questions. They are there to help. And, you CAN work with peers in completing the labs. This is a bit tricky when everybody is remote; you may use slack, email, discord, etc. Up to you. But, in no circumstances should you SHARE code, which involves emailing code and then submitting it as your own. Submitting your work Submit your C program files as the Lab 2 Submission item on Canvas. You must submit your program by the due date/time specified on Canvas. Create a C source file, compile it, and link it to get an executable Use the nano editor (or any editor of you choice, such as emacs) to create a file called lab2Convert.c, type the following contents and save the file. #include int main() {} Compile this file into an executable by issuing the following from the command line, and then run: $ gcc –o lab2Convert lab2Convert.c $ ./lab2Convert This is a skeleton of a program, so it doesn’t do anything (yet).Implement a Conversion Function Implement a function with the following signature: char* itoa(int num, char* str, int base); where num is an integer that you need to represent as a string in the base specified. The input can be a negative number. In principle, this is VERY similar to the task for homework 1, but here you are tasked to write the function for converting to ANY base, and not just binary nor hexadecimal. For example, assuming char buffer[50]; has been declared, Invocation Output to screen printf(“%s”,itoa(4, buffer, 2)); 100 printf(“%s”,itoa(64, buffer, 8)); 100 printf(“%s”,itoa(72, buffer, 8)); 110 printf(“%s”,itoa(675, buffer, 16)); 2A3 printf(“%s”,itoa(456, buffer, 12)); 320 Hint: To specify the alphabet of a base greater than 10, use the ASCII values of letters starting with A, then B, the C, the D, etc. A typical approach is the following: 1. Get the least significant digit by finding the modulus of the number and the base 2. Depending on the base, represent this digit in ASCII by either adding it to the ASCII ‘a’ or the ASCII ‘0’ and store it in a string 3. Divide the number by the base and repeat steps 1-3 until the number is reduced to zero 4. Reverse the string (the char* str), and display using your method of choice.II. Bit manipulation The Objectives of this part of the lab are the following: • Continue to develop your understanding of binary representation of integers Implement a function with the following signature: int countSetBits(unsigned int var); This function should return the number of set bits (1s) in argument. That means, you must convert the input unsigned int into its binary equivalent, and then count the number of bits. Note: This is in principle the same as the bitCount function of project 1, but here you ARE allowed to use any operator that you want. Also, this function’s input is an unsigned int, which is a bit different than the bitCount function in project 1. Implement a function with the following signature: int reverseBits(int var); This function should return an integer that has all the bits (including the sign bit) of the argument reversed. These functions that perform bit manipulations are meant to force you to THINK about and MANIPULATE the bit representations of different data types. For example, there are many learning points for this task. First you would need to recall that ints in C are 4 bytes and are SIGNED. Thus, invoking reverseBits(1) where the 1 is of type int, the 1 would be saved as 00000 … 00001 Reversing all of those gives 10000 … 00000 Which when assigned to an integer (because that is what the function returns), that integer would have the value -1(231) + 0 + 0 + …. + 0 Thus printing the value of the output of reverseBits should print -2147483648 to the screen.Implement a function with the following signature: bool onlyOneBitSet(int aVar); This function should return true if only one bit is set in the argument passed in, and should return false otherwise. III. The main() Write a main method that • Prompts the user to provide two integers • Invokes itoa using the two inputs • Invokes countSetBits, reverseBits, and onlyOneBitSet, using the first input integer • Prints to the screen the output (char*, int, int, bool) of the 4 functions. Rubric and submission Please upload your .c file to Canvas. itoa correctly implemented 3 points countSetBits correctly implemented 3 points reverseBits correctly implemented 3 points onlyOneBitSet correctly implemented 3 points lab2Convert.c uploaded via Canvas • Program Compiles • Main method prompts for user’s input • The 4 functions are invoked • Output is nicely formatted 3 points 15 points
In this homework assignment you will interface with a cellular automation simulator. The rules are very simple. The board is a grid. Each grid square can hold at most one cell. For a cell to survive from generation to the next, it needs two or three neighbors. Too many neighbors cause the cell to starve. Too few neighbors causes an incurable case of ennui. All is not lost. If a grid square has exactly three neighbors, a new cell is born, which is kind of strange when you think about it. In this simulation, a grid square that includes a cell is marked as 1, and 0 otherwise. For example 0 0 0 1 0 1 0 1 0 0 0 1 1 0 1 1 would represent a 16 square grid, with 7 cells, where the underlined cell has no neighbors. There are many variations on this game, which is Conway’s Game of Life and is a B3/S23 game. That is, cells survive with two or three neighbors and are born with exactly 3 neighbors. This game is can be extended into the real domain or more dimensions. However, we will stick with the original B3/S23. You are being given a very naive evolution implementation called evolve. It works, but it is slow. See how fast you can make it run (we’ve discussed optimization techniques). Outcomes: Understand and apply the loop and other optimizations we discussed, including: • Remove loop inefficiencies and reduce procedure calls • Reduce unnecessary memory references and loop unrolling You CAN work in groups of 2 in completing this assignment. In that case, only a single person uploads .c files to Canvas, and the names of both people should be in the header of each file. The instructions in this document are meant to be executed on the lab machines (you need to ssh in). If you want to work on your personal machine, see section Working on your personal computer. Details The experimental set-up is implemented in a library called liblife.a. Since it has solutions (different types of evolve), it is a binary, which is saved to /home/jagodzf/lib. A provided Makefile and life.c are available at the following, which you should retrieve.There are multiple ways to run the simulation/test program. • Silent mode. The program runs the test cases against the provided evolve methods for 500 generations. It then reports the average performance of each method. The performance value is an equation that considers memory moves, efficiency, memory accesses, etc. A low value performance measure specifies that fewer resources were needed to run the program. Hence, a lower performance value is preferred. This is the default mode. • Full GUI mode. The simulator will attempt to open a new WINDOW showing the simulation running. If you are connecting via SSH to the CS computers, you must export your view. This is invoked via -fg. • Lazy GUI mode. This is a command-line version of the GUI, that does not open a new WINDOW (hence is suitable for invoking via SSH). This will print the top-left 10 x 10 cells of the 1024 x 1024 grid for each generation. Invoke via -lg. For example, compiling and invoking via the simple GUI mode: $ make $ ./life -lg All invocations will print the generation number, as well as the final stats for each implementation of the evolve method. Working on your personal computer Although you can download the lib (and header file at /home/jagodzf/include/), note that the Makefile references lib and include in the jagodzf directory, so if you want to build the executable on your personal computer, you’ll need to modify Makefile to direct it to the local locations of lib and include. Your task • Improve the performance of the simulation by modifying the evolve method. Do this by implementing various optimization techniques. Refer to the lecture slides. • You can modify any code in life.c, but make sure your edits don’t break the simulation run. • Please name your implementation the same as your CS username. In other words, replace “Simple” with your userID, so that when the program runs, it might print the following: jagodzf: 5.61 jobss: 27.22 gatesb: 16.44 turinga: 10.68 lovelaa: 7.37Hints and suggestions • You are free to add as many test methods as you want, and you are encouraged to do this. Copy the code, give it a new name, and add the new evolve method to the test harness (e.g, add_method). This will let you see if you are making improvements. Grading Your implementation will be evaluated against Simple, jobs, gatesb, turinga, and lovelaa. It will be tested using the silent (default) mode. Rubric and Submission Upload your life.c file to Canvas. If for some reason you also develop other (custom) .c and .h files, upload them as well. Correctness Points Beating Simple (the provided solution) 7 Beating jobss 6 Beating gatesb 5 Beating turinga 1 Beating lovelaa 1 Coding style, including informative comments, well structured code, meaningful function and variable names, and helper functions when necessary 3 Total 22 points
You will use your newly acquired gdb skills to reverse engineer three C programs, which have been compiled without the -d flag (hence the executables do not contain debugging information allowing you to inspect each line of the equivalent plain-text program). However, you can disassemble the programs. Outcomes • Gain more experience in the use of gdb • Become more familiar with assembly, including the use of control routines You CAN work in groups of 2 in completing this assignment. In that case, only a single person uploads .c files to Canvas, and the names of both people should be in the header of each file. Retrieve the three executables hw2_prog1, hw2_prog2, and hw2_prog3 from the following directory: /home/jagodzf/public_html/teaching/csci247/homeworks/hw2-assembly Your task • Use gdb to set breakpoints for each of the three executables; each program has a main method • Disassemble each program • Compose three program files, hw2_prog1.c, hw2_prog2.c, and hw2_prog3.c which are the source code equivalents for the executables Hints and suggestions • Look up the opcodes (online) that you encounter in the disassembled programs • Refer to the GDB tutorial pdf that is available for lab 3; consider using gdb’s layout asm Rubric and Submission Upload your hw2_prog1.c, hw2_prog2.c, and hw2_prog3.c file to Canvas. Correctness Points • hw2_prog1.c correctly reverse engineers hw2_prog1 • hw2_prog2.c correctly reverse engineers hw2_prog2 • hw2_prog3.c correctly reverse engineers hw2_prog3 10 15 20 Total 45 points And, adhere to correct formatting. This is the quality component of code. You will be deducted points if your code is not of high quality.
Unless you are thinking in base-2 or base-16, converting between decimal, hexadecimal, and binary integer representations is extremely valuable when reasoning and discussing how data is stored by a computer. The conversion is algorithmic, but it is tedious. Is there a way we could automate the conversion of a decimal integer to its hex or binary equivalent? For this assignment, you will write a C program, convert, that reads decimal integers from standard input (a.k.a., the keyboard) and prints the representation of each value in either hex or binary. The program will continue to read values until reaching the end-of-file signal. What is the end-of-file for the keyboard? Control-D. We use control characters so often, “control” is usually written with a carrot. For example, ^D. The program convert must take a single command-line argument that is either “-x” or “-b”, where “-x” indicates that the program should print the input value in hexadecimal, and “-b” indicates that it should print binary. Outcomes • Gain more experience with C programming, the C library, compiling C programs, etc. • Properly use some of the C bit-wise operators • Produce well formatted code. Example invocations $./convert -x 1234 0x4d2 879 0x36F ^D $./convert -b 1234 100 1101 0010 4321 1 0000 1110 0001 ^D $./convert Usage: ./convert [-x|-b] The dollar sign, $, is a generic shell prompt. Your prompt will probably be different. Carrot-D (^D) is shorthand for control-D.Implementation Details Name the source file convert.c. Create the file with your favorite text editor (nano was mentioned in lab 1, but there are many others). If you develop your code on your personal computer, make sure you’re your code compiles correctly on the CS linux machines. You program much check to make sure the correct flag (-x or -b) was issued during invocation. To get started, here is a skeleton of a program: #include /* Main * argc, argv Command line arguments. * return zero for success, non-zero for failure * * This is the main entry point for the program. */ int main(int argc, char* argv[]) { printf(“%s says, ”Hello, World!” ”, argv[0]); return 0; } This program doesn’t convert anything, but it is a starting point. To verify that it works, compile it and run it (just like you’ve been shown in lab 1): $ gcc -o convert convert.c $./convert ./convert says, “Hello, World!” Remember to use the on-line manual: man. For example, C-strings or char*s are really weird. The normal comparison operators do not do what you expect, so you have to use the strcmp function. How is it used? Hint: You may want to read the following man-pages: scanf, printf, strstr, and strcmp. You are not allowed to use printf’s %x format character. In other words, you must do the conversion manually. Coding Style Coding style is almost as important (some say more so) than correct code logic. Code should be easy to read, both for your sake when you return to a code file after a long absence, and for the benefit of others because in the real world (post graduation, industry), multiple people work on and share the same code base, so everything should be tidy, well organized, and clean.For this and all future labs, homework assignments, and projects, please adhere to the following guidelines. 1) Use meaningful names that give the reader a clue as to the purpose of the thing being named. 2) Avoid the repeated use of numeric constants. For any numeric constants used in your program, define a static constant: static const float PI = 3.141592653589793; From then on, use the symbol in place of the value. There is a C convention to use ALL CAPS for constants. 3) Use comments at the start of the program to identify the purpose of the program and include your name. If you are working in groups, BOTH names must be included, but there is only a single submission. For example: /* * Name: Marie Curie * Description: This program converts decimal to either * binary or hexadecimal… */ 4) Use comments at the start of each function to describe the purpose of the function, the purpose of each parameter to the function, and the return value from the function. /* Read Decimal * This reads and returns a single, decimal integer from stdin. * NOTE: Most of the parsing work is performed by scanf. */ int read_decimal() 5) Avoid in-line comments in the code itself. 6) Use comments at the start of each section of the program to explain what that part of the program does. 7) Use consistent indentation. 8) Write functions (methods). Do not compose a .c file with just a main function, with all the code inside of the main function. These are general guidelines to help you produce superior code. However, as an up-and-coming software professional, it is your job to know when to deviate from these rules to produce code that is as easy to read and understand as possible.Rubric and Submission Upload your convert.c file to Canvas. Correctness Points • Checks for proper invocation • Correctly converts to and prints binary value • Correctly converts to and prints hexadecimal value • Correctly prints values without using printf’s %x format character 5 5 5 5 Total 20 points Be sure to test your program thoroughly. Partial credit is given And, adhere to correct formatting. This is the quality component of code. You will be deducted points if your code is not of high quality. Quality • Programming style (organization, indenting, comments, symbol names, etc.) • Organization (Intro to file includes comments, meaningful grouping, etc.) • Use of multiple functions
Task 1 – Specializing the `File` classOk spiel aside, open your IDE. We’ll do some coding.#### Provided Additions to `File`You’ll notice that `File` has a couple new things.##### `updateLastModified()` function & `std::shared_ptr system_clock_` member**TLDR: Calling this function updates the last-modified-timestamp to the current time. That’s all you NEED to know (you shouldn’t interact with this `system_clock_` member at all)**If you’re curious: `std::shared_ptr` is a “shared pointer” to a Clock instance. Shared pointers are just automatically managed pointers (an alternative to the “raw” pointers you guys have worked with until now, eg. `int* my_int_ptr`), and their memory is automatically deallocated when the last shared pointer to the object is destroyed.Why this change? Because testing via dependency injection. [Here’s a link with an insanely good explanation of dependency injection.](https://www.jamesshore.com/v2/blog/2006/dependency-injection-demystified) (3 minute read)Read More:1. [Geeks for Geeks – Smart Pointers](https://www.geeksforgeeks.org/cpp/smart-pointers-cpp/) 2. [Stack Overflow – When to use smart pointers](https://stackoverflow.com/a/30143936)#### Part A – Typing up a `TextFile`This ones simple. Create the `TextFile` class (ie. `TextFile.hpp` & `TextFile.cpp`). Then, make it extend the `File` class.Add the following member:“`c++ content_ // A string representing the actual text stored within the file “`Then, implement the following parameterized constructor.“`c++ /** * Constructs a new TextFile object. * * @pre For simplicity, we assume that the filename extension is that of a text file — you need not validate it. * * @param filename A const reference to a string representing the filename of the text file. * @param content A const reference to a string representing the initial file contents (defaults to an empty string if omitted). * @param readable A boolean indicating whether the file is readable (defaults to true if omitted). * @param writable A boolean indicating whether the file is writable (defaults to true if omitted). * * @post * 1. The filename and permissions are initialized via the base File constructor. * 2. The file contents are set to the provided string, or remain empty if none is provided. * * @note You should be initializing the base class explicitly (refer to lecture) */ TextFile “`And then the following getters/setters for the new member:“`c++ /** * Retrieves the current contents of the text file. * @return A string containing the text file’s contents. */ TextFile::getContent/** * Updates the content of the text file. * * @param newContent A const reference to a string representing the new file contents. * @post * 1. The content_ member variable is updated to match the provided string. * 2. The last_modified_timestamp_ of the underlying File is updated to the current time * specified by Clock::now. * * @note Hint: You will need to modify `File` (ie. the base class) to allow you to actually update the last modified timestamp. */ TextFile::setContent “`For _your own_ testing purposes, you can (optionally) implement:“`c++ /** * Generates a formatted string representation of the text file. * * @return A string containing the file’s name, permissions, last modified timestamp, * and contents, or “(none)” if the contents are empty. */ TextFile::toString “`#### Part B – Pixels & `ImageFile`Ok so now that we have text files we’ll also want to make a separate class for images.But first, we’ll make a pixel class.##### Introducing `Pixel` – Seeing Your First StructStructs are classes, except all members are public by default instead of private. Use these when you just want to transfer data in a more readable / constructed way. After all `pixel.red` is much better than `pixel[0]`.We’ve defined the Pixel struct with the following members:“`c++ red // An integer specifying the red channel of the pixel (defaults to 0) green // An integer specifying the red channel of the pixel (defaults to 0) blue // An integer specifying the red channel of the pixel (defaults to 0) “`**These names must match exactly since we’ll be testing the values of your Pixels — so if we call `p.red` we better have a member named `red`.**You can initialize a Pixel easily using [structured initialization](https://stackoverflow.com/questions/11516657/c-structure-initialization):For example, if I want a red Pixel, I can just say `Pixel red_pixel = { 255, 0, 0 }`.Order matters — the order in which you’ve given the parameters must be the order they are defined in the struct as.**Don’t modify anything within the provided `Pixel` struct — those changes will be disregarded when you submit.**##### Implementing `ImageFile`You know the routine by now:Private members:“`c++ /** * A 2D vector of Pixel structs * The pixel data is stored in a 2D vector, where pixels_[row][col] corresponds to * the pixel at the given row and column of the image. * * pixels_[0][0] should be the top-left of the image * pixels_[YOUR_IMAGE_HEIGHT – 1][YOUR_IMAGE_WIDTH – 1] should be the bottom-right of the image */ pixels_ “`Parameterized Constructor:“`c++ /** * Constructs a new ImageFile object. * * The pixel data is stored in a 2D vector, where pixels[row][col] corresponds to * the pixel at the given row and column of the image. * * @pre Assume that the image ends with a valid image extension (i.e. you do not need to validate it). * * @param filename A const reference to a string representing the filename of the image. * @param pixels A const reference to a 2D vector of Pixel objects representing the image’s pixel data. * Defaults to a grid of 20(width) x 10(height) pixels initialized to black (0,0,0). * @param readable A boolean indicating whether the file is readable (defaults to true if omitted). * @param writable A boolean indicating whether the file is writable (defaults to true if omitted). * * @post * 1. The filename and permissions are initialized via the base File constructor. * 2. The pixel buffer is set to the provided vector, or initialized to the default size with all black pixels if… * – The parameter is omitted (ie. as a default value). * – Or the pixel array’s rows are not all the same length. * * @note It IS allowed to set pixels to an empty 2D vector! */ ImageFile “`By the way, here’s a rough example of how you would provide a default `std::vector` parameter:“`c++ // This is a 1D array — you’ll need to adapt this so it’s 2D void myFunction(std::vector someVector = std::vector(2, ‘a’)); // Vector of 2 integers, each initialized to the letter ‘a’ “`Of course, our typical getters and setters:“`c++ /** * Updates the pixel buffer of the image if given a valid pixel array; otherwise, returns false. * * @param pixels A const reference to a 2D vector of Pixel objects representing the new image data. * @returns True if the operation was successful, false otherwise. * @post * 1. If the new pixel array’s rows are not all the same length, NO member is updated and false is returned. * 2. Otherwise, the pixels_ member variable is updated to match the provided 2D vector. * and the last_modified_timestamp_ of the underlying File is updated to the current time * specified by the Clock class * * @note It IS allowed to set pixels to an empty 2D vector! */ ImageFile::setPixels/** * Retrieves the current pixel buffer of the image. * * @return A 2D vector of Pixel objects, where pixels[row][col] corresponds to the pixel at * the specified row and column. */ ImageFile::getPixels “`But we’ll also have some metadata related getters. You can achieve this in multiple ways:1. Introduce your own member variables 2. Derive them from the 2D `pixels_` memberYour call! Just make sure that whichever way you choose, these methods do what they’re supposed to.“`c++ /** * Retrieves the height (number of rows) of the image. * @return An integer representing the total number of rows in the pixel buffer. */ getHeight/** * Retrieves the width (number of columns) of the image. * @return An integer representing the total number of columns in the pixel buffer. */ getWidth “`Because I know this isn’t the most trivial, I’ll give you the `ImageFile::toString()` implementation to help you test (you’re welcome):“`c++/** * Generates a string representation of the image file. * * @return A string containing the file’s name, permissions, last modified timestamp, * and image dimensions (width x height). */ std::string ImageFile::toString() const { std::stringstream ss; // Call the base class toString() ss
File `operator
Introduction In this lab, you’ll write a program to read historical earthquake data from a file and plot each earthquake on a map using turtle graphics. An example output is shown in Figure 1. Figure 1: The output from my solution code. 1 Setup Create a lab8 directory in your lab environment of choice. Download the following files from the course webpage and place them in your lab8 folder: • plot earthquakes.py – this file contains skeleton code and pseudocode • earthquakes.csv – this file contains the data you’ll be reading • earth.png – this will be set as the background image in the turtle graphics canvas (this is done for you by the turtle setup function given in the skeleton code). 1 2 Approach and Guidelines Implement the parse row function and the remainder of the main function according to the pseudocode included in comments. Follow the same coding style conventions we’ve been using up to this point: comment at the top, good variable naming, and so on. You’ll find that you need many of the structures and concepts we’ve covered in this course to complete this task—ask your TA if you encounter any problems, and use this opportunity to take note of any topics you need to brush up on before the final exam. Some hints: • The code to read the csv file will look pretty similar to the code I provided in A5 to read the cancer data files. • The first line of the file contains column headers, so you’ll need to skip over it before starting to read data. • Plotting earthquakes on the map is quite simple: the map image (and turtle canvas) is 720×360 pixels, with (0,0) in the center. Longitude (the x axis) goes from -180 to 180 and latitude (y axis) goes from -90 to 90, so (0,0) is in the center. To get the canvas (x, y) coordinates based on a given (lon, lat) coordinate, simply multiply each coordinate by 2. • The skeleton includes an implementation of the teleport function from Lab 5. • You can use a turtle object’s circle method to draw a circle. See the documentation for details on how it is called. • Coloring the circles is optional. In my color scheme, the red channel is proportional to magnitude, while the green and blue channels are inversely proportional to magnitude. For an extra challenge, try coloring the circles based on the date instead of the magnitude. Submission Take a screenshot of your program’s output and save it as earthquakes.png. Zip your screenshot and completed plot earthquakes.py file in a file called lab8.zip and submit to Canvas. 2 Rubric You submitted a single zip file called lab8.zip, containing the correct files 2 The top of your program has comments including your name, date, and a short description of the program’s purpose. 3 The program reads the earthquake data into a list of dictionaries 15 A circle is drawn for each earthquake 5 The circle’s size varies with the earthquake’s magnitude 5 Total 30 points
Task 1: Creating `FileUtils`Boot up your IDE of choice, we’re coding now. We’ll start by making some utility functions to make your life easier later.**In this task you’ll be modifying the following provided files:**1. `FileUtils.hpp` 2. `FileUtils.cpp`Since this is just for utility, we don’t need a class. However, we do want to keep things organized. That’s why we’ll define all such functions in the `FileUtils` namespace (instead of just leaving them out and about).**Important**: That means that whenever calling these functions, you must use the `FileUtils::` namespace (e.g. `FileUtils::myFunction()`), instead of just `myFunction()`.### Part A: Implementing `findFileExtension`All you need to do is use the spec to write the function header in the `.hpp` file and then implement it in the `.cpp`. See below on the behavior.**Remember the function name must match entirely, case and all.**“`c++ /** * Extracts the file extension from a given filename. * * We define the file extension as the string containing: * 1. The last period within the filename * 2. All characters after that period * * @pre Assume the given filename has no spaces * @param filename A const reference to a string representing the filename from which to find the extension. * @return A string containing the extracted file extension or an empty string if: * 1. No extension is found * 2. The filename is empty. */ FileUtils::findFileExtension “`Once you’re done, write a `main` file to test your code! Remember you should call this function by saying `FileUtils::findFileExtension(“whatever_your_test_case_is”)`.### Part B: Implementing `hasWhitespaces`Same thing here. Add the function signature to the `.hpp` and implement it within the `.cpp`.You will find the link I’ve attached with `@see` to be VERY helpful. Just make sure to include the correct library in your `FileUtils.hpp` file.“`c++ /** * Checks if a given filename contains any whitespace characters. * * A whitespace character is any character matching the STL documentation in the link below. * * @param filename A const reference to a string representing the filename to check for spaces. * @return true if the filename contains one or more whitespace characters, false otherwise. * @see https://en.cppreference.com/w/cpp/string/byte/isspace.html */ FileUtils::hasWhitespaces “`## Task 2: Creating the `File` classOk so we have these utilities. Now we gotta use them.Before we get into this, I’m just going to put these here for you, because I’m nice (you’re welcome):1. [Default Parameters](https://www.geeksforgeeks.org/cpp/default-arguments-c/) 2. [Default & Parameterized Constructors](https://www.geeksforgeeks.org/cpp/constructors-c/) 3. [The Best Way to Make a Constructor (initializer lists)](https://www.geeksforgeeks.org/cpp/when-do-we-use-initializer-list-in-c/) 4. [Const Functions](https://www.geeksforgeeks.org/cpp/const-member-functions-c/)### Part A: Setting Up the Class#### Basic Private MembersOk since you’re experts on making classes by now (or idk maybe you’re rusty — that’s fine, I was on summer break too, just reference the links above), setup the `File` class with the following private members.“`c++ filename_ // A string containing the filename of the File object readable_ // A boolean containing the `read` permission of the File writeable_ // A boolean containing the `write` permission of the File “`#### Constructors##### Default ConstructorThis ones super simple:“`c++ /** * Constructs a new File object. * * @post * Sets the File’s filename_ to “New_Text_Document.txt” * Sets all boolean members to true. */ “`##### Parameterized ConstructorThis one’s a little more involved, but just make sure to use the utility functions we made before. It should be pretty short — just make sure to test!“`c++ /** * Constructs a new File object. * * @param filename A const reference to a string for the initial filename * @param isReadable A const reference to a boolean for the readable permission * @param isWritable A const reference to a boolean for the writable permission * * @post * All booleans should have a default value of true (ie. use true if they are omitted). * * Sets the File’s filename_ such that: * 1. If the parameter contains spaces or has no characters at all, the default filename is used * 2. If the parameter has no extension (no `period` characters whatsoever), .txt is appended to the filename & used * 3. If the parameter has an empty extension (a `period` characters followed by no characters), txt is appended to the filename & used * 4. Otherwise, the parameter filename is used as is * Note: A filename like `.env` or `.log` IS allowed (ie. filenames containing only the extension)! */ “`### Part B: Getters & Setters for Trivial Data TypesNow that we have private members, you’ll need to get and set them.**Remember:**1. Getters _don’t_ modify the object, so we declare the function const (see the links above if you don’t know what I’m talking about). 2. If a function doesn’t have a return it returns `void`.#### `readable_` & `writable_` Getters & SettersWe’ll start simple. Just make two basic getters & setters for `readable_` and `writable_`. Nothing fancy.“`c++ /** * Retrieves the current readable permission as a boolean. * @return The value stored in `readable_` */ isReadable/** * Sets the readable permission of the File object. * * @param new_permission A const reference to a boolean for the new readable permission * @post * 1. The readble member is set to the value of the parameter * 2. (more to come in a later task) */ setReadable/** * Retrieves the current writable permission as a boolean. * @return The value stored in `writable_` */ isWritable/** * Sets the writable permission of the File object. * * @param new_permission A const reference to a boolean for the new writable permission * @post * 1. The writable member is set to the value of the parameter * 2. (more to come in a later task) */ setWritable “`#### Getting & Setting the FilenameNow we’ll move onto something a little more difficult:“`c++ /** * Retrieves the current filename as a string. */ getFilename/** * Attempts to set a new filename for the File object. * The operation FAILS if: * 1. The passed filename is empty or contains spaces * 2. The extension of the old and new filenames are not equal. * Note: Do not append a default extension to the parameter! * * @param filename A const reference to a string for the new filename. * @return true if the filename was successfully updated, false otherwise. * @post * 1. If possible, the filename variable is set to that of the parameter * 2. If the filename was modified, the last modified attribute is updated to the current system time */ setFilename “`#### Helping You Test (Optional)At this point you _should_ be testing your code.We’re not checking that you have this — but hey you never know what might be on a test. You might find it useful to write a `toString()` method for File.You could totally use string concatenation, but using [string streams](https://www.geeksforgeeks.org/cpp/stringstream-c-applications/) is cleaner.“`c++ std::string File::toString() const { std::stringstream ss; ss
In this lab, you’ll write a program that calculates the total square footage in a home. Imagine you are working for a construction company that builds homes with only square or rectangular rooms. The houses vary in size, with as little as 1 room and up to 100s. Your task is to write a program that will prompt the user to input the number of rooms and their dimensions, and which then calculates the total square footage of the home. Two invocations of such a program are shown below. Figure 1: Two sample invocations The figure on the left is the program running where a user specifies a house with 3 rooms – a square room and two rectangle rooms. The image on the right is the calculation for a house with 4 rooms – three square rooms and a rectangular room. You’ll create such a program from scratch. You’ll be asked to follow good coding conventions – if you find yourself typing similar code over and over again, create a function for performing that repeated task (as was shown in lecture). Look at the above program invocations, and notice the following: • To calculate the size of a square room, you need only the dimension of one of the walls • To calculate the size of a rectangular room, you need both dimensions, the width and length • There are repeated print statements that are very similar, but not identical. However, they all begin with “What is the”, and end with a question mark. From these observations, your supervisor (boss) has decided that your program can have ONLY 3 functions: 1. room_square_feet, which takes a single argument to designate whether the room is a square or rectangular room. If the room is a square room, the function room_square_feet 1 invokes the prompt_user function once to retrieve the single dimension needed to calculate the size of the room. If the room is a rectangular room, the function room_square_feet invokes the prompt_user function twice to retrieve the two dimensions needed to calculate the room’s size. The function room_square_feet returns the square footage of a room. 2. main, which prompts the user for the count of rooms and calls room_square_feet for each room, using the accumulator pattern (refer to Section 6.4 of the textbook) to keep a running total of the square footage of the house. 3. prompt_user, which receives two arguments and returns one value. The first parameter, of type str, is the text of the question that the user is prompted. In the examples above, “length of the room” and “width of the room” and “shape of room 1, square or rectangle” would be the three Strings that are provided as input on three separate occasions to the function prompt_user. The second argument designates the return type of the function. Hint: use type conversion function(s) to convert the user’s input into the appropriate type of data to be returned. A diagram showing two example usages of the prompt_user function for two sample inputs is included below. prompt_user “number of rooms” “integer” Prompt user : What is the number of rooms? User inputs : “4” inputs outputs 4 (type int) prompt_user “shape of room 2” “string” Prompt user : What is the shape of room 2? User inputs : “rectangle” inputs outputs “rectangle” (type str) 1 Setup Create a lab6 folder and in it create a Python file called squarefootage.py. 2 Example Program Flow The steps below illustrate an example of the program’s behavior when prompting for the information and calculating the square footage of a single room. Recall that your main program will do this once for each room in the house. Notice that main uses prompt_user twice, then calls room_square_feet, which itself calls prompt_user once or twice depending on the shape of the room. 2 Step 1: prompt_user is invoked with first and second arguments “shape of room 1” and “string” both of type string. Step 2: prompt_user prompts the user with the question “What is the shape of room 1?” Step 3: The user responds to the prompt and types “square” Step 4: prompt_user returns the string “square”, which is then passed to the function room_square_feet Step 5: The function room_square_feet calls prompt_user with two arguments, “side length of square room” and “integer” Step 6: The function prompt_user prompts the user with the question “What is the side length of square room” Step 7: The user responds to the prompt and types “12” Step 8: The function prompt_user returns the integer 12, which is saved in a variable in the function room_square_feet Step 9: The function room_square_feet calculates the size of the room (12 ∗ 12) and returns the integer 144. 3 Game Plan and Guidelines • All three functions are fairly simple, taken by themselves. You should be able to write each one in less than about 10 lines of code. • Start by writing a header and specification for the prompt_user function based on the description above. Then implement the function and test it using the interactive shell. Test it for both integer and string output types. • Write a header and specification for room_square_feet. Implement it, using your alreadytested prompt_user function, and test its functionality in the interactive shell. • Write the main function, noting that it takes no arguments and has no return value; when the total square footage is calculated, print the total. • Finally, at the bottom of your program, call your main function in a main guard so that running the program calls the main function: if __name__ == “__main__”: main() • As usual, you are not required to check for and handle input from badly behaved users: you may assume the user enters numbers when they’re supposed to, and that they enter either square or rectangle for the shape of each room. • We test your programs with automated scripts, so the prompts must be made in exactly the order shown in the sample outputs to receive full credit. The text of the prompts does not need to match exactly, but the order must match. 3 Submission Submit squarefootage.py via Canvas. Rubric Your file is called squarefootage.py and has a comment specifying author, date, and purpose at the top. 1 points Your program uses good, descriptive variable names 2 main, room_square_feet, and prompt_user have headers and docstrings consistent with the description in the lab handout 6 Each function is at most 10 lines of code (not counting comments) 6 prompt_user prompts the user and returns the correct type 4 room_square_feet uses prompt_user to prompt for the dimensions 2 main uses prompt_user to specify how many rooms 2 main calls prompt_user to prompt for shape of the room 2 main calls room_square_feet for each room and the return value is added to an accumulator variable 2 main function prints correct final square footage 3 Total 30 points
In this lab you’ll gain practice using and manipulating strings. In lecture you’ve seen how to iterate over the characters in a string, access individual characters by index, and how to slice out substrings. We also touched on a few of the multitude of methods that can be called on string objects, including upper, lower, find, and replace. Suppose you are an employee at a software company called Lotter.io. You have been tasked with writing a Python program that will simulate the drawing of a winning lottery pick, then prompt a user to guess the lottery pick, and inform the user if their pick is the winning pick. Your company’s secret sauce that will guarantee its explosive growth into a billion dollar startup is that the lottery doesn’t just involve guessing numbers: Instead, this lottery involves both words and digits. A lottery pick is made up of one of three words (monkey, dragon, or snake), and one of three digits (1, 2 or 3), arranged either with the word first or the number first. For example, monkey1, and 2dragon are both possible winning picks. The user only wins if the correct word and the correct digit are guessed in the correct order. The program consists of three main tasks: 1. Generate a winning pick. 2. Get a valid pick from the user. 3. Check the user’s pick against the winning pick and tell them how they did. Three sample invocations are shown in Figure 1. 1 Generate a winning pick Random pick generation is to be implemented in the generate winner function. The function header, specification, and some of its implementation have been written for you. Easter Egg Our lottery game will have a secret easter egg, a hidden feature that’s only accessible to those who have read the code, or users who somehow stumble upon it. Our easter egg behavior is as follows. 1 Figure 1: Three sample invocations The welcome message tells the user to press enter to continue; however, if the user enters something that looks like a valid pick and then presses enter, generate winner will simply use their input as the correct pick. The functionality for this easter egg has been implemented for you: the begin input variable captures what the user enters, and is passed into the generate winner function, which first checks to see if it should return the cheat pick. This “cheater mode” may help you more thoroughly test your program’s behavior by giving you the option to choose the winning pick without any randomness involved. It will also make grading easier for us, for the same reasons, so be sure not to modify the code that implements this feature. Your task is to write the code after this part of the function that generates and returns a truly random winning pick. Pseudocode for your portion of the function is provided as comments in the skeleton code. 2 Get a valid pick from the user. Implement the get_valid_guess function to prompt the user, repeatedly if necessary, until they enter a guess that contains one of the words and begins or ends with one of the numbers. Notice that these criteria do make it possible to enter an invalid pick (e.g., dragoncat3 contains one of the words and ends with one of the numbers. This is fine: cases such as these will be handled later in the program. The function header, specification, and pseudocode for this part are provided in the skeleton code. 2 3 Check the user’s pick Now, we need to tell the user whether any or all aspects of their pick were correct. Here’s what the program should do once it has determined the winning pick and the user’s pick. Your messages do not need to match mine exactly, but should convey the same content. Feel free to decide on your own prize for guessing the winning pick. • If the user inputs a pick that exactly matches the winning pick character for character, the program outputs a message telling the user they’ve won. • If the user’s word and number both match the winning pick, but their pick doesn’t match the winning pick exactly, print You guessed the correct number and word in the wrong order! • If the number matches but the word doesn’t, print You guessed the correct number but not the correct word. • If the word matches but the digit isn’t correct: print You guessed the correct word but not the correct number. • If neither the word nor number are correct, print You guessed neither the correct word nor the correct number. The main method includes calls to the two functions you completed in the prior tasks, followed by pseudocode for this step. You may want to, but are not required to, create a separate function to accomplish this task. Getting Started Download the skeleton code lottery.py from the course webpage. Open up and read through the skeleton code, making sure that you understand the provided code and function specifications. We recommend completing the three tasks in the order described above. You may find the in and not in operators useful on strings, as well as indexing individual characters of a string and slicing substrings. Review the lecture slides for details on the syntax for these operators. Don’t forget that when a program’s logic gets complicated, it can be helpful to define boolean variables to keep the conditions of if/elif statements short and easy to read. Submission Submit your completed program lottery.py file via Canvas. 3 Rubric Submitted a file called lottery.py 1 Comment at the top of program specifies author, date, and description 1 Easter egg code is unmodified 1 Random pick is generated 5 User is prompted again if guess doesn’t contain one of the words 5 User is prompted again if guess doesn’t begin or end with one of the numbers 5 Message printed for correct pick 5 Message printed for correct word and number but incorrect order 5 Message printed for correct word but not number, and vice versa 5 Message printed for neither correct 5 Coding style (commenting, variable names, etc.) 2 Total 40 points
1 Functions This section of the handout reviews the basics of functions. Please read through it before getting started, and refer back to it if you encounter confusion or unfamiliar terminology when completing the activity. If you have any questions, your TA is there to help. Basics As we’ve seen in lecture, functions provide a way to assign a name to a given procedure, or a sequence of statements. We’ve been using (calling) functions that have been written for us since early in the course, such as print(“Hello, world!”) A function can take zero or more input arguments, have effects, and optionally return a value. For example, print(“Hello world!”) takes one or more arguments as input, has the effect of printing them to the screen, and does not return a value. 1 Writing your own functions is an extremely powerful ability, because it gives you a way to create customizable pieces of code that you can then use as building blocks for creating more complicated programs. Recall from lecture that the syntax for declaring a function looks something like this: def function_name(arg1, arg2): “””An example function that demonstrates the syntax for writing your own functions.””” statement_1 statement_2 statement_3 return a_value Here’s an example program that declares a function that takes two inputs, computes their sum, and then prints the sum before returning it. The program then declares two variables and calls the function to print and return their sum. # example of a function definition: def calc_sum(num_1, num_2): “”” Print, then return, the sum of num_1 and num_2 Precondition: num_1 and num_2 are numbers. “”” the_sum = num_1 + num_2 print(the_sum) return the_sum a = 4 b = 6 # example call to the function: ab_sum = calc_sum(a, b) Notice that printing a value and returning it are two different things: printing is an effect that causes it to show up on the screen. Returning it means that the expression calc sum(num 1, num 2) evaluates to the resulting sum. This means when we execute the assignment statement after the function definition, the returned value pointed at by the sum will get assigned to the variable ab sum. 2 Triple-Quoted Strings Notice that the lines directly after after the function header (the line with the def keyword) contain a triple-quoted string. Enclosing a string in triple quotes is like using single or double quotes, except that newlines are allowed in triple-quoted strings. my_str = “a normal string with a newline” # will cause an error triple_quoted_string = “””A string in triple-quotes””” # will not cause an error print(triple_quoted_string) # would print the following: # A string in # triple-quotes Otherwise, a triple-quoted string behaves just like any other string. Specifications When writing functions in any language, it’s standard practice to write a specification (or spec, for short): a description of what someone needs to know to use it. In particular, the spec typically includes a description of any parameters, effects, and the return value, if any, of the function. This makes it possible for other programmers to make use of your function without having to read through the function’s code to figure out how it works. This is what you’ve been doing all along when calling functions like print: you know what it does, but you don’t know how the code is written to accomplish its behavior. Docstrings In Python, the convention is to write function specifications in docstrings: triple-quoted strings that appear just after the function header (the line with the def keyword). The triple-quoted string is not technically a comment: it’s actual Python syntax; but an expression (or a value) on a line by itself has no effect when executed by the Python interpreter, so it’s presence doesn’t change the behavior of the program. Consequently, it is not a syntactic requirement of the language to include a docstring in every function. However, it is a requirement of this course 3 to include a docstring in every function you write, unless you are told otherwise. Take a look at the docstring in calc sum for an example. What information should you include in your docstrings? Generally speaking, a programmer should know the following after reading your function’s specification: • The meaning of each parameter that the function takes • Any effects that the function has • The return value (and its type), if any, of the function • Any preconditions: Assumptions that your function makes about the state of the program, or about the arguments passed to it. • Any postconditions: Assumptions that can be made once the function call is finished about the program state or return value. Note that it’s a good idea to keep specifications as concise as possible. For example, the spec for calc sum does not specify as a postcondition that the return value is the sum of the two inputs, because that’s already stated in the description. However, it is worth including the precondition that the arguments are numerical, because otherwise an error might result. A user of your function is now aware that they shouldn’t call calc sum with non-numeric arguments. If they do and an error occurs, it’s their mistake, not yours! Local Variables Notice that in the definition of calc sum, we created a new variable called the sum1 . Because it was created inside a function definition, the sum is what is known as a local variable, meaning that it doesn’t exist (or isn’t “visible”) anywhere in the program except inside the calc sum function definition. A variable’s scope refers to the set of statements in a program where it is accessible; in this case, the sum’s scope is within the calc sum function. If we tried to refer to the sum outside that indented code block, we’d get an error. Variables such as a, b, and ab sum are called global variables because once they are defined using an assignment statement, they are visible for the entire remainder of the program. 1 I didn’t call it sum because that’s already the name of a builtin function; it’s syntactically valid to create a variable with that name, but it “hides” the builtin function so you can’t use it anymore because sum now refers to a varaible. 4 Parameters Are Local Variables When defining a function, we need a way to refer to the arguments that are passed in when it’s called. Parameters serve this purpose: in the calc sum function definition, num 1 and num 2 are the function’s parameters. When the function is being executed, num 1 points to the value of the first argument and num 2 points to the value of the second one. Consequently, parameters are simply special local variables that are automatically assigned the values passed to the function as arguments. Like any other local variable, their scope is limited to the function definition to which they belong. Referring to num 1 or num 2 outside of the function definition will result in an error for the same reason that trying to refer to the sum will cause an error. 2 Shape Functions for Turtles You’ll now write some functions that will make it easier to make complicated drawings using Python’s turtle module. For now, you’ll be provided with the function header and specification, and it is your job to make sure that the function implements (or adheres to) the spec exactly and in all cases. 2.1 Setup Create a lab5 directory in your lab environment of choice. Fire up Thonny, create a new file, and save it as turtleshape.py. Write a comment at the top with author, date, and a description of the program. Download turtleshape test.py from the course webpage and save it in your lab5 directory alongside turtleshape.py. 2.2 Testing One of the many benefits of writing small, self-contained functions is the ability to test them independently of other code that uses them. Once you’ve tested a function thoroughly, you can safely use it without fear of a bug lurking somewhere inside. It’s a good idea to test functions one at a time, as you write them. Start by making calls to your function in the interactive shell (the bottom pane in Thonny) to see if they’re working correctly. Once you believe a function behaves as specified, open up turtleshape test.py, and look toward the bottom for a commented-out call to a function named test function name. For example, for draw square, the corresponding function is called test draw square. Remove 5 Figure 1: The correct output of turtleshape test.py after all functions are completed. the # from the beginning of the line to enable the test function, then hit the green Run button to run turtleshape test.py. Each of the functions draws one piece of the drawing shown in Figure 1. For example, the black squares of increasing size in the bottom left should appear exactly as in the figure once your draw square function works correctly. To make sure that everything’s set up correctly, first run the test program unmodified: you should see the drawing with only the green dot in the middle. 6 2.3 draw square In last week’s lab, you wrote a loop to make a turtle draw a square. Now, let’s do the same thing, but wrap it in a draw square function so we can draw a square with a simple function call. Header and Specification: def draw_square(t, side_length): “”” Use the turtle t to draw a square with side_length. Precondition: t’s pen is down Postcondition: t’s position and orientation are the same as before “”” Type the function header and specification (docstring) into turtleshape.py, then write code in the function body to make the turtle draw a square. Try out your draw square function in the interactive pane, something like this: >>> import turtle >>> scott = turtle.Turtle() >>> draw_square(scott, 100) 2.4 draw rectangle Next, write a more general function to draw a rectangle of any size. Notice that once we have a rectangle function, we can use it to draw a square by calling the rectangle function with equal side lengths. def draw_rectangle(t, width, height): “”” Draw a rectangle using turtle t with size width x height Precondition: t’s pen is down Postcondition: t’s position and orientation are the same as before “”” After uncommenting test draw rectangle in turtleshape test.py, the orange spiral of rectangles should appear as in Figure 1. 7 2.5 draw triangle Another way to generalize the square function would be to draw different equilateral polygons (i.e., shapes with different numbers of equal side lengths). To get started, implement a draw triangle function that draws a triangle with equal length sides: def draw_triangle(t, side_length): “”” Draw an equilateral triangle using turtle t with side_length Precondition: t’s pen is down Postcondition: t’s position and orientation are the same as before “”” When completed and the corresponding test function is uncommented, the purple bowtie-like figure should appear as in Figure 1. 2.6 draw polygon You’ve now figured out how to draw a square (4-sided polygon) and a triangle (3-sided polygon). Now, write a function that draws an n-sided polygon: def draw_polygon(t, side_length, num_sides): “”” Draw a polygon with num_sides sides, each with length side_length using turtle t Precondition: t’s pen is down; num_sides > 2 Postcondition: t’s position and orientation are the same as before “”” The red pattern with nested n-gons should appear as in the Figure when this function works correctly. 2.7 draw snowflake One of the reasons that functions are so powerful is that we can compose them; in other words, one function can call another. Now that we have a function that draws polygons, it’s pretty simple to make a function that uses it to create variations on the snowflake-like pattern from last week’s lab: 8 def draw_snowflake(t, side_length, num_sides): “”” Use t to draw a snowflake made of ngon-sided polygons. The snowflake contains 10 copies of a polygon with num_sides and side_length, each drawn at a 36-degree angle from the previous one. Postcondition: t’s position and orientation are the same as before “”” The teal, green, and blue snowflakes in the bottom right corner should appear as in the Figure once this function is working correctly. 2.8 teleport Finally, write a function that implements a convenient ability: teleport the turtle to a given location without drawing, but leaving the pen state unchanged afterwards. This is similar to the turtle object’s goto method, except it never draws. To accomplish this, you’ll need to pick up the pen first, then put it down only if it started out down. You may find it helpful to look at the turtle documentation for methods that could be useful here. def teleport(t, x, y): “”” Move the turtle to (x, y), ensuring that nothing is drawn along the way. Postcondition: the turtle’s orientation and pen up/down state is the same as before. “”” When basic movement is working, the gradient-colored grid of dots should appear. When the pen is correctly restored to its previous state, the vertical red lines should appear as in the Figure. 2.9 Screenshot Take a screenshot of the Turtle window when you have everything working, and name the file turtleshape.png. 9 3 Drawing Your final task will be to write a short program that uses your drawing functions to make some interesting drawing. Importing Local Files; Writing “Main” Functions You may have noticed that the code in turtleshape test.py calls functions from turtleshape.py. To make this possible, turtleshape test.py had to execute import turtleshape; this is just like importing a module (like math or turtle, except the module is located right in the same directory. Python looks first in the local directory for a module with name turtleshape.py, then it imports the code if it is found. What happens when importing code? Basically, it’s like pasting the imported module’s code into your file: it all gets run. So far, your turtleshape.py contains only function definitions, so importing it simply defines those functions. But if you wrote code outside the functions, it would get executed when you import turtleshape. Often, we want to separate the behavior of a file as a program versus as a module, so importing it causes functions to be defined but doesn’t run the program, but you can still run the program, e.g., with python turtleshape.py or by clicking the Run button. The way to do this is to use a so-called “main function” or “main guard”. turtleshape test.py contains an example of this. Basically, any code you want to run as a program but don’t want to execute when you import your file as a module, you can put inside the following if statement: if __name__ == “__main__”: # code here will not run when this file is imported # but will run if the file is run as a program print(“Hello, world!”) You don’t need to worry about the details of why this happens, but it’s a good thing to remember how to do. You can always google it if you forget the syntax. A common way to use this is to have one function that contains your program code, usually called main(), and place a single call to that function inside the main guard: 10 def other_function(): “”” Return the number 4 “”” return 4 def main(): “”” Main program: print hello, world! “”” print(“Hello, world!”) if __name__ == “__main__”: main() If this were in a file called prog.py, then running python prog.py would print ”Hello, world!”, whereas executing import prog would make other function and main available for use, but wouldn’t execute the call to main(). Make a Drawing Below all your function definitions in turtleshape.py, write some code that creates a drawing. Put your code in a main function and call it inside a main guard as illustrated above, so that running the test program (which imports your code) does not cause your main function to be called. Your code should use at least one loop and make use of at least two of the functions you wrote in this lab. Feel free to also use other functions from the turtle module. Take a screenshot of your drawing and save it as drawing.png. Your drawing should complete in under a few seconds (use turtle.tracer(0,0) and turtle.update() as in Lab 4), and should match your screenshot. Submission At this point, show the output of the test program and your drawing to your TA so you can be immediately awarded points for it. Unless you do not finish during the lab period, do not leave until your TA has verified that your output is correct. Create a zip file called lab5.zip containing turtleshape.py, turtleshape.png, and drawing.png. Upload your zip file to the Lab 5 assignment on Canvas. Even if your TA has checked you off, you still need to submit to Canvas. 11 Rubric You submitted a single zip file called lab5.zip, containing the correct files 1 The top of your program has comments including your name, date, and a short description of the program’s purpose. Comments placed throughout the code explain what the code is doing. 1 draw square works correctly 3 draw triangle works correctly 3 draw rectangle works correctly 3 draw polygon works correctly 3 draw snowflake works correctly 3 teleport works correctly 3 Your drawing code is is inside a main guard 2 Your drawing code uses at least one loop and two of the functions you wrote. 6 Your drawing code runs in under a few seconds. 2 Total 30 points
Introduction and Setup This lab gives you practice with Python loops and Turtle graphics. You’ll complete three programs that draw pictures: the first two are so-called “ASCII art”, which refers to pictures made from text characters; the third one is made using a turtle. If you have questions, be sure to ask the TA: your TA is there to help you! Log into your operating system of choice and make a lab4 directory in your N drive or home directory. You will write three programs: triangle.py, triangle.py, and turtledraw.py. 1 triangle.py Your first task is to write a program that asks the user for a width, then prints a sideways isosceles triangle made of asterisks (“*”) with the given maximum width. For example, a width of 3 would print: * ** *** ** * A width of 8 would print: 1 * ** *** **** ***** ****** ******* ******** ******* ****** ***** **** *** ** * A triangle of width 1 would print a single asterisk, and width 0 should print no asterisks. Your solution should use at least one for loop. Here’s a suggested way to approach this problem: 1. Create an empty file triangle.py in your lab4 directory. Write a comment at the top listing the code’s author, date and a short description of the program. 2. Write a code snippet that prints a given number of asterisks in a row, followed by a newline. Hint: there are ways to do this with or without using a loop. 3. Draw the top half of the triangle by putting the code you wrote in Step 2 in the body of a loop that changes the number of asterisks drawn. 4. Draw the bottom half of the triangle using a similar approach. 5. Test your code on widths 2 and 3 first, then check 0 and 1, then try a larger number such as 8. 2 2 flag.py The purpose of this program is to print an ASCII art approximation of the American flag. Figure 1: The true American flag Some things to notice: • We have to get a bit approximate with ASCII art, because the rows of stars in the true flag don’t line up with the stripes. Our version lines them up, and thus has only 4 stripes below the stars, instead of 6 as in the true flag. • The whole flag has 13 rows. • The whole flag is 55 characters wide. • The 9 rows of stars alternate between having 6 and 5 per row, with two spaces in between. The 6-star rows have no spaces at the beginning and two before the stripes begin; the 5-star rows have two spaces at the beginning and thee spaces before the stripes begin. Here are some guidelines and suggestions: • You must control structures (loops, if statements, etc.) to print the rows of the flag. • You may use no more than 6 print function calls 3 * * * * * * ====================================== * * * * * ====================================== * * * * * * ====================================== * * * * * ====================================== * * * * * * ====================================== * * * * * ====================================== * * * * * * ====================================== * * * * * ====================================== * * * * * * ====================================== ======================================================== ======================================================== ======================================================== ======================================================== Figure 2: An ASCII art approximation of the American flag. • All print function calls must be inside the body of a loop. • The characters must be printed exactly as displayed in the Figure above. • Try to write this program as concisely as possible. I (Scott Wehrwein) wrote a solution that has 7 lines of code, not counting comments. If you’re looking for a challenge, see if you can fit your program in a space smaller than the flag it prints (13 lines long, 55 characters wide). 3 turtledraw.py In this section, you’ll write a program turtledraw.py that creates a picture like the one shown in Figure 3. This may seem intimidating at first! But the code you’ll need to write isn’t actually that complicated. There’s a lot of repetition in the picture, and you’ll use loops to perform this repetition effortlessly. You’ll also get some practice looking at the documentation for a module; the turtle module has tons of functionality, most of which you won’t use or understand—that’s fine! The ability to sift through unfamiliar documentation and find out how to use the pieces relevant to solving your problem is a valuable skill. Each pattern is identical, and is simply composed of many squares with side length 100, each drawn with one corner in the center of the pattern, but at different angles. 4 Figure 3: The result of running turtledraw.py 3.1 Drawing a Square Start by writing code to draw a square with side length 100. Recall that you saw an example like this in lecture. After this step, your program should generate the picture shown in Figure 4. 3.2 Drawing one pattern with many squares Next, you’ll create a single one of the patterns. To draw 60 squares that go all the way around a circle (360 degrees), you’ll need each one to be different by 6 degrees from the previous one. Put the code for drawing a square inside a for loop that draws all 60 squares. When it works correctly, you should get a picture like the one in Figure 5. 3.3 Speeding up the drawing At this point, you’re probably sitting around waiting for the turtle to finish drawing, and thinking “wow, CS is boring”. Most programs we write run very quickly, but you can see that loops make it easy to write short programs that still take a long time to finish! Fortunately, 5 Figure 4: Drawing a square with side length 100 the turtle module has some features to speed up the drawing. Start by looking in the turtle module’s documentation (https://docs.python.org/3.3/library/turtle.html). There’s a lot there, but don’t worry about all the stuff you don’t understand! Find the section on the speed method, and read the description to see if you can figure out how it’s used. In your code above where your turtle starts drawing anything, call the speed method on your turtle object (e.g., scott.speed(arg )) with the correct argument to make the turtle move as quickly as possible. Try running your program again – do the squares draw faster now? That helps some, but it still takes a few seconds to draw 60 squares! The reason for this is that Python is re-drawing the entire picture every time the turtle moves. You can think of this as Python having to loop over all 120,000 pixels and re-color each one. We can speed things up even more by telling the turtle not to re-draw between moves, and to draw once at the end. Near the top of your code, before your turtle starts drawing, add the following line: turtle.tracer(0, 0) Notice that this a turtle module function, not a method of your turtle object. This disables re-drawing after each move. Next, at the end of your program, add the following line: 6 Figure 5: Drawing a single radial pattern. turtle.update() This tells Python to re-draw the picture to the screen. Now we’re not wasting effort re-drawing each time the turtle moves! When debugging your code, you may find it helpful to keep the animations to see the sequence of moves the turtle makes. Make sure that the submitted verision of your code has the above lines and draws the whole picture in less than a couple seconds. 3.4 Repeating the pattern four times The last thing we need to do is draw the pattern four times, near each corner of the window. In particular, draw the pattern centered at all four corners 200 units away from the middle of the screen (at coordinates (0,0), where the turtle starts). Start by looking at the documentation for the penup, pendown, and goto methods. Start by using these methods to move your turtle to position (-200, -200) before drawing the pattern. Make sure the turtle doesn’t draw a line when it’s moving from the middle of the screen to the corner. Finally, we need to move the turtle to each of the four corners and repeat the same pattern. You could copy/paste the same code four times and change the coordinates, but that wouldn’t be ideal if we wanted to draw 400 of these patterns instead. So let’s use loops instead! 7 The coordinates where we want to draw the pattern are: (-200, -200) (-200, 200) ( 200, -200) ( 200, 200) Notice that this is just all possible ordered pairs of -200 and 200. You saw an example of how to print all possible pairs of 1 through 6 in lecture; this is similar, but with -200 and 200 instead of 1 through 6, and instead of printing them, you’re moving the turtle to those coordinates and drawing the pattern. In class we used while loops, but for loops could also work (and might be a more natural choice). You may choose whichever loop you like. The pseudocode I’d write for this is something like: for i = each of {-200, 200}: for j = each of {-200, 200}: move to (i,j) without drawing a line draw the pattern 3.5 Color the drawing (optional) Look up the turtle’s color method and figure out how to make your drawing more colorful. You can color the drawing however you want, but don’t change the pattern drawn. An example coloring is shown in Figure 6. Preparing your files for submission: creating a zip file For this lab and future labs and assignments with multiple files to submit, you will submit a single zip file containing all your programs. Instructions on how to do this depend on your platform; here are the steps for Linux, Windows, and Mac: 8 Figure 6: Sample colored pattern. Linux Using the terminal (command line): 1. Navigate to the directory containing your files: cd lab4 2. run the zip command, giving it the zip file name as the first argument, and all the files you want to submit as the reamining arguments. For example: zip lab4.zip triangle.py flag.py turtledraw.py 3. Verify that the zip file (e.g., lab4.zip) has been created by listing the files in the directory: ls 9 You can also use the graphical file manager. Navigate to the directory with your submission files, select all the files you wish to submit (hold CTRL and click on each file to select multiple files). Right click on one of the selected files and select Compress…. Name the zip file and make sure to select the .zip option. 3.6 Windows Navigate to the directory containing your code using the file explorer. Select all the files you wish to submit (hold CTRL and click on each file to select multiple files). Right-click on one of the files, hover over Send to, and choose Compressed (zipped) folder. Rename the resulting zip file to your desired filename (e.g., lab4.zip). 3.7 Mac Follow the terminal (command line) instructions under Linux. Alternatively, navigate to your code in Finder and select all the files you wish to submit. Select multiple files by holding down Command and clicking each file. Right click one of the files and select Compress 3 items (the number will depend on how many files you have selected). Rename the resulting Archive.zip to your desired filename (e.g., lab4.zip). Submission Submit a zip file called lab4.zip containing triangle.zip, flag.zip, and turtledraw.zip to the Lab 4 assignment on Canvas. 10 Rubric You submitted a single zip file called lab4.zip, containing three Python files called triangle.py, flag.py, and turtledraw.py 1 point The top of each program has comments including your name, date, and a short description of the program’s purpose. Comments placed throughout the code explain what the code is doing. 3 triangle.py produces the correct output 6 flag.py produces the correct output 5 flag.py uses 6 or less print statements, and no print statements outside a loop 5 turtledraw.py draws at least one instance of the pattern. 4 turtledraw.py draws four copies of the pattern in the correct corner positions using loops. 4 turtledraw.py draws the pattern quickly and without animation. 2 Total 30 points
Introduction This lab gives you practice with if statments (also sometimes called conditionals, or selection. In the process, you’ll also get some more experience with Boolean operators. The idea is the following: your goal is to write a program that recommends what clothing items to wear based on the weather conditions indicated by a user. If you have questions, be sure to ask the TA: your TA is there to help you! By now you’ve seen how to use Thonny on both your Windows and Linux accounts. You are free to select whichever operating system you want to use. 1 Setup We recommend creating a new directory/folder called lab3 on your N drive (Windows) or in your home directory (Linux). In your lab3 directory, create a new Python file clothingPicker.py. 2 Unary Selection Unary selection is a fancy name for a simple if statement. You’ve seen these already in lecture: the if statement allows you to execute a sequence of statements (or a code block) if a given boolean expression evaluates to True, or skip over the code block if the expression evaluates to False. The code block inside an if statement must contain one or more statements. In Python, the code block associated with an if statement is distinguished by indenting lines of code immediately underneath the line containing the if keyword of the selection statement. The syntax and structure of a unary selection statement are shown below: if boolean_expression : statement 1 statement 2 statement 3 For this first version, write a single unary selection statement that checks whether the user has specified whether it is windy or not. If it is windy, the program should output, “Be sure to not bring an umbrella because it is windy.” Pseudocode and sample input and output for this first version of your program are given below. • Ask the user if it is windy 1 Figure 1: Sample output for the initial version. • Save user input into a variable • If it is windy, print “Don’t bring an umbrella because it’s windy.” • If it is not windy, do nothing 3 Binary Selection We’ve also discussed binary selection, which is a fancy name for an if/else statement. It has an if clause and an indented code block just as in unary selection, but it also has an else clause and code block that is executed whenever the Boolean expression in the if clause evaluates to False. The syntax and structure of a binary selection statement are shown below below, where Statements 1 through 3 are the code block for the if clause, and Statements 4 and 5 constitute the code block for the else clause. if boolean_expression : statement 1 statement 2 statement 3 else: statement 4 statement 5 Next, modify your code so that it still prompts the user to answer whether it is windy, but this time if the answer is “no”, then have the program output, “It is not windy. Bring an umbrella if you wish.” If it is windy, the program should output the same as before. Sample input and output for this second version of your program is shown below. Figure 2: Sample output, Binary Selection 2 4 Boolean expression with logical operators We’ve discussed in lecture how to use more complicated boolean expressions; specifically, the logical operators or, and, and not were presented. Modify your code to also prompt the user to for whether it is sunny or cloudy. Retain the if, else code as you’ve already written, except change the Boolean expression to check if it is windy and sunny. If the user specifies yes, then the output should be “It’s windy and sunny, so bundle up and don’t bring an umbrella.” If it is not both windy and sunny, have the program output, “It is not both windy and sunny.” Pseudocode for the revised version of your program is shown below. Sample output is shown in Figure 3. • Ask user if it is windy, save input into a variable • Ask user if it is sunny or cloudy, save input into a second variable • If it is windy and sunny, output “It’s windy and sunny, so bundle up and don’t bring an umbrella.” • Otherwise, output “It is not both windy and sunny.” Note: Here and in all further parts of the lab, you may assume that the user responds to the sunny/cloudy prompt with the exact input “sunny” or “cloudy”; you do not need to handle other inputs. Also notice that the instructions above are phrased only in terms of sunny and not sunny. Figure 3: Sample output for boolean expression with logical operators 5 Nested if statements As shown in lecture, it is possible to nest an entire selection statement (if statement with an else clause) inside of a code block of an existing if statement. The syntax is shown in below. To make it easier to see, a box has been drawn around the outer-most and inner most if statements. if boolean_expression_1 : if boolean_expression_2 : statement_1 else: statement_2 else: statement 4 statement 5 3 Modify your code so that the outer condition (boolean expression1 ) checks if it is windy, and the inner condition (boolean expression1 ) checks whether it is sunny. If it is windy and sunny, print “It is windy and sunny,”; if it is windy and not sunny, print ”It is windy and not sunny”; if it is not windy, print “It is not windy.” Sample output is shown In Figure 4. Figure 4: Output of program with nested conditionals 6 Clothing picker: chained conditionals One more possible clause in a conditional statement an elif clause. An elif, which is short of else if, contains a Boolean expression that is checked ONLY if the first if’s condition, and all preceding elif conditions all evaluate to False. Unlike an else, whose code block is ALWAYS executed if the if condition evaluates to False, the code block of an elif is executed only if the conditional of the elif evaluates to True. Note that including an else is always optional; an if statement can have zero or more elif clauses and zero or one else clause. This time, have your program prompt the user to ask if it is sunny, and also ask for the temperature. Modify your program so that the else code block has a nested if statement as well. Both of the nested if statements will now have if, elif, and else clauses (see sample below). The outer condition should check whether it is sunny, and inner if/elif/else should make recommendations according to the temperature and whether or not it is sunny. Don’t forget to convert the temperature input to an int and recall that you can use comparison operators like = to get the boolean result of numerical comparisons. Write appropriate conditions that rely on the user’s input (whether it is sunny and the temperature), and write appropriate print statements that produce the clothing recommendations indicated in Figure 5. Table 1 shows the sunny/temperature combinations and their corresponding output value (clothing recommendation) that your program should print. Sample output is shown in Figure 6. 4 Figure 5: Schematic of logic for clothing picker Table 1: Sample input/output combinations Sunny Temperature Output Yes Less than 60 degrees Wear a sweater Yes 60 degrees exactly Woo hoo, it is 60 degrees. Wear what you want Yes More than 60 degrees Wear a tee shirt and flip flops No Less than 40 degrees Wear a coat and hat No Between 40 and 50 degrees Not quite freezing, but close. Bundle up No 50 degrees exactly A jacket is best No More than 50 degrees Wear a long sleeved shirt Figure 6: Sample clothing picker program output. Note that this does not display all possible cases in the table above, but your program must work for all of them. Submission Upload clothingPicker.py to Canvas for grading. 5 Rubric Your file is called clothingPicker.py 1 point The top of clothingPicker.py has comments including your name, date, and a short description of the program’s purpose. Comments placed throughout the code explain what the code is doing. 3 Your program makes use of if, elif, and else. 6 Your program correctly prompts the user and stores the user’s input. 3 Your code provides unique clothing combinations for each of the sunny/temperature combinations in the table in this lab handout. 7 Total 20 points
1 Logging into Linux Linux is an operating system with much of the same functionality as the Windows or Mac operating systems, but with a slightly different feel. The lab computers are dual boot computers, and when the computer boots up you can specify which of the operating systems (Windows or Ubuntu, which is a flavor of Linux) you want to use. To log into your CS Linux account, reboot your CS computer; when a menu appears, use the arrow keys to select Ubuntu from the set of options, and press enter to select it. The login window should look similar to what is shown in Figure 1. You can click on the circular gnome icon to the right of ”Login” to view a menu where you can customize the look and feel of your Linux session. For now, we’ll assume that you’ve left it on Ubuntu (Default). Provide your CS account username and password (the same credentials as you used for your Windows account in lab 1) to log in. Once logged in, the overall look and feel of your desktop will vary depending on which environment you have selected. To access system settings for your desktop environment, click on the power icon in the upper right hand corner and select System Settings… To find Thonny, click the Ubuntu icon (the top-most icon in the bar on the left side of the screen. If Thonny doesn’t appear among the applications there, you can type Thonny in the search bar and it should appear. Once Thonny starts, it should look very similar to the Windows version you used in last week’s lab. 1 Figure 1: A typical linux Login prompt and desktop environment selector 2 Linux Command Line Basics Windows, Mac OS, and Linux all provide graphical interfaces such as those you’re used to using, that allow you to open programs and accomplish tasks using the mouse, icons, windows, and so on. All of these operating systems also provide another way of interacting with them, called a Command Line Interface (CLI). Although there is a steeper learning curve for knowing how to accomplish things using the command line, for certain tasks it can be more powerful once you know how to use it. In this lab, you will learn the very basic elements of how to interact with the Linux command line and learn how to run Python code without the help of an IDE such as Thonny. What you will learn here is only a tiny fraction of the commands available; you can find a helpful ”cheat sheet” of many commonly used Linux commands on the course website1 i you want to learn more. 1. Begin by opening a command line window (also called a Terminal). Click on the Ubuntu icon in the upper left corner and type terminal to initiate a search; click on the Terminal icon from the results to launch a new terminal window. 2. In the terminal, the $ sign and the space to the right of it where you type is called the command line. Commands that you issue are interpreted by a program called a shell (the default shell, or command line language, in the lab machines is bash). It is one of the many shells available in Linux. 3. You’ll notice that the $ is prepended with your username and an @ followed by the name of the computer that you are logged into. For example, wehrwes@linux-11:~$ specifies the user wehrwes logged into the linux-11 machine. 4. All of the things that you can do with the mouse when interacting with a windows environment you can also accomplish via the command line. In the following steps you will create a new directory (folder), navigate into that folder, and run python from the command line. For these instructions, code and/or sample file content or output are 1Direct link: https://facultyweb.cs.wwu.edu/~wehrwes/courses/csci141_19s/labs/linuxref.pdf 2 shown in boxes. Type commands EXACTLY as they provided, and press return/enter to issue the command. For example: whoami is instructing you to type the command whoami on the command line and execute it by pressing return/enter. Try it out. What does the whoami command do? 5. Commands can take arguments, similarly to how functions in Python take arguments, except here they are not surrounded by parentheses. To create a directory, use the mkdir command with a single argument that is the name of the directory (folder) that you want to make. Create the directory Lab2. mkdir Lab2 6. To confirm that you have made your directory, issue the ls command, which will list all contents of the directory where you are currently in. ls You should see a list with multiple items, which are the files and/or directories in your account. If done correctly, Lab2 should be listed. 7. In graphical interface, you would double click on a folder to access that folder. In Linux, you open a directory using the command cd, for change directory. Enter the Lab2 directory. cd Lab2 8. Launch Thonny via the command line : thonny & The & is important: this allows you to continue using the terminal window AFTER you launch Thonny. Use Thonny to create a new file, helloWorld.py, with a single print statement : print(“hello world”). Save the file in your Lab2 folder. Return to the terminal, and again issue the ls command, and you should see the just-created file listed. 9. Just as you can run a Python program using Thonny by pressing the green Run button, you can also run a program from the command line. In the terminal window (make sure you are in your Lab2 folder, which contains your Python program), run the helloWorld program by invoking the python3 interpreter : python3 helloWorld.py You should see the output of your program printed to the terminal console line. For this lab, you must invoke the helloWorld.py program from the command line. To provide proof that you have done so, either upload a screenshot showing that you invoked helloWorld from the command line (use the screenshot tool available on Linux), or show your TA how you execute the program helloWorld from the command line so they can give you credit on Canvas for those points right away. For the remaining sections of this lab, you can run python either via Thonny or via the command line. 3 3 Errors, comments, and the sep argument of print Inevitably, you will write code that will have bugs, or errors, no matter how experienced of a programmer you might be. Knowing how to find and fix bugs is a critical skill for all programmers. Using a browser such as Firefox, go to the course website: https://facultyweb.cs.wwu.edu/~wehrwes/courses/csci141_19s/#schedule) download the file badCode.py, and save it in your Lab2 folder. The contents of that file are shown in the following figure. Open the file badCode.py in Thonny. Read over the code, paying particular attention to the comments. Proper commenting is crucial to writing good code, so that it is easy to read by you and others. In python all comments begin with the # character. As a general rule: • Include your name (the author) and a short description at the top of each .py file • For every few lines of code, include a descriptive comment • Use white space (blank lines) to chunk your code into logical sections For all the labs and assignments in this course, commenting is a portion of the rubric. Get into the habit now of commenting your code well! Notice that this code contains a brand new way of using print. Adding sep=”” (short for “separator”) as the last argument to the print function will prevent print from adding spaces between items that you want printed. If you use sep=””, the only spaces that are included in the output are the spaces that you place explicitly into the Strings. For example: print(“Taking”, “CSCI”, 141, “woo-hoo!”) would print the following: Taking CSCI 141 woo-hoo! 4 but print(“Taking”, “CSCI”, 141, “woo-hoo!”, sep=””) would print the following: TakingCSCI141woo-hoo! In general, the print function defaults to ” ” as the separator between the arguments it prints. If you want a different separator, you can give any string to the sep argument, such as the empty string (sep=””) or a comma (sep=”,”), or any other string you’d like (e.g., sep=”, uhh, “). Try out a few calls to print with different separators in the interactive Shell pane in Thonny. badCode.py has a single intentional error. Run the code to see the error (following Figure). Look closely at the error message. On what line number is the error? Fix the error. Hint: Refer to the lecture slides for fixing an error that uses the conversion function int. Be sure that you modify ONLY the line of code that says numReindeer = int(approxNumReindeer). You may not modify any other line of code, nor add nor delete any line of code. 4 Additional errors Download faultyCode.py from the course webpage and save it in your Lab2 folder. The contents of that file are shown in Figure 2. Take a close look at the code. Notice again the good commenting. The program faultyCode.py has intentional MULTIPLE errors. Run the code (either using Thonny or via the command line), and look closely at the error message. Fix the errors in faultyCode.py. Go back and forth between fixing an error and trying to run the program. Ultimately, the goal is that the output of the program is as shown in Figure 3. 5 Operands and Operators In lecture we have discussed operands and operators. Make sure that you know the definition of both. If you do not recall, review the lecture slides. 5 Figure 2: contents of faultyCode.py Figure 3: Output of the corrected faultyCode.py program. In this section, you’ll solve the following programming problem: The period key on your keyboard is broken, but you would like to want to multiply two numbers with a decimal digit. Let’s look at an example. Suppose you want to calculate 20.4 × 17.7, but can only enter 204 and 177. The desired result is 361.08. If the user inputs the values 204 and 177, how can you convert them to 20.4 and 17.7? By using the modular and integer division operators! For example, 204 modulus 10 has a remainder of 4, which gives the decimal value .4, while 204 integer division 10 gives 20, which is the number before the decimal in 20.4. The Math: Suppose that for the input values 204 and 177 you have successfully extracted the whole and decimal values (i.e., 20, 4, 17 and 7). How can you calculate the result of 20.4 x 17.7? Multiplication of decimal values requires you to sum the following four parts: • The first integer times the second integer • The first integer times the second decimal • The first decimal times the second integer • The first decimal times the second decimal Notice that for each decimal, we also multiply in a factor of 0.1 to make sure that it is correctly 6 weighted in the final product. In our example, the calculation looks like this: 20.4 ∗ 17.7 = (20 ∗ 17) + (20 ∗ 7 ∗ 0.1) + (4 ∗ 0.1 ∗ 17) + (4 ∗ 0.1 ∗ 7 ∗ 0.1) = 340 + 14 + 6.8 + 0.28 = 361.08 1. Download brokenCalculator.py from the course webpage and save it to your Lab2 folder. 2. That file is incomplete. Only two lines of code have been written, which you are not allowed to edit. The rest are comments. Lines of code that say # COMPLETE THE CODE you will need to write. Read the comments for each section to get a sense of what code you need to write. Also, the number of COMPLETE THE CODE comments in that file is how many lines of python code I (Scott) wrote in my solution. It’s okay if your solution uses fewer lines of code, or more, but each block of code should accomplish what the comment above it specifies. For the lines of code that you write, you are only allowed to use the print function, the assignment operator, and the following mathematical operators: • // • % • * • + For the lines of code that you write, you cannot use float(), nor int(), nor /. 3. There are 7 parts to the code, labeled A through G. Here are hints for each of them: • A: This requires a single use of the print function • B: Use only the // and % operators. Follow the logic in the description above • C: This requires a single use of the print function • D: Do the same for the second integer as you did for the first integer (step B). Use only the // and %operators • E: The same as step C, but for the second integer • F: Use the Hint above for explanation on how to do this • G: This requires a single use of the print function. In your python code, you CAN make use of periods, but when the program is RUN, the user CAN ONLY enter integer (non decimal) numbers. 7 A sample output for the completed code is shown in the following figure: Submission Either show your working code to your TA, who will post your lab grade scores right away, else upload the following files: • Screenshot (.png, or .jpg file) showing you invoking your helloWorld program from the command line • Your fixed faultyCode.py code file • The completed brokenCalculator.py file that can reproduce the output shown in the above figure Rubric Screenshot showing execution of helloWorld from the linux command line 5 points faultyCode.py has been fixed, and is properly commented 3 brokenCalculator.py uses only %, //, + and ∗ operators for the lines of code that you have written 3 brokenCalculator.py has no syntax errors 3 brokenCalculator.py produces the correct output 3 brokenCalculator.py is properly commented 3 Total 20 points
1 Overview The goal of this project is to gain more practice with using functions, lists and dictionaries and gain some intuition for Machine Learning, the field of computer science concerned with writing algorithms that allow computes to “learn” from data. The problem we’ll be solving is as follows: Given a data file containing hundreds of patient records with values describing measurements of cancer tumors and whether or not each tumor is malignant or benign, develop a simple rule-based classifier that can be used to predict whether an as-yet-unseen tumor is malignant or benign. The general idea is that malignant tumors are different than benign tumors. Malignant tumors tend to have larger radii, to be more smooth, to be more symmetric, etc. Measurements have been taken on many tumors whose class (malignant or benign) is known. The code you are going to write will get the average score across all the malignant tumors for an attribute (e.g. ‘area’) as well as the average score for that attribute for benign tumors. Let’s say that the average area for malignant tumors is 100, and for benign tumors is 50. We can then use that information to try to predict whether a given tumor is malignant or benign. Imagine you are presented with a new tumor and told the area was 99. All else being equal, we would have reason to think this tumor is more likely to be malignant than had its area been 51. Based on this intuition, we are going to create a simple classification scheme. We will calculate the midpoint between the malignant average and the benign average (75 in our hypothetical example), and simply say that for each new tumor, if its value for that attribute is greater than or equal to the midpoint value for that attribute, that is one vote for the tumor being malignant. Each attribute that we are using produces a vote, and at the end of counting votes for each attribute, if the malignant votes are greater than or equal to the benign votes, we predict that the tumor is malignant. 2 Machine Learning Framework “Machine learning” is a popular buzzword that might evoke computer brain simulations, or robots walking among humans. In reality (for now, anyway), machine learning refers to something less fanciful: algorithms that use previously observed data to make predictions about new data. It may sound less glamorous than fully sentient robots, but that’s exactly what was described above! You can get more sophisticated about the specifics of how you go about this, but that’s the core of what machine learning really means. If using data to make predictions on new data is our goal, you might think it makes sense to use all the data we have to learn from. But in fact, if we truly don’t know the labels (e.g., malignant or benign) of the data we’re testing our algorithm on, we won’t have any idea whether it’s doing a good job! For this reason, it makes sense to split the data we have labels for into a training set, which we’ll use to “learn” from, and a test set, which we’ll use to evaluate how well the algorithm does on new data (i.e., data it wasn’t trained on). We will take about 80% of the data as our training set, and use the remaining 20% as our test set. 2.1 Training Phase Here’s how our classifier will work: In the training phase, we will “learn” (read: compute) the average value each attribute (e.g. area, smoothness, etc.) among the malignant tumors. We will also “learn” (again: compute) the average value of each attribute among benign tumors. Then we’ll compute the midpoint for each attribute. This collection of midpoints, one for each attribute, is our classifier. 2.2 Testing Phase Having trained our classifier, we can now use it to make an educated guess about the label of a new tumor if we have the measurements of all of its attributes. Our educated guess will be pretty simple: • If the tumor’s value for an attribute is greater than or equal to the midpoint value for that attribute, cast one vote for the tumor being malignant. • If the tumor’s attribute value is less than the midpoint, cast one vote for the tumor being benign. • Tally up the votes cast according to these rules for each of the ten attributes. If the malignant votes are greater than or equal to the benign votes, we predict that the tumor is malignant. If we want to use this classifier to diagnose people, we have an important question to answer: how good are our guesses? To answer this question, we’ll run test our algorithm on the 20% of our data that we held out as the test set, which we didn’t use to train the classifier, but we do know the correct labels. Our rate of accuracy on these data should be indicative of how well our classifier will do on new, unlabeled tumors. 3 Dataset Description You have been provided with cancertTrainingData.txt, a text file containing the 80% of the data that we’ll use as our training set. The file has many numbers per patient record, some of which refer to attributes of the tumor. The skeleton code includes the function make_training_set(), which reads in the important information from this file and produces a list of dictionaries. Each dictionary contains attributes for a single tumor as follows: 0. ID 1. radius 2. texture 3. perimeter 4. area 5. smoothness 6. compactness 7. concavity 8. concave 9. symmetry 10. fractal 11. class The middle 10 attributes (numbered 1 through 10) are the numbers that describe the tumor. The first attribute is just the patient ID number, and the last attribute is the actual real life state of the tumor, namely, malignant (represented by “M”) or benign (represented by “B”). We don’t need to know what these attributes mean: all we need to know is that they are measurements of the tumors, and that benign and malignant tumors tend to have different attribute values. For these 10 tumor attributes when comparing to the midpoint values, higher numbers indicate malignancy. Pictorially, the list of dictionaries looks like this (two are shown, but the list contains many more than that): dict ID 897880 radius 10.05 texture 17.53 perimeter 64.41 area 310.8 smoothness 0.1007 compactness 0.07326 concavity 0.02511 concave 0.01775 symmetry 0.189 fractal 0.06331 class B list . . . training_set dict ID 89812 radius 23.51 texture 24.27 perimeter 155.1 area 1747 smoothness 0.1069 compactness 0.1283 concavity 0.2308 concave 0.141 symmetry 0.1797 fractal 0.05506 class M Figure 1: Illustration of the data layout of the training set returned by make training set The dictionary stored in the 0th spot in the list gives the attributes for the 0th tumor: training_set[0][“class”] gives the true class label (in this case, ”B” for benign) of the 0th tumor. 4 Getting Started Download the skeleton code (cancer_classifier.py), training set (cancerTrainingData.txt), and the test set (cancerTestingData.txt). Make sure all three files are in the same directory, or the main program will not be able to load the data from the files. 5 Tasks 5.0 Overview Training and evaluating our classifier involves several steps. The first task, which has been done for you, is to write code to load the training and test data sets from text files into lists of dictionaries representing patient records, as described in the previous section. The functions make_training_set and make_test_set are included in the skeleton code to complete these steps. You will complete the following four tasks: • TODO 1: Train the classifier • TODO 2: Apply the classifier to the test set • TODO 3: Calculate and report accuracy on the test set • TODO 4: Provide classifier details on user-specified patients The main program has been provided to you: you will be implementing functions that are called from the main program at the bottom of the skeleton code file. Take a moment to read through and understand the main program (notice that the parts of the program that use TODOs 1–4 are commented out). Each of the above steps is described in detail in the remainder of this section. After you finish each TODO (2 and 3 are completed together), uncomment the corresponding block in the main program and run your code to make sure your output matches the sample output provided below. 5.1 TODO 1: Train the classifier A classifier is simply some model of a problem that allows us to make predictions about new records. We use the training set to build up a simple model, as described in Section 2: • For all malignant records, calculate the average value of each attribute. • For all benign records, calculate the average value of each attribute. • Calculate the midpoint between these averages for each attribute. Our classifier is a single dictionary that stores this midpoint value for each attribute. Implement this functionality in train_classifier. My solution for this part totals roughly 30 lines of code. As always, you may find it useful to write helper methods that perform smaller tasks: for example, you could create a helper function to initialize a dictionary with each of the attributes as keys and 0 as values. When done, uncomment the block of code in the main program that calls train_classifier and debug your code until your attribute midpoints match the sample output. 5.2 TODO 2: Apply the classifier After computing the classifier (namely, the dictionary of attribute midpoints), we can use these values to make predictions given the attribute values of a new patient. A record is classified as follows: For each attribute, determine whether the record’s value is less than or equal to the classifier’s midpoint value. If so, cast one vote for Benign; otherwise, cast one vote for Malignant. If the votes for Malignant are greater than or equal to the votes for Benign, the record is classified as Malignant; otherwise, it is classified as Benign. Implement this classification scheme in the classify function, applying it to each record in the test set. Notice that the prediction for a record is to be stored in the “prediction” field of the dictionary for that record. 5.3 TODO 3: Report accuracy For each record in the test set, compare the predicted class to the actual class. Print out the percentage of records that were labeled correctly (i.e., the predicted class is the same as the true class). 5.4 TODO 4: Provide patient details The final task is to provide a user the opportunity to examine the details of the predictions made for individual patients. Implement check_patients, which contains commented pseudocode describing its the exact behavior. You are strongly encouraged to write helper functions that are called from within this function: if a pseudocode step requires more than a few lines of code, consider making a helper function to accomplish that step. If the user-specified patient ID is found in the test set, print a table with four columns: • Attribute: the name of the attribute • Patient: the patient’s value for that attribute • Classifier: the classifier’s threshold (midpoint) for that attribute • Vote: the vote cast by the classifier on for that attribute See the sample output for specifics of what the table should look like. Printing a table of results with nice even columns and uniformly formatted decimal numbers requires delving into the details of string formatting in Python. There are multiple ways to do this, but the following tips should be sufficient1 : • String objects have rjust and ljust methods, which return a copy of the string padded to the given width, justified either right or left. For example, “abc”.rjust(5) returns ” abc”. • Floating point numbers can be formatted nicely using the format method, which is called on strings containing special formatting specifiers. For example, “{:.2f}”.format(8.632) formats the argument (8.632) as a float with 2 decimal places, resulting in the string “8.63”. Your table does not need to match the sample output character for character, but your columns should be lined up, right justified, and floating-point values should be printed with the decimals aligned and a consistent number of digits following the decimal point. 6 Sample Output A sample run of my solution program is shown below. User input is bolded. Reading in training data… Done reading training data. Reading in test data… Done reading test data. Training classifier… Classifier cutoffs: radius: 14.545393772893773 texture: 19.279093406593404 perimeter: 94.91928571428579 area: 693.337728937729 smoothness: 0.09783294871794869 compactness: 0.1104729532967033 concavity: 0.09963735815018318 concave: 0.054678068681318664 symmetry: 0.18456510989010982 fractal: 0.06286657967032966 Done training classifier. Making predictions and reporting accuracy Classifier accuracy: 92.20779220779221 1For much more detail on string formatting, see the Python Tutorial entry: https://docs.python.org/3/ tutorial/inputoutput.html Done classifying. Enter a patient ID to see classification details: 897880 Attribute Patient Classifier Vote radius 10.0500 14.5454 Benign texture 17.5300 19.2791 Benign perimeter 64.4100 94.9193 Benign area 310.8000 693.3377 Benign smoothness 0.1007 0.0978 Malignant compactness 0.0733 0.1105 Benign concavity 0.0251 0.0996 Benign concave 0.0177 0.0547 Benign symmetry 0.1890 0.1846 Malignant fractal 0.0633 0.0629 Malignant Classifier’s diagnosis: Benign Enter a patient ID to see classification details: 89812 Attribute Patient Classifier Vote radius 23.5100 14.5454 Malignant texture 24.2700 19.2791 Malignant perimeter 155.1000 94.9193 Malignant area 1747.0000 693.3377 Malignant smoothness 0.1069 0.0978 Malignant compactness 0.1283 0.1105 Malignant concavity 0.2308 0.0996 Malignant concave 0.1410 0.0547 Malignant symmetry 0.1797 0.1846 Benign fractal 0.0551 0.0629 Benign Classifier’s diagnosis: Malignant Enter a patient ID to see classification details: quit 7 Hints and Guidelines • Start by reading through the skeleton code, and making sure you know what the main program does and how the functions you are tasked with implementing fit into the overall program. • If your understanding of lists and dictionaries is shaky, you will have great difficulty making progress. Visit my office hours, TA office hours, or mentor hours early so you don’t spend too much time struggling. • The top of the skeleton file has a global variable called ATTRS, which is a list of the attribute names each patient record has. Using global variables with all-caps names is a common convention when you have variables that need to be referenced all over your program and (crucially) never change value. You may refer to ATTRS from anywhere in your program, including inside function definitions, without passing it in as a parameter. • As in A4, all variables (other than ATTRS) referenced from within functions must be local variables – if you need access to information from outside the function, it must be passed into the function as a parameter. • When iterating over patient record dictionaries, use loops over the keys stored in ATTRS rather than looping directly over the dictionary’s keys. An example of this appears in the main program where the classifier cutoffs are printed. • The functions provided in the skeleton code include headers and specifications. Make sure you follow the given specifications (and don’t modify them!). • Keep the length of each function short: if you’re writing a function that takes more than about 30 lines of code (not including comments and whitespace), consider how you might break the task into smaller pieces and implement each piece using a helper function. • All helper functions you write must have docstrings with precise, clearly written specifications. • Test each function after you’ve written it by running the main program with the corresponding code block uncommented. Don’t move on until the corresponding portion of the output matches the sample. Submission Upload cancer_classifier.py to Canvas and fill in the A5 Hours quiz with an estimate of how many hours you spent working on this assignment. Rubric Submission Mechanics (2 points) File called cancer_classifier.py is submitted to Canvas 2 Code Style and Clarity (28 points) Comment at the top with author/date/description 3 Comments throughout code clarify any nontrivial code sections 5 Variable and function names are descriptive 5 Helper functions are used to keep functions no longer than about 30 lines of code (not counting comments and blank lines) 5 ATTRS is used to iterate over dictionary attributes 5 No global variables except ATTRS are referenced from within functions 5 Correctness (70 points) The trained classifier has the correct midpoint values for each attribute 30 Prediction is performed as described using the midpoints computed in training 5 Accuracy is computed and reported correctly as shown in the demo output 10 User is repeatedly prompted for Patient ID 5 Message is printed if given ID is not in the test set. 5 If ID is in the test set, table is printed with all four columns and rows for all 10 attributes 10 Table columns are right-justified and aligned 3 Floating-point values in the table are lined up on the decimal point and have a fixed number of digits after the decimal. 2 Total 100 points Acknowledgements This assignment was adapted from a version used by Perry Fizzano, who adapted it from an original assignment developed at Michigan State University for their CSE 231 course. 8 Challenge Problem The following challenge problem is worth up to 10 points of extra credit. As usual, this can be done using only material we’ve learned in class, but it’s much more open-ended. If you are trying to tackle this, feel free to come talk to me about it in office hours. In this assignment, you trained a simple classifier that used means over the entire training set to classify unseen examples. This simple classifier does quite well (92% accuracy) on the test set. There are many more sophisticated methods for learning classifiers from training data, some of which depend on some pretty heavy-duty mathematical derivations. One type of classifier that doesn’t require a lot of math but nonetheless performs pretty well on a lot of real-world problems is called the Nearest Neighbor Classifier or its more general cousin, the K Nearest Neighbors Classifier. The idea behind KNN is that records with similar attributes should have similar labels. So a reasonable way to guess the label of a previously-unseen record is to find the record from the training set that is most similar to it and guess that record’s label. To implement a nearest neighbor classifier, we need some definition of what it means to be ”near”. One of the the simplest choices for numerical data like ours is the Sum of Squared Differences metric. Given two records, compute the difference between the two records’ values, square the difference, and add up all the squared differences over all 10 attributes. The smaller the SSD metric, the more similar the two records are. (up to 5 points) Implement a nearest neighbor classifier using the SSD metric in a file called KNN.py. Feel free to copy and re-use the data loading functions, and any other functions that remain relevant, from cancer_classifier.py. Evaluate your classifier’s accuracy like we did in the base assignment. Write a comment in KNN.py reporting your classifier’s performance. You might notice an issue with the SSD metric applied to our dataset: some attributes have huge values (e.g., in the hundreds) and others have tiny values. When computing SSD, the large-valued attributes will dominate the SSD score, even if they aren’t the most important attributes. Come up with a way to modify the distance metric so that it weights attributes evenly. Describe your approach and compare the performance of your new metric with SSD in a comment in KNN.py. (up to 5 points) The nearest neighbor classifier can be a bit fiddly, because the guess depends on a single datapoint in your training set, so a single unusual (or mislabeled!) training record could cause a wrong prediction. A more robust classifier looks not just at the single nearest neighbor, but each of K nearest neighbors, for some choice of K. Generalize your nearest neighbor classifier to a KNN classifier. Try out different values of K and include a comment discussing the classification accuracy for values of K. Do any of them beat the base assignment classifier’s performance?
1 Overview For this assignment you will write a Python program that draws a Sierpinski Triangle using a method called a chaos game. The chaos game is played as follows. The user chooses the window size (say 300 by 300 pixels). Denote the three corners of an isosceles triangle 1, 2, 3, where corner 1 is at the top center of the screen, corner 2 is in the lower left of the screen, and corner 3 is in the lower right of the screen. Here’s some pseudocode to help you understand how the chaos game works: Let p be a random point in the window loop 10000 times: c = a random corner of the triangle m = the midpoint between p and c choose a color for m color the pixel at m p = m This process will generate a Sierpinski Triangle like the one pictured below. 2 Details 1. One thing you might notice if you try this on paper (or if you carefully look at the image you generate once it’s complete) is that the first few iterations of this game may produce points that are not actually part of the Sierpinski triangle. Thus, you should start the process of generating points, but don’t color the first few points you calculate. To be safe you should start adding points to the image after 10 iterations. 2. You are provided with a skeleton code file called sierpinski.py. This file contains some code to help get you started, including a function that sets up the Turtle graphics window for our somewhat nontraditional turtle use case. In particular, take a look at the specification for the turtle_setup function: this takes care of creating a turtle, and resizing the window to the desired dimensions. Call this before beginning the chaos game iterations, and use the turtle it returns to do all your pixel coloring. 3. The setup function changes the window so its coordinate system now has (0,0) at the bottom left corner, with positive x going right and positive y going up, so the top left corner is at (0, canv_height),the bottom right corner is at (canv_width, 0), and the top right is at (canv_width, canv_height). This helps to simplify the math when locating corners of the triangle. The setup function also calls tracer(0, 0), which you may recall disables automatic re-drawing of the canvas. This means that to get your picture to show up, you need to call turtle.update() yourself. For the sake of speed, I recommend re-drawing the picture only every 100 or every 1000 iterations so the drawing doesn’t take too long. 4. In this program, we’re not really using turtles for what they were meant for. Instead of drawing lines as the turtle moves, we’ll use the turtle to color individual pixels on the canvas. Turtles draw as they move, but they can also draw shapes, such as circles and dots; we’ll make use of the aptly named dot method. To fill in a pixel, all you need to do is move the turtle to that pixel, then draw a dot of size 1. 5. When the turtle draws via movement with the pen down, or via other methods such as dot, the color it draws is determined by the turtle’s current color. You can change the turtle’s current color using the (again, aptly named) color method. One way to specify colors is using various standard color names (“red”, “green”, “purple”, etc.). A more flexible way is to specify how much red, green, and blue you want: some combination of these three primary colors can represent all colors that your screen can display. When storing images on computers, we typically store each R,G, and B value using a single byte (8 bits). That means a color is represented by three numbers from 0 to 255, which is the maximum number representable using 8 bits. For instance (255, 0, 0) is red, (0, 255, 0) is green and (0, 0, 255) is blue. Furthermore, (255, 255, 255) is white and (0, 0, 0) is black. 6. In the figure on the first page, you can see that the colors of the pixels are related to their coordinates. If you simply followed the pseudocode at the top of this document, but chose black for the color every time, then you’d have a black and white version of the Sierpinski triangle. That’s a good first step to make sure your chaos procedure is working correctly. Once you have that working, you should figure out how to make the triangle prettier. The color scheme used in the example above chooses each color value based on the distance from one of the corners. In particular, the red color scales from 255 to 0 based on distance from corner 1, the green scales with distance from corner 2, and blue scales with distance from corner 3. You may choose a different scheme, but your colors should appear in a smooth gradient across the triangle, and the corners should each be colored one of the “base” colors (red, green, and blue). This is not too difficult in a square window but you need to be a little more careful in a non-square window (when the width of the window is not equal to the height of the window). 3 Suggested Approach This may seem like a big problem to solve all at once; in fact it is, so it is highly recommended that you write functions to solve small pieces of the problem, then put them together into a solution to the full program. 1. In class we wrote distance and midpoint functions. These will come in handy here, so copy those into your code, and feel free to modify them as needed. 2. I included the pseudocode for the chaos game in the skeleton file. This is a handy way to keep track of your overall program structure: start with pseudocode and piece-by-piece fill in code that accomplishes each of the steps. Because each step has some complexity to it, you should define functions that take care of the details of each step. That way, the code in your main program will end up corresponding fairly closely to the lines of the pseudocode, and it will be easy to understand. 3. Based on the pseudocode, decide what functions you’d like to have in order to make the algorithm easy to implement. In my solution, I have almost one-to-one correspondence between functions and lines in the pseudocode. To give one example, to choose a color for the point m, I have a choose_color function. It takes a point and the three corners and calculates the RGB color values based on distance of the point from each of the colors. This function in turn makes use of the distance function. 4. Instead of immediately starting to code each function you’ve decided to write, try this instead: write out the specification (docstring) for the function. This means deciding what the function takes as arguments and what it returns. Once you have this, try sketching out the code for the chaos game, using the functions (even though you haven’t written them yet!). In doing this, you may discover changes that you want to make to your function specifications—make them now so you don’t have to rewrite the code. 5. Now, go implement each of your functions. Start with the ones that will be needed to draw the triangle in black. After finishing one function, test it. Use the interactive shell and/or put code in your main program that checks whether the code does what you expect it to. For example, to test my choose_color function, I first tried passing in each corner: I made sure the top corner gave me (255, 0, 0) back, and so on for all three corners. Then I tried the bottom middle point on the canvas, because it’s easy for me to calculate that its blue and green values should be about 128 (it’s equidistant from the green corner and the blue corner). Then test the center point – its RGB values should all be equal because it’s equidistant from all three corners. 6. Finally, turn your sketch of the overall chaos game algorithm into real code that uses your functions to draw the Sierpinski triangle. Make sure it works with different square window sizes first (e.g., 200 by 200, 300 by 300). Then try testing it with unequal width and height (e.g., 200 by 300). 4 Hints 1. I defined three variables in my main program that hold the coordinates of the three corners, since the corner coordinates are needed in several places. The functions that do calculations involving corners need to take the relevant corners as parameters. 2. Drawing a black and white triangle is a great first step. You may want to start out simply choosing black as the color for all pixels to ensure the geometry is all working correctly. 3. The distance and midpoint function used tuples to pack the coordinates of points together into a single argument / return value. This is a design decision, and you may choose to use this approach in your functions or not. For example, my function that colors a certain pixel a given color has the following header: color_pixel(turt, point, color) where point is expected to be a 2-tuple point = (x, y), and color = (r, g, b) is a 3-tuple of the RGB color values. I could also have written it color_pixel(turt, px, py, r, g, b) but I think it’s cleaner to pass points and colors to functions as tuples. 4. How solidly filled in your triangle is depends on how many iterations of the chaos game you run and how large your canvas is. A smaller canvas has fewer pixels to fill in, so fewer iterations will make a more solid picture, but it will have lower resolution. A large picture requires more iterations but has higher definition. Feel free to experiment with running more iterations to get larger, higher-definition triangles, but please turn in code that runs 10000 iterations and runs in less than 5 seconds. To keep things fast, remember that you can choose how often to call turtle.update(); for maximum speed, call it once after all your iterations are complete. The images below show what you can expect your drawing to look like with 10000 iterations for a few different canvas sizes. Here’s a 200×200 output: Here’s a 100×300 output: Here’s a 200×100 output: 5 Guidelines Please make sure your program follows these guidelines: • Your code should run 10000 iterations of the chaos game and run in under 5 seconds. • Your functions should not directly make use of (refer to) any global variables. Any information a function needs to do its job should be passed into the function as a parameter. • Your code should do all the drawing (i.e., color all pixels) with the Turtle object returned by the setup function. Don’t create any additional turtles. • Each of your functions, and the main program, should not be too long. Not counting comments, docstrings, and blank lines, my main program (the part in the if __name__ == “__main__”: block) is just under 20 lines and each of my functions is less than 10 lines. If you find yourself writing a continuous block of code that’s longer than about 30 lines (not counting comments and blank lines), think about how you could break it up into logical subtasks and write functions to accomplish each one. • Your functions and variable names should be descriptive but not overly long. For example, your corner 1 variable should probably not be called c1, nor should it be called the_top_middle_corner_of_the_triangle. Somewhere in between is best. Submission Take a screenshot of the drawing produced on a canvas with width = 300, height = 120, and name it triangle.png. Zip both files into a zip file called a4.zip and submit it to the A4 Code assignment on Canvas. As usual, please fill out the A4 Hours survey with an estimate of the hours you spent on this assignment. Rubric Submission Mechanics (10 points) You submitted a zip file called a4.zip containing sierpinsky.py. 1 Your zip file also includes triangle.png, a screenshot of your program’s result on a 300×120 canvas. 4 Your sierpinski.py program runs in under 5 seconds. 4 sierpinski.py contains comments including your name, date, and description at the top 1 Code Style and Clarity (36 points) Your program defines at least two additional functions beyond the provided setup, distance, and midpoint functions. 10 Each function you introduce has a docstring containing a clear function specification. 8 Your functions do not make use of any global variables. 6 The main program and each individual function is not excessively long. 6 The names of functions and variable names are descriptive but not too verbose. 6 Correctness (34 points) The triangle is drawn correctly for a square window 10 The triangle is drawn correctly for a non-square window 10 The first ten points generated are not added to the image. 4 Each corner is colored one of red, green and blue as described above 5 The colors gradually blend according to their distance from each corner 5 Total 80 points 6 Challenge Problem Take a look at the following web page: http://mathworld.wolfram.com/ChaosGame.html. There you can see how what we’re doing here is just one specific case of a general idea. The general idea is you can have triangles, squares, pentagons, hexagons, etc. And you when you choose a random corner and find the midpoint you could instead find the point that is 1/3 of the way to the corner, or 3/8 of the way to the corner, etc.Make a copy of your main assignment program in a file named chaos.py. In this file, implement the following function: def chaos_game(canv_width, canv_height, poly_sides, ratio): “”” Run a chaos game on a canvas with size (canv_width, canv_height) with n = poly_sides (i.e., a poly_sides-sided polygon) and r = ratio (i.e., fraction of distance from the corner) “”” This challenge may require usage of material we haven’t covered in detail (for example, lists will likely come in handy to store the corners of the polygon). If you are trying to tackle this and encounter any problems, come talk to me and I’d be happy to help. Successful completion of the challenge problem is worth 5 points of extra credit. Submit chaos.py to the A4 Challenge assignment on Canvas.
Guessing Game: 32 points Assume you are a computer programmer working for a company, Nostalgia-R-Us, that makes legacy (old-style, text-only) games for people who were using computers in the early 1980s. The game you have been tasked to write is a simple guessing game. A player specifies how many tries are allowed, and then proceeds to guess a secret two-character sequence. Because the game is intended for distribution to alumni of Western Washington University, the letters are selected from the letters in the word bellingham. See the sample screen shots in Figure 1 for sample gameplay. Figure 1: Two sample runs of the program 1 Your manager has provided you with the following requirements and/or pseudocode: • Your program must be named letterGuessGame.py. • The program should provide a brief blurb that explains the game and prompts the player to specify the number of tries. • Two letters from the word bellingham should be chosen randomly as the secret answer. Because the letters are chosen independently, both the first and second secret letters may be the same. • While the player has tries remaining, the game should prompt the user to guess a letter. For each of the two secret letters, the program should specify whether the guess was correct or not. If the guess is not one (or neither) of the secret letters, then the program should output a statement stating that fact. • The program should remember which letter(s) (if any) have already been guessed correctly. Once a letter has been guessed correctly, subsequent output should not mention that letter. • If the player guesses both letters, the game should output ”You win” and terminate right away, even if the player has tries remaining. • If the player does not correctly guess the secret letters in the number of tries indicated, the game should end, specify that there are no more tries remaining, and the correct answer should be revealed. This game can be implemented many different ways. Declare and use as many variables as you need to keep track of guesses. The logic for a sample ”you lose” game play is shown below. Num Guesses : 4 Secret Answer : bh User Guess 1 : b Game Response : You have guessed the first leter. The second letter is not b. User Guess 2 : g Game Response : The second letter is not g. User Guess 3 : l Game Response : The second letter is not l. User Guess 4 : e Game Response : You are out of tries. Game over. The secret letters were b and h. 2.1 Testing Test your program thoroughly. Make sure it works correctly for a ”win” and a ”lose” scenario, noting that a player can win after a minimum of 1 attempt (if both letters are the same and the player guesses them on the first try) but can also win in more than that, up to (and including) the maximum number of attempts specified. 2 Submission Upload letterGuessGame.py to Canvas. Rubric Canvas (written) questions 18 points Top of python file contains comments, including your name 1 The program correctly prompts for the number of tries 2 The program selects two random characters from the letters in bellingham 4 The program correctly keeps track of how many tries are remaining 4 The program specifies which (if any) of the secret letters have been guessed correctly after each guess 4 If one of the two letters has been guessed correctly, on subsequent guesses, the program does not mention the already-guessed letter 5 The program terminates right away and says ”Win” if the player guesses correctly. If the player loses, the answer is revealed. 5 The program runs as intended, and does not generate errors 5 The code is commented adequately and variable names are appropriately named 2 Total 50 points 3 Challenge Problem This challenge problem is worth two points of extra credit: Write a program that prompts the user for a non-negative decimal number, then prints the binary representation of the number with no leading zeros. Submit your Challenge Problem solution in a file named binary.py to the A3 Challenge (NOT A3 Code) assignment on Canvas.
Programming Task: 20 points Congratulations! You’ve just been hired as a Python programmer at an education start-up company. Your first task is to develop a prototype of a program that kindergarten students will use to check their homework assignments which involve addition, multiplication, and division problems. Program Specification The program begins with a series of prompts, then prints a few lines to the screen in response. In total there are 6 lines that are printed each time the program is run: 1 1. Prompt the user for their name 2. Greet the user and ask them to supply the first integer 3. Prompt the user for a second integer 4. Output the sum of the two numbers 5. Output the product of the two numbers 6. Rephrase the division question, and output the whole number and remainder. All numerical outputs on the 6th line of output must be integers (whole numbers, without decimals). A sample invocation of the program is shown in Figure 1: Figure 1: Sample Output Although this is a simple set of steps, there are many, many different Python programs that can achieve it. The text of your prompts does not need to match the example exactly. However, your solution must follow the the instructions above exactly as specified. For example: • Both the greeting and the prompt for the first number must be printed on the second line of output. • The last (6th) line of output must rephrase the division question and output the whole number and remainder portions of the calculation on a single line. Valid Input and Error Checking You should assume that the user provides all requested inputs (via the keyboard) as instructed, and assume that all integers are positive numbers. Your program is not required to check the input or behave in any specific way if the above conditions are not met. Testing Your Program Testing is a major component in the process of writing software. Often, testing (detecting errors) and debugging (locating and fixing errors) takes way more effort than writing the code did in the first place. We’ll talk more about testing as the quarter progresses; in the meantime, the following table provides some helpful test cases that you can use to see if your program is working correctly. Try your code out with the given pairs of integers and see if your output matches the sum, product, and division result. 2 First Integer Second Integer Sum Product Division 7 5 12 35 1 remainder 2 5 7 12 35 0 remainder 5 3 3 6 9 1 remainder 0 1 678 679 678 0 remainder 1 8364724 9738 8374462 81455682312 858 remainder 9520 Submission Double check that your program works according to the specification. Take a look through the rubric below and make sure you won’t lose points for reasons that could easily be foreseen and fixed. When you’re finished, submit your program to Canvas as a single .py file named arithmetic.py. Finally, fill out the A1 Hours quiz with an estimate of the number of hours you spent on A1 (include both the written and programming portions in your estimate). Rubric Canvas questions 16 points Author, date, and program description given in comments at the top of the file 1 point Program prompts for user’s name on the first line 4 points Greeting on second line includes user’s name 4 points First integer prompt also appears on second line 2 points Correct sum output on fourth line 2 points Correct product output on fifth line 2 points Division question is rephrased, quotient and remainder are printed on sixth line 3 points Code is commented adequately and variables are appropriately named 2 points Total 36 points 3 3 Optional Challenge Problem Some assignments will come with an optional challenge problem. In general, these problems will be worth very small amounts of extra credit: this one is worth one point. Though the grade payoff is small, you may find them interesting to work on and test your skills in Python and algorithm development. The skills and knowledge needed to solve these problems are not intended to go beyond those needed for the base assignment, but less guidance is provided and more decisions are left up to you. The A1 challenge problem is as follows: Many online real estate websites have mortgage calculator features1 . These calculators ask for some information, such as the price of a home, the down payment (amount of the home price you’d pay up front), and the interest rate, then calculate the amount you’d have to pay monthly on a loan for the home. According to NerdWallet2 , the formula used to calculate the monthly payment based on these inputs is as follows: M = (P − D) r(1 + r) N (1 + r)N − 1 Where: M = The monthly payment P = The price of the home D = The down payment amount N = The number of months over which the loan will be paid off r = R/12, the monthly interest rate, which is the yearly rate divided by 12 Write a program that asks the user to enter P, D, N, and R, then outputs the monthly payment amount M. Notice that you will prompt the user for R, the annual interest rate, but the formula uses r, the monthly interest rate. 3.1 Submission Upload your submission to Canvas in a file called challenge.py. 1See https://www.zillow.com/mortgage-calculator/ for an example 2Go to https://www.nerdwallet.com/mortgages/mortgage-calculator/calculate-mortgage-payment and click “How to calculate your mortgage payment” for the source of the formula