Lecture 40 - Programming Review

Lecture Date: Wednesday, April 27

We’ll do some example programs from previous exams and talk about some of the things you might expect programming-wise on the final. Consider this exam review part 1.

Coding Questions from Fall 2015 Final Exam

Key to Fall 2015 Coding Questions

Starter Code for Rotate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from cImage import *

# Prompt the user for a filename
file_name = 'mtn.gif' #input("Filename?: ")

clockwise = int(input("0 for Clockwise - 1 for Counter Clockwise:  "))

# Open an image
old_image = FileImage(file_name)

# Open a window that is twice the size of the original image
image_window = ImageWin("Image Processing", old_image.width, old_image.height)

# Draw the image on the window
old_image.draw(image_window)

# Create a new, blank image
new_image = EmptyImage(old_image.height, old_image.width)

new_image_window = ImageWin("Rotated", old_image.height, old_image.width)

# For each pixel in the original image...
for row in range(old_image.height):
    for col in range(old_image.width):
        # ... get the original pixel ...
        oldPixel = old_image.getPixel(col, row)

        # ... and draw it in the correct place in the new image!
        # Fill in your code here!

# Draw the new image
new_image.draw(new_image_window)

# Wait for a user to click the window to close the image
image_window.exitOnClick()


Lecture 39 - Image Manipulation

Lecture Date: Monday, April 25

Another day of image algorithms! These are a bit trickier than the last few days…

The algorithms for today are:

  • Edge Detection
  • Image Subtraction

Edge Detection

The edge detection algorithm will show us where the edges of objects are in an image and highlight them. The basic idea is that we can look at every pixel and then see if the pixels next to it are substantially different in intensity. To do this, we will apply a set of convolution matrices called Sobel operators to each pixel. The set consists of two matrices: one that looks for differences on the x axis and one on the y axis.

Masks

The steps of the algorithm are:

  • Convert the original image to grayscale
  • Create an empty image of the same size as the original

Then, for each pixel:

  1. Convolve the pixel with the x_mask, resulting in an int called gX
  2. Convolve the pixel with the y_mask, resulting in an int called gY
  3. Compute the square root of the sum of squares of gX and gY called g
  4. Based on the value of g, assign the corresponding pixel in the new image to black or white

One example would be if g > 175, make the pixel black and otherwise white.

Edge Algorithm Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import cImage
import math

from cImage import *

def convolve(image, pixel_row, pixel_col, kernel):
    k_col_base = pixel_col - 1
    k_row_base = pixel_row - 1

    sum = 0
    for row in range(k_row_base, k_row_base + 3):
        for col in range(k_col_base, k_col_base + 3):
            k_col_index = col - k_col_base
            k_row_index = row - k_row_base

            pixel = image.getPixel(col, row)
            intensity = pixel.getRed()

            sum = sum + intensity * kernel[k_row_index][k_col_index]

    return sum

def grayscale_image(image):
    new_image = EmptyImage(image.width, image.height)

    for row in range(image.height):
        for col in range(image.width):
            old_pixel = image.getPixel(col, row)
            intensity = (old_pixel.getRed() + old_pixel.getGreen() + old_pixel.getBlue()) // 3
            new_pixel = Pixel(intensity, intensity, intensity)
            new_image.setPixel(col, row, new_pixel)

    return new_image

# Open an image
old_image = FileImage('whiteside.gif')

image_window_old = ImageWin("Original", old_image.width, old_image.height)

# Draw the image on the window
old_image.draw(image_window_old)

new_image = EmptyImage(int(old_image.width), int(old_image.height))

image_window_new = ImageWin("Edges", int(old_image.width), int(old_image.height))

new_gray_image = grayscale_image(old_image)

black_pixel = Pixel(0,0,0)
white_pixel = Pixel(256, 256,256)
x_mask = [[-1,-2,-1],[0,0,0],[1,2,1]]
y_mask = [[1,0,-1],[2,0,-2],[1,0,-1]]

for row in range(1,new_gray_image.height -1):
    for col in range(1,new_gray_image.width -1):
        gx = convolve(new_gray_image, row, col, x_mask)
        gy = convolve(new_gray_image, row, col, y_mask)
        g = math.sqrt(gx**2 + gy**2)

        if g > 175:
            new_image.setPixel(col, row, black_pixel)
        else:
            new_image.setPixel(col, row, white_pixel)

new_image.draw(image_window_new)

image_window_new.exitOnClick()
image_window_old.exitOnClick()    

Image Subtraction

Image subtraction shows us the difference between two images, highlighting what has changed. We’ll have to figure out a way to determine the distance between two colors. We can use this to loop over the images.

Version 1

Version 1

Version 2

Version 2

Image Difference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import math
from cImage import *

def distance(pixel_1, pixel_2):
    sum = (pixel_1.getRed() - pixel_2.getRed())**2 + (pixel_1.getBlue() - pixel_2.getBlue())**2 + (pixel_1.getGreen() - pixel_2.getGreen())**2
    return math.sqrt(sum)

def image_difference(image_1, image_2):
    diff_image = EmptyImage(image_1.width, image_1.height)

    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row),image_2.getPixel(col, row) )

            if dist > 20:
                black_pixel = Pixel(0,0,0)
                diff_image.setPixel(col, row, black_pixel)
            else:
                white_pixel = Pixel(256,256,256)
                diff_image.setPixel(col, row, white_pixel)
    return diff_image

image_1 = FileImage('version1.jpg')
image_1_window = ImageWin("Image 1", image_1.width, image_1.height)
image_1.draw(image_1_window)

image_2 = FileImage('version2.jpg')
image_2_window = ImageWin("Image 2", image_2.width, image_2.height)
image_2.draw(image_2_window)

image_diff = image_difference(image_1, image_2)
image_diff_window = ImageWin("Image Diff", image_diff.width, image_diff.height)
image_diff.draw(image_diff_window)

image_1_window.exitOnClick()
image_2_window.exitOnClick()
image_diff_window.exitOnClick()
Image Difference w/ Heatmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import math
from cImage import *

def distance(pixel_1, pixel_2):
    sum = (pixel_1.getRed() - pixel_2.getRed())**2 + (pixel_1.getBlue() - pixel_2.getBlue())**2 + (pixel_1.getGreen() - pixel_2.getGreen())**2
    return math.sqrt(sum)

def get_pixel_from_distance(dist):
    if dist >= 1:
        return Pixel(255,255,255)
    elif dist <= 0:
        return Pixel(0,0,0)
    elif dist > 0.8:
        return Pixel(255,255,int(255*(dist-0.8)/0.2))
    elif dist > 0.5:
        return Pixel(255, int(255 * (dist - 0.5) / 0.3), 0)
    elif dist > 0.2:
        return Pixel(int(255 * (dist - 0.2) / 0.3), 0, int(255 * (dist - 0.5) / 0.3))

    return Pixel(0, 0, int(255 * dist / 0.2))


def image_difference(image_1, image_2):
    diff_image = EmptyImage(image_1.width, image_1.height)

    # figure out what the biggest change is to determine what's "hottest"
    max_distance = 0
    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row),image_2.getPixel(col, row) )
            if dist > max_distance:
                max_distance = dist

    for row in range(image_1.height):
        for col in range(image_1.width):
            dist = distance(image_1.getPixel(col, row), image_2.getPixel(col, row))
            diff_image.setPixel(col, row, get_pixel_from_distance(dist/max_distance))
    return diff_image

image_1 = FileImage('version1.jpg')
image_1_window = ImageWin("Image 1", image_1.width, image_1.height)
image_1.draw(image_1_window)

image_2 = FileImage('version2.jpg')
image_2_window = ImageWin("Image 2", image_2.width, image_2.height)
image_2.draw(image_2_window)

image_diff = image_difference(image_1, image_2)
image_diff_window = ImageWin("Image Diff", image_diff.width, image_diff.height)
image_diff.draw(image_diff_window)

image_1_window.exitOnClick()
image_2_window.exitOnClick()
image_diff_window.exitOnClick()


Final Exam Review Guide

Where and When

Date/Time - Tuesday, May 10, 7:00-10:00 PM (except for those that have been pre-approved for an alternate time)

Locations - You must go to your assigned location!

  • CS 1110 w/ Sherriff - GIL 130
  • CS 1110 w/ Smith - WIL 402
  • CS 1111 w/ Dill - GIL 190

Review Session - Monday, May 9, 12:30-1:30 PM in CHEM 402 -

Conflicts

All conflicts should have been reported to the form posted on Piazza. Contact Prof. Sherriff if you have questions.

What to bring

  • A writing utensil - pen or pencil
  • Your UVa student ID - you will need to show your ID to turn in your final exam

No laptops, calculators, scratch paper, backpacks, books, or anything else should be brought. These items will be left in the back/front of the room if you bring them. It is also highly recommended to dress in layers. It is likely to get quite warm in the room.

Test Specifics

We are writing the test to be 1 ½ times the length of the previous two tests. So, we are writing the test to take 1 ½ hours, but you will have all 3 hours.

The format of the test will be similar to what you have seen, but with basically a few more pages. You can expect similar multiple choice, short answer, code reading, and code writing questions to previous tests.

Major things you can expect:

  • A “long” coding question, one that asks you to solve a problem and will encourage you to use the various tools you’ve picked up this semester
  • Reading and evaluating methods / code snippets
  • Some questions related to material from the first two thirds of the class
  • Some questions specifically about the final third of the class

Things that we will definitely not ask:

  • How to use specific libraries, such as gamebox, cImage, Turtle, beautifulsoup4, etc. without providing the API
  • Chase activities
  • Professor AMAs

Topics

All topics from the previous two tests are fair game. You can find their lists here:

Additional Topics:

Under the Hood

  • Basics of computer hardware - different types of memory and storage and what they do
  • How memory works; the stack and the heap
  • Dynamic vs. Static typing in a programming language
  • What does it mean for code to be “better?” - speed, easier to read, fewer bugs, quicker to write

Gamebox

  • We won’t ask you to code any gamebox/pygame code
  • It would be good to consider some of the basic algorithms used such as taking a moving character and looping over all of the walls/platforms to see if it is touching any of them

Image Manipulation

  • The concept of a picture and pixel as represented in Python (basically, a 2D list of pixels, where a pixel is a single color point)
  • General complexity of most image algorithms we looked at (i.e. a double-for loop, looking at each pixel in the image)
  • General idea of the various image algorithms - how did they work, what is the difference between an algorithm that moves pixels (transposition - like flip) versus one that changes the pixels (transformation - like grayscale)
  • You may have to read and interpret image algorithms on the test, so understand the basics of how code and algorithms we have done works!

Study Hints

Example questions to look at

Coding Questions from Fall 2015 Final Exam

Key to Fall 2015 Coding Questions!

Here are some questions from the Gaddis book that we think are good ones to review with:

  • Chapter 5 (p. 229) - 4, 5, 7, 13
  • Chapter 6 (p. 288) - 1, 4, 5, 10
  • Chapter 7 (p. 334) - 2, 3, 6, 7
  • Chapter 8 (p. 366) - 2, 4, 6, 9
  • Chapter 9 (p. 416) - 3, 4, 5, 7

Remember: You have more time!

Take the time to write out your code/algorithm on scratch paper FIRST! You’ve got the time on the final to really work through the options here and write better (and hopefully easier to read) code. So use it!

Check out the lab code

We will be adding example solutions to past labs - so check the Previous Labs page!

Practice coding on paper

You’ll be writing code on paper. This feels different than writing it in Eclipse. You don’t want to be surprised by how different it feels. Practice writing code by hand.

A few small syntax errors is OK. But if you are really off we will take off points. Try to write correct code.

We’ll give you any imports you might need - so don’t worry about memorizing those.

Try re-solving the POTD and Lab problems on paper without looking at your code or textbook.

You can find more sample problems in Programming Challenges in the textbook. We do not, however, have the answer key to share with you.

Practice reading code

We will show you code and ask you what it does. You won’t be able to have Python run it. Practice thinking through code without running it.

Review the Lectures

Not everything in the book is equally important. Review the lecture notes to see what we emphasized. If you are confused by some point, check the audio. You might want to listen to the audio of the other instructor (the one you didn’t hear in class) so that you can get a different perspective on the material.


Lecture 38 - Image Manipulation

Lecture Date: Friday, April 22

More image manipulation algorithms today!

Our main algorithms for the day will be:

  • Image Negative (see previous day’s lecture notes)
  • Grayscale
  • Resizing
  • Green Screen

Grayscale

The basic idea here to get the overall intensity of the color by adding up the red, green, and blue values and then taking the average. Remember that for a pixel to be gray (or black or white), all three RGB values have to be the same.

1
2
3
4
5
6
# Here we define a method that will take a pixel
# and return a pixel that is the right intensity of gray
def negative_pixel(old_pixel):
    intensity = (old_pixel.getRed() + old_pixel.getGreen() + old_pixel.getBlue()) // 3
    new_pixel = Pixel(intensity, intensity, intensity)
    return new_pixel

Resizing

With resizing, we will either be taking a fraction of the pixels (to make the image smaller) or duplicating pixels (to make the image bigger). We begin by creating a new image at the new size. Then, as we adjust the looping through our original image based on the scaling factor - we either skip pixels to make a smaller image or grab the same pixel multiple times to enlarge it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from cImage import *

# Open an image
old_image = FileImage('rotunda.gif')

image_window_old = ImageWin("Original", old_image.width, old_image.height)

# Draw the image on the window
old_image.draw(image_window_old)

scale = float(input("Scale?: "))

new_image = EmptyImage(int(old_image.width* scale), int(old_image.height* scale))

image_window_new = ImageWin("Scaled", int(old_image.width* scale), int(old_image.height* scale))

for row in range(int(old_image.height*scale)):
    for col in range(int(old_image.width*scale)):
        old_pixel = old_image.getPixel(int(col/scale), int(row/scale))
        new_image.setPixel(col, row, old_pixel)

new_image.draw(image_window_new)

image_window_new.exitOnClick()
image_window_old.exitOnClick()

Green Screen

Take two pictures, one in which the background is completely one solid color that you wouldn’t normally find in a “typical” picture. (This is one reason TV weathermen don’t wear green…) Then, as you loop through both pictures, pick the pixels from the background image if the matching pixel from the foreground image is green. Otherwise, take the pixel from the foreground image. Here are two images we can work with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from cImage import *

def isGreen(greenPixel):
    if greenPixel.getGreen() > greenPixel.getRed() + greenPixel.getBlue():
        return True
    return False

green_image = FileImage('ninja.gif')
background_image = FileImage('mtn.gif')
image_window = ImageWin("Green Screen", green_image.width * 3, green_image.height)
green_image.draw(image_window)
background_image.setPosition(green_image.width + 1, 0)
background_image.draw(image_window)

combined_image = EmptyImage(green_image.width, green_image.height)

for row in range(green_image.height):
    for col in range(green_image.width):
        if isGreen(green_image.getPixel(col, row)):
            new_pixel = background_image.getPixel(col, row)
            combined_image.setPixel(col, row, new_pixel)
        else:
            new_pixel = green_image.getPixel(col, row)
            combined_image.setPixel(col, row, new_pixel)

combined_image.setPosition(background_image.width + green_image.width + 1, 0)
combined_image.draw(image_window)

image_window.exitOnClick()


Lecture 37 - Image Manipulation

Lecture Date: Wednesday, April 20

For the next few days, we are going to look at the algorithms behind some basic image manipulation.

First thing’s first: we need to know how to load in a picture into our Python programs. We will be using a library called cImage that was written at Luther College specifically for use in CS 1 courses.

To get started, download these files and move them into your PyCharm project:

We are going to be working mainly with .gif files. If you would like to use something else (like .png or .jpg), you need to install the pillow Python library. (In PyCharm, open your Preferences/Settings, and use the Project Interpreter screen to install pillow, just like you did with the other libraries we have used.)

Drawing with Pixels

We started our programming journey by learning to draw pictures with the Turtle. But what exactly is a “picture” in the context of a computer program?

In effect, it’s a 2D array of pixels.

Well, what’s a pixel?

A pixel is the smallest display element of a picture. It could be dots on your monitor or TV, or how small an ink jet printer can put a dot on your paper (although we still typically call that “dots”). The pixel specifies what color (or components of colors) should be used to display that particular location in accordance with a color model. “Pixel” is short for “picture element.”

Printers (and paints and crayons…) use a subtractive color model. That is, as you add more color (paint), more light is absorbed. Thus, adding in all the colors makes the color black, as shown in the CMYK model below.

CMYK

However, computer monitors (and all forms of light, like stage lighting) use an additive color model, like RGB.

RGB

So, as we add more and more colored lights, we get closer to white, not black!

In RGB, each of the three primary colors (Red, Green, and Blue) can have a value from 0 to 255. This allows for 16,777,216 colors (in theory)!

For example, (255,0,0) is red. But (128,0,0) is also red. It’s just not a “saturated” or bright as the first red. If all three values of , G, and B are the same, you get some shade of gray (or white or black).

Many pixels also have a fourth value - alpha. That tells the pixel how much to blend with any images behind the one that is currently “on top” and about to be drawn.

How many pixels?

It’s a big question when you buy a new camera. “How many megapixels is this thing?”

For reference:

  • An old, standard TV is about 852 x 480 = 400K pixels
  • A 1080p HD TV is 1920 x 1080 = 2M pixels
  • Many laptop monitors are 1680 x 1050 pixels
  • A “retina” MacBook has 2880 x 1800 pixels
  • An 8 megapixel camera has 3264 x 2448 pixels

So, why does resolution really matter if the monitors can’t display all that information?

cImage

The cImage library we will use has several objects in it that we can use to manipulate pictures:

  • FileImage - creates an image from a file you open
  • EmptyImage - creates a blank image that you can change
  • ImageWin - creates a window you can display an image inside

When you make an image you can use the following to manipulate it:

  • getPixel(col, row) - gets the pixel at that position
  • setPixel(col, row, pixel) - puts a new pixel at that position

See the example code for more examples!

Example Code

Here are some example algorithms:

Flip an Image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from cImage import *

# Open an image
old_image = FileImage('uva.gif')

# Open a window that is twice the size of the original image
my_image_window = ImageWin("Image Processing", old_image.width * 2, old_image.height)

# Draw the image on the window
old_image.draw(my_image_window)

# Create a new, blank image
new_image = EmptyImage(old_image.width, old_image.height)

# For each pixel in the original image...
for row in range(old_image.height):
    for col in range(old_image.width):
        # ... get the original pixel ...
        oldPixel = old_image.getPixel(col, row)

        # ... and draw it in the opposite place in the new image
        new_image.setPixel(old_image.width - col-1, row, oldPixel)

# Make sure to put the new image over to the side the right number of pixels
new_image.setPosition(old_image.width + 1, 0)

# Draw the new image
new_image.draw(my_image_window)

# Wait for a user to click the window to close the image
my_image_window.exitOnClick()
Image Negative
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from cImage import *

# Here we define a method that will take a pixel
# and return a pixel that is "flipped" as far as RGB is concerned
def negative_pixel(old_pixel):
    new_red = 255 - old_pixel.getRed()
    new_green = 255 - old_pixel.getGreen()
    new_blue = 255 - old_pixel.getBlue()
    new_pixel = Pixel(new_red, new_green, new_blue)
    return new_pixel

# Open an image
old_image = FileImage('uva.gif')

# Open a window that is twice the size of the original image
image_window = ImageWin("Image Processing", old_image.width * 2, old_image.height)

# Draw the image on the window
old_image.draw(image_window)

# Create a new, blank image
new_image = EmptyImage(old_image.width, old_image.height)

# For each pixel in the original image...
for row in range(old_image.height):
    for col in range(old_image.width):
        # ... get that pixel ...
        old_pixel = old_image.getPixel(col, row)
        # ... flip the pixel ...
        new_pixel = negative_pixel(old_pixel)
        # ... and put that pixel in the new image
        new_image.setPixel(col, row, new_pixel)

# Make sure to put the new image over to the side the right number of pixels
new_image.setPosition(old_image.width + 1, 0)

# Draw the new image
new_image.draw(image_window)

# Wait for a user to click the window to close the image
image_window.exitOnClick()


Lecture 36 - Speed, Simplicity, Correctness

Lecture Date: Monday, April 18

Do you remember Lab 2? The one with the robot and counting rooms? We’re going to circle back around to that today.

What makes code “good”? It’s kind of an arbitrary question. Code can always be “better” to some degree.

It could be:

  • It works (for what set of inputs?) – versatility and correctness
  • It is maintainable – readable, simple, good comments and naming, etc.
  • It is efficient – uses minimal time or memory when running
  • It is easy to create (meaning inexpensive to create too)

We can almost always improve on one of these three areas: speed, simplicity, and correctness. All of them don’t have to be perfect to have a “working” system. (Yes, even correctness - most, if not all, software ships with some known errors in it.)

Consider these bits of code:

1
2
3
4
5
6
x = 2;
y = 5;
# swap x and y:
tmp = x; # x = 2, y = 5, tmp = 2
x = y;       # x = 5, y = 5, tmp = 2
y = tmp;     # x = 5, y = 2, tmp = 2
1
2
3
4
5
6
x = 2;
y = 5;
# swap x and y:
x -= y;    # x = 2-5,         y = 5
y += x;    # x = 2-5,         y = 5+(2-5) = 2
x = y - x; # x = 2-(2-5) = 5, y = 2
1
2
3
4
x = 2;
y = 5;
# swap x and y:
x,y = y,x

Which is “better”? Why?

We want to write “good code” that’s “fast” and “easy to maintain.” So what exactly does that mean?

As an example, we’ll play with a robot counting rooms, just like you did in Lab 2.

You’ll need these files to follow along:

1
2
# Option 1:
announce(16)
1
2
3
4
5
# Option 2:
num_rooms = 1
while(look_right()):
  move_right()
  num_rooms += 1
1
2
3
4
5
6
7
8
9
10
# Option 3:
width = 1
height = 1
while(look_right()):
  move_right()
  width += 1
while(look_down()):
  move_down()
  height += 1
announce(width*height)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Option 4:
visited_rooms = []
x = 0
y = 0
visited_rooms.append(str(x) + "," + str(y))
while(True):
  next_direction = random.randint(0,3)
  if next_direction == 0:
      if(look_up()):
          move_up()
          y -= 1
  elif next_direction == 1:
      if(look_down()):
          move_down()
          y += 1
  elif next_direction == 2:
      if(look_left()):
          move_left()
          x -= 1
  elif next_direction == 3:
      if(look_right()):
          move_right()
          x += 1
  here = str(x) + "," + str(y)
  if here not in visited_rooms:
      visited_rooms.append(here)
      announce(len(visited_rooms))


Lecture 35 - Under the Hood

Lecture Date: Friday, April 15

Once the program gets going, you have something called the stack and the heap.

stackvsheap

Image credit: thenewcircle.com

The stack is where variable pointers go, such as with a complex/mutable type. The actual values of the complex/mutable type variable is found in the heap.

What happens when a variable no longer points to something in the heap? This is called garbage collection.

Let’s look at some examples at this tutorial: http://www.pythontutor.com/ We talked about this a bit at the beginning of the semester when we discussed activation records. We’ll revisit that a bit here with some more information.

How exactly does Python keep up with what type a variable is? How do other languages do it?

The War between Filing Systems

There are lots of numbers in your life. Social security numbers, student ID numbers, SIS person numbers, telephone numbers, zip codes, … How do you know which number is which?

Option 1: remember. This number is on the post-it beside my bed, which is where I wrote my student ID number, so that must be what it is.

Option 2: annotate. This piece of paper says SSN: 012345678 so it must by my SSN, not my telephone number.

In programming we call the first static typing and the latter dynamic typing. People argue about which one is better heatedly.

Python happens to be dynamically typed. Java, on the other hand, is statically typed.

How does this affect how we write our programs?

Imagine a program that you might write that has these lines:

1
2
3
x = 4
x = "Hello World"
x = gamebox.Camera()

In Python, this works just fine, because of the dynamic typing. But in Java, this would never work, because we would have defined x to have a particular type. After that, it can’t be changed. But, if we store the type with the data itself and not the variable, then this works just fine. x is just a pointer to some data - how we interpret it is up to the programmer.

You might think that dynamic typing can get a programmer in a lot of trouble if they don’t keep their variables straight. And you’re right. But it does make for less coding in general, even if dynamically typed languages are usually slower than statically typed ones.

Java is also a strongly typed language, which means that once you set a type, it can never be changes. Oh sure, you can cast it, but that’s just the type being temporarily converted. The original data stays with the original type.

So, if we’re building a program, and given a choice, which would you prefer to do?

  • Write a program quickly
  • Write a program that runs fast
  • Write a program that has few if any bugs
  • Write a program that you can read and make sense of latter
  • Write a program that runs on many different devices

This partially drives our choice of language.


Lecture 34 - Under the Hood

Lecture Date: Wednesday, April 13

Did you ever wonder exactly where all this stuff we’ve been talking was being stored on your computer?

There are different types of “memory” in a computer

  • Cache - small, really fast memory that’s attached to the processor - used as “working memory”
  • RAM (Random Access Memory) - holds info about programs currently running - used as “short term memory”
  • Hard disk / SSD - holds data that will persist if the power is cut off - used as “long term memory”

Your programs are .py files, stored on the disk itself. But when they run, the Python interpreter requests from the operating system that some space be set aside for your program to run in. This is typically in RAM (although it can vary a little).

Today we’ll look at the hardware of a computer itself.


Lecture 33 - gamebox

Lecture Date: Monday, April 11

More on gamebox today! Let’s talk about how to come up with a “good game” and some more things we can do with gamebox!

First, what makes up a game?

Here are a couple of definitions:

  • “Playing a game is the voluntary attempt to overcome unnecessary obstacles.” -Bernard Suits
  • “A game is a system in which players engage in artificial conflict, defined by rules, that results in a quantifiable outcome.” - Salen & Zimmerman, Rules of Play

Another way of thinking about it is that all games have:

  • goals - something to work toward
  • rules - the framework around the game
  • feedback - letting the player know what’s going on
  • voluntary participation / players - people willingly playing the game

Let’s consider these things in the context of the games we play.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# starfield simulation

import pygame
import gamebox
import random
camera = gamebox.Camera(800,600)
stars = []
counter = 0

def tick(keys):
    global counter
    counter += 1

    if counter % 5 == 0:
        numstars = random.randint(0,7)
        for i in range(numstars):
            stars.append(gamebox.from_color(random.randint(5,795),0,"white",3,3))

    camera.clear("black")

    for star in stars:
        # move the star
        star.y += 3
        if(star.y > 600):
            stars.remove(star)
        # draw the star
        camera.draw(star)

    camera.display()

ticks_per_second = 30

# keep this line the last one in your program
gamebox.timer_loop(ticks_per_second, tick)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# infinite jumper

import pygame
import gamebox
import random

camera = gamebox.Camera(800,600)
character = gamebox.from_color(50, 200, "green", 15, 40)
character.yspeed = 0
walls = [
    gamebox.from_color(50,250, "black", 200, 10),
    gamebox.from_color(400,150, "black", 200, 10),
    gamebox.from_color(600,25, "black", 200, 10),
]

counter = 0

def tick(keys):
    # get access to the counter
    global counter
    if pygame.K_RIGHT in keys:
        character.x += 10
    if pygame.K_LEFT in keys:
        character.x -= 10
    character.yspeed += 1
    character.y = character.y + character.yspeed
    camera.clear("cyan")
    camera.draw(character)

    # makes the screen scroll
    camera.y -= 3

    # make random walls appear every time the counter hits a particular number
    # notice how I use the random.randint to vary the height of the platform
    # also I add in the camera.x to the x position because the screen keeps moving
    counter += 1
    if counter % 50 == 0:
        new_wall = gamebox.from_color(random.randint(200,600), camera.y-300,  "black", random.randint(100,250), 10)
        walls.append(new_wall)


    for wall in walls:
        if character.bottom_touches(wall):
            character.yspeed = 0
            if pygame.K_SPACE in keys:
                character.yspeed = -20
        if character.touches(wall):
            character.move_to_stop_overlapping(wall)
        camera.draw(wall)

    camera.display()


ticks_per_second = 30

# keep this line the last one in your program
gamebox.timer_loop(ticks_per_second, tick)