Stanford, Winter 2024-25
This was quite a challenging exam, and we were pleased with how well the class did overall. The median was 86/100.
# CS106A Exam Reference Reminder # [square brackets] denote functions listed here that we have not used yet # Exam questions will not depend on functions we have not used yet Bit: bit = Bit(filename) bit.front_clear() bit.left_clear() bit.right_clear() bit.get_color() bit.move() bit.left() bit.right() bit.paint('red') [bit.erase()] General functions: len() int() str() range() [list() sorted()] String functions: isalpha() isdigit() isspace() isupper() islower() find() upper() lower() strip() List functions: append() index() [extend() pop() insert()] SimpleImage: # read filename image = SimpleImage(filename) # create blank image image = SimpleImage.blank(width, height) # foreach loop for pixel in image: # range/y/x loop for y in range(image.height): for x in range(image.width): pixel = image.get_pixel(x, y) Grid 2D: grid = Grid.build([['row', '0'], ['row', '1']]) grid.width, grid.height - properties grid.in_bounds(x, y) - True if in bounds grid.get(x, y) - returns contents at that x,y, or None if empty grid.set(x, y, value) - sets new value into grid at x,y
a. Write what value comes from the Python expression:
>>> 1 + 2 + 3 * 4 - 1
>>> 24 % 5
>>> 3 ** 2
>>> s = 'Python' >>> s[1:3]
b. What 3 numbers print when the caller() function runs? This code runs without error.
def foo(a, b): a *= 2 b += 1 return a + b def caller(): a = 1 b = 2 c = foo(b, a) print(a, b, c)
# What 3 numbers print?
Bit is in a 1-high tunnel, facing the right side of the world. Move bit forward until an opening appears above, the entrance of a 1-wide vertical hole. Move bit into the hole. Move bit forward until an opening appears towards the left side of the world, the entrance of a second 1-high tunnel. Move bit forward in the tunnel until blocked. Use three while loops.
Bit before and after:
def loop3(filename): bit = Bit(filename) # Your code here
Given an image filename and ints a and b which are 1 or more.
Produce a new out image with three features: (1) a horizontally flipped copy of the original image with the other rectangles around it. (1) two rectangles b pixels high and the same width as the original image, directly above and directly below the flipped image, with the lower rectangle painted aqua. (3) To the left and right of the rectangles and image, two blank vertical stripes, each a pixels wide. The stripes run the full height of the output. Please try to avoid writing too close to the right edge of the paper.
1. Write one line of code to create the out image.
2. Almost all of the code to write the flipped image is provided — looping over the original image, writing the colors at each "pixel" to "pixel_out". Write the one line of code which sets the "pixel_out" variable used by the later lines in this loop. It's ok if you need to put the parameters on multiple lines to make it fit.
3. Write the loops and other needed code to produce the aqua rectangle at the bottom. These are separate loops, not nested inside the earlier loops. To set each white pixel to aqua, the last line in the loop is like pixel_out.red = 0
. We'll assume there is a return out
as the last line.
def do_image(filename, a, b): image = SimpleImage(filename) #### 1. Create "out" image # Write flipped image to out for y in range(image.height): for x in range(image.width): pixel = image.get_pixel(x, y) #### 2. Set "pixel_out" pixel_out.red = pixel.red pixel_out.green = pixel.green pixel_out.blue = pixel.blue #### 3. Fill aqua rectangle
a. Given a string s, return a list containing every alphabetic char in s. Omit all the other chars. So for example 'Ab2$c'
returns ['A', 'b', 'c']
'Ab2$c' -> | def alphas(s): ['A', 'b', 'c'] | '!!z!!z' -> | ['z', 'z'] | '@' -> []
b. Given a string s and an "omit" list of lowercase chars like ['b', 'x', 'a']
. Build and return a version of s, omitting all the chars that appear in the omit list. The logic should not be case-sensitive, so if an 'e'
is in the omit list, then both 'e'
and 'E'
should be omitted from the result.
'Kitten', ['e', 't'] | def without(s, omit): -> 'Kin' | 'Kitten', ['k', 'x' | -> 'itten' | 'KITTEN', ['t', 'i'] -> 'KEN' 'Hi', ['i', 'h', 'x'] -> ''
c. Given a string s and a non-negative int n. (1) If there is a digit at the index 2 * n, then return double the digit number. (2) Otherwise, if the chars at indexes n and 2 * n are both alphabetic, then return the string length 2 made of those chars. Otherwise return the empty string.
'abcd9', 2 -> 18 | def special_n(s, n): 'a12de', 1 -> 4 | 'abcde', 1 -> 'bc' | 'ab5de', 1 -> 10 'abcde', 3 -> ''
d. Find the first '@'
char in s. If it is present, and the 2nd char after the '@'
is a digit, then return the value of that digit squared, e.g. 'abc@x3y'
returns 9
. Otherwise, if the '@'
with 2nd char digit is not there, but the first char in the string is a digit, then return the value of that digit squared. In all other cases, return -1
. Use s.find().
'abc@x3y' -> 9 | def at2(s): 'a@12' -> 4 | 'abc@xy' -> -1 | 'abc@5y' -> -1 | 'abc@' -> -1 '2abc@xx' -> 4 'xabc@xx' -> -1 '' -> -1
e. Given a string s, find the first '##'
in s. Then find a second, non-overlapping '##'
that comes after the first. If there are not two '##'
, return the empty string ''
. Otherwise, consider the substring between the two '##'
, such as the substring '123@ab'
in 'x@##123@ab##xx'
. If there is an '@'
in the substring, then return a version of the substring with the parts before and after the '@'
swapped, so '123@ab'
returns 'ab@123'
. If there is no '@'
in the substring, simply return the substring unchanged. Use s.find() and slices.
'x@##123@ab##xx' | def hash_at(s): -> 'ab@123' | 'x@##Hello##xx' | -> 'Hello' | '##syz#x#' -> '' '12@ab##' -> ''
In this problem, every square is one of these four values: empty None
, squirrel 's'
, nut 'n'
, or tree 't'
. As usual, you can get full credit for each part independently of what you write on the other parts. Write the code for the function downward_squirrel(grid, x, y, n)
assuming the parameters x, y represent an in-bounds square that contains a squirrel, and the parameter n is an int, 1 or greater. Here are the conditions for the downward squirrel action:
1. Consider the square in the same row as the x, y squirrel, and n squares to the left - call this square A. Consider the square in the row immediately below the squirrel and n squares to the right - call this square B.
2. If squares A and B are non-empty and each contain the same value as the other, and the square immediately below the squirrel is empty, then the downward-squirrel action happens: the squirrel moves to the square immediately below.
3. Otherwise, the grid is left unchanged.
def downward_squirrel(grid, x, y, n):
(b) Add the two lines to complete the following Doctest for a call to downward_squirrel() where the action succeeds and the squirrel moves. The first Grid.build() line is provided which builds a small grid suitable for this Doctest.
>>> grid = Grid.build([['t', 's', 's'], ['t', None, 't']]) >>>
This problem resembles the homework encryption, but with some differences. As a simplification, we will not handle uppercase chars. For this encryption, there is an extra shift
list, the same length as the source list, which contains non-negative int values. Here are example lists, with the index numbers shown:
If the input char is in the source, compute the "output" index of the output char as follows: The output index is the sum of the input char's index in the source list plus the number in the shift list at the same index. So for example, for the input char 'b'
, its index is 1, and its shift value is 2, so its output char in the slug is 1 + 2 = 3, e.g. 'e'
. If the output index is too big for the slug, then the output char should be '!'
. If the input char is not in the source, then the output char is the input char unchanged.
Encryption examples using above lists 'a' -> 'y' (0 + 1) 'b' -> 'e' (1 + 2) 'c' -> 'w' (2 + 0) 'd' -> '!' (3 + 4 too big) '$' -> '$'
def encrypt_char(source, shift, slug, ch): # Your code here
#### 1. Short Answer 14 4 9 'yt' 1 2 6 #### 2. Bit def loop3(filename): bit = Bit(filename) # Find the hole to our left while not bit.left_clear(): bit.move() # Into the hole bit.left() bit.move() # Find tunnel while not bit.left_clear(): bit.move() # Face into tunnel and go bit.left() while bit.front_clear(): bit.move() #### 3. Image # 1 out = SimpleImage.blank(image.width + 2 * a, image.height + 2 * b) # 2 flipped image pixel_out = out.get_pixel(a + image.width - 1 - x, b + y) # 3 aqua area for x in range(image.width): for y in range(b): pixel_out = out.get_pixel(a + x, b + image.height + y) pixel_out.red = 0 #### 4. Strings ## a def alphas(s): result = [] for ch in s: if ch.isalpha(): result.append(ch) return result ## b def without(s, omit): result = '' for ch in s: if ch.lower() not in omit: result += ch return result ## c def special_n(s, n): if 2 * n < len(s) and s[2 * n].isdigit(): return int(s[2 * n]) * 2 if 2 * n < len(s) and s[n].isalpha() and s[2 * n].isalpha(): return s[n] + s[2 * n] return '' ## d def at2(s): at = s.find('@') if at + 2 < len(s) and s[at + 2].isdigit(): return int(s[at + 2]) ** 2 if 0 < len(s) and s[0].isdigit(): # check that [0] is in bounds return int(s[0]) ** 2 return -1 ## e def hash_at(s): left = s.find('##') right = s.find('##', left + 2) # + 2 is needed if left == -1 or right == -1: # Actually works without left check return '' mid = s[left + 2:right] # Substring into var is helpful at = mid.find('@') if at != -1: return mid[at + 1:] + '@' + mid[:at] return mid # -or- without var at = s.find('@', left + 2) if at != -1 and at < right: # Subtle: avoid '@' beyond '##' return s[at + 1:right] + '@' + s[left + 2:at] return s[left + 2:right] # Some students had: at = s.find('@') # which gets most of the points, but has a bug with '@' # outside of the hashes. #### 5 Grid def downward_squirrel(grid, x, y, n): # A and B in bounds if grid.in_bounds(x - n, y) and grid.in_bounds(x + n, y + 1): # A and B the same if grid.get(x - n, y) == grid.get(x + n, y + 1): # Below squirrel is empty if grid.get(x, y + 1) == None: grid.set(x, y, None) grid.set(x, y + 1, 's') return grid ## Doctest >>> grid = Grid.build([['t', 's', 's'], ['t', None, 't']]) >>> downward_squirrel(grid, 1, 0, 1) [['t', None, 's']['t', 's', 't']] #### 6 Encrypt Char def encrypt_char(source, shift, slug, ch): if ch in source: idx = source.index(ch) out = idx + shift[idx] # Output index into var if out < len(slug): # Not too big return slug[out] return '!' # Too big return ch