CS106A Midterm + Solutions

Stanford, Winter 2022-23

Instructions

1. Short Answer (6 points)

a. By each ???, write what value comes from the Python expression:

>>> 5 + 2 * 4 - 1 - 5
???


>>> 86 % 5
???


>>> s = 'Winter'
>>> s[3]
???


>>> s[3:]
???


b. What 3 numbers print when the caller() function runs? This code runs without error.

def foo(a, b):
    a = a + 1
    b = b + 1
    return a + b


def caller():
    a = 2
    b = 3
    c = foo(b, 1)
    print(a, b, c)
# What 3 numbers print ???

2. Bit (6 points)

Bit is on the ground facing the right side of the world, which may be any size. Move bit forward until a hole appears below. Move bit down to the bottom of the hole, leaving bit facing down. While moving down the hole, paint the first moved-to square blue, leave the next square blank, the next square blue, the next square blank, and so on (see the before/after picture below).

Bit before and after:
alt: bit before and after

def blue_down(filename):
    bit = Bit(filename)
    # Your code here

3. Image (20 points)

Given an image filename and int n which is 1 or more. Produce a new out image with three features: (1) a blank stripe which is always 10 pixels wide running down the left side of the out image. (2) to the right of the stripe, a yellow rectangle n pixels wide and 2 * n pixels high. (3) below and to the right of the rectangle, a horizontally flipped copy of the original image. Much of code for the function is provided below, with spaces (a) (b) (c), described below, where you add your code.

alt: blank stripe, yellow rect, flipped image

a. Write one line of code to create the out image.

b. 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.

c. Write the loops and other needed code to write the yellow rectangle. These are separate loops, not nested inside the earlier loops for (b). You can make yellow by setting the blue value to 0. We'll assume there is a return out as the last line.

def do_image(filename, n):
    image = SimpleImage(filename)
    #### a. Create "out" image (Your one-line here)


    # Write flipped image to out
    for y in range(image.height):
        for x in range(image.width):
            pixel = image.get_pixel(x, y)
            #### b. Set "pixel_out" (Your one-line here)


            pixel_out.red = pixel.red
            pixel_out.green = pixel.green
            pixel_out.blue = pixel.blue

    #### c. Write yellow rectangle
    # (Your code here)

4. Strings (24 points)

a. Given a string s, return a new string made of all the chars from s which are digits or the letter 'e' (case sensitive). (To make more room for writing, the examples here are on the left with space for the def/code on the right.)

'Eb12ex5e' -> '12e5e' |  def digit_e(s):
'a77a' -> '77'        |
'xyz' -> ''           |





b. Given a string s, return the index number of the first alphabetic char in s, closest to the start of the string, or -1 if there is no alphabetic char in s.

'##ab77' -> 2    |  def first_alpha(s):
'E77z' -> 0      |       
'#123' -> -1     |





c. Given a string s that is guaranteed to contain exactly one pair of at-signs '@@' and exactly one pair of up-hats '^^'. The order of the at and hat pairs varies for each string.

1. If the at is before the hat, return the chars between the two, like this:

'aa@@xy^^bb' -> 'xy'
'x@@^^BBx' -> ''

2. Otherwise, the hat must be before the at. In that case, return the text before the hat, followed by the text after the at, like this:

'aa^^xy@@bb' -> 'aabb'  |  def at_hat(s):
'a^^@@b' -> 'ab'        |






5. Grid Super-Snack (24 points)

This problem has two parts, and you can get full credit for each part regardless of what you did on the other part. We have a Grid representing Yosemite national park, and every square is either a regular bear 'b', a happy bear 'B', honey 'h', or empty None. The function super_snack(grid, x, y, n) will be called with an in-bounds x, y, and then must check the following conditions:

1. There must be a regular bear at x, y

2. There must be honey 1 square to the right, and exactly n squares down from the bear. The parameter n will be an int which is 0 or more. For example, if n is 0, the honey would be in the same row as the bear, if n is 1, the honey would be in the row immediately below the bear, and so on.

3. If the conditions are met, then the function should remove the honey (set its square to None) and change the bear to a happy bear (set its square to 'B').

If the conditions are not met, the function should leave the grid unchanged. In all cases, the function should return the grid.

def super_snack(grid, x, y, n):















b. Write a Doctest for a call to super_snack() where a bear successfully eats a honey. Use a grid at least as large as the 3-by-2 grid in the example below. As a reminder of the syntax, here is a working Doctest from the movie scroll_left() lecture example which shifts each letter one square to the left.

>>> grid = Grid.build([['a', 'b', 'c'], ['d', None, None]])
>>> scroll_left(grid)
[['b', 'c', None], [None, None, None]]

# super_snack() Doctest:


6. Heart Encryption (20 points)

This problem uses an encryption scheme somewhat like the homework, however it works with both digits and alphabetic chars. As a simplification, all text in the inputs, outputs, and lists for this problem will use non-uppercase chars. The encryption uses 3 lists of chars, like the following (for simplicity, the example shows the alphabetic chars 'a'-'d' instead of 'a'-'z'):

source = ['a', 'b', 'c', 'd']
slug_d = ['7', '5', '4', '0', '1', '3', '9', '8', '2', '6']
slug_a = ['♥', '♥', '♥', 'c', 'd', 'b', 'a']
indexes    0    1    2    3    4    5    6    7    8    9

Encrypt a char with the following algorithm, and the slug lists will be the appropriate length for this algorithm.

1. If the char is a digit, then use that number as the index in slug_d to get the encrypted form. So for example, the encrypted form of '2' is '4', since '4' is at index 2 in the list.

2. If the char is not a digit and appears in the source list, then its encrypted form is found in the slug_a list. However, exactly 3 heart emoji chars '♥' have been inserted at the beginning of slug_a, and the encryption should skip over these. For example, with the lists shown above, the encrypted form of 'a' is 'c', and the encrypted form of 'b' is 'd'.

3. If a char is not a digit and not in the source, then it should be returned unchanged.

# Examples using above 3 lists:
'2' -> '4'
'5' -> '3'
'a' -> 'c'
'b' -> 'd'
'd' -> 'a'
'$' -> '$'
def encrypt_char(source, slug_d, slug_a, ch):
    # Your code here
    

Solutions



#### 1

7
1
t
ter

2 3 6


#### 2

def blue_down(filename):
    bit = Bit(filename)
    while not bit.right_clear():
        bit.move()
    bit.right()
    while bit.front_clear():
        bit.move()
        bit.paint('blue')
        if bit.front_clear():
            bit.move()


#### 3

# out image
out = SimpleImage.blank(image.width + 10 + n, image.height + 2 * n)

# reversed image
pixel_out = out.get_pixel(out.width - 1 - x, 2 * n + y)
# or
pixel_out = out.get_pixel(10 + n + image.width - 1 - x, 2 * n + y)

# yellow rectangle
for y in range(2 * n)
    for x in range(n):
        out_pix = out.get_pixel(10 + x, y)
        out_pix.blue = 0

#### 4

def digit_e(s):
    result = ''
    for ch in s:
        if ch.isdigit() or ch == 'e':
            result += ch
    return result


def first_alpha(s):
    for i in range(len(s)):
        if s[i].isalpha():
            return i
    return -1


def at_hat(s):
    at = s.find('@@')
    hat = s.find('^^')
    if at < hat:
        return s[at + 2:hat]
    pre = s[:hat]  # hat left of at
    post = s[at + 2:]
    return pre + post


#### 5

# Here doing if/return for the not-work cases
# but other forms can work too

def super_snack(grid, x, y, n):
    # No bear - nope
    if grid.get(x, y) != 'b':
        return grid

    # Out of bounds - nope
    if not grind.in_bounds(x + 1, y + n):
        return grid

    # No honey - nope
    if grid.get(x + 1, y + n) != 'h':
        return grid

    # Ok do it
    grid.set(x + 1, y + n, None)
    grid.set(x, y, 'B')
    return grid


# here bear in first row, honey one row down
>>> grid = Grid.build([[None, 'b', None], [None, None, 'h']]);
>>> super_snack(grid, 1, 0, 1)
[[[None, 'B', None], [None, None, None]]

# Some students interpreted the question that there were
# two honey - one to the right and one n down. Not our
# intention but reasonable, so solutions could get full credit
# that way so long as the code worked.


#### 6

def encrypt_char(source, slug_d, slug_a, ch):
    if ch.isdigit():
        idx = int(ch)   # need int()
        return slug_d[idx]
    if ch in source:
        idx = source.index(ch)
        return slug_a[idx + 3]  # need + 3
    return ch