# Code Developed in CSCI-1100 Spring Semester 2016¶

## Lecture 1¶

### Module:`lec01_three_doubles` — Finds three consecutive pairs of double letters¶

Find all words containing three consecutive pairs of double letters in a file of all English words located at:

Modules used: `urllib`

Returns: All words matching condition and the count of found words

Pseudo Code:

```open the file from the web with all the words in English

for each word in the file:
for all positions l in the word
if the letters at positions (l and l+1) are the same
and the letters at positions (l+2 and l+3) are the same
and the letters at positons  (l+4 and l+5) are the same then
output word and increment the count
```

Code:

```""" Find all words containing three consecutive pairs of double letters
in a file of all English words located at:

http://www.greenteapress.com/thinkpython/code/words.txt

**Modules used:**  :py:mod:`urllib`

**Returns:** All words matching condition and the count of found words

**Pseudo Code**::

open the file from the web with all the words in English

for each word in the file:
for all positions l in the word
if the letters at positions (l and l+1) are the same
and the letters at positions (l+2 and l+3) are the same
and the letters at positons  (l+4 and l+5) are the same then
output word and increment the count

"""

import urllib

def has_three_double(word):
""" Returns True if the word contains three consecutive pairs of
double letters and False otherwise.
"""
for l in range(len(word)-5):
if word[l] == word[l+1] and \
word[l+2]==word[l+3] and \
word[l+4]==word[l+5]:
return True
return False

# Comments that fit in a single line can be put in this format.
# Anything after a single pound sign is ignored.

# The main body of the program starts here

word_url = 'http://www.greenteapress.com/thinkpython/code/words.txt'
word_file = urllib.urlopen(word_url)

count = 0
for word in word_file:
word = word.strip().strip('\n')
if has_three_double(word):
print word
count = count + 1

if count == 0:
print 'No words found'
elif count == 1:
print "1 word found"
else:
print count, 'words were found'
```

## Lecture 3¶

### Module:`lec03_raw_input` — Demonstrate the use of raw_input in the volume calculation code.¶

Code:

```"""
Write a program to
read the dimensions of a rectangular prism,
compute the surface area and volume, and
print them.

"""

length = float(raw_input("Enter the length of the rectangular prism ==> "))
width = float(raw_input("Enter the width of the rectangular prism ==> "))
height = float(raw_input("Enter the height of the rectangular prism ==> "))

area = 2 * (length*width + length*height + width*height)
volume = length*width*height
print "Rectangular prism with length %.3f, width %.3f, height %.3f" %(length, width, height)
print "Area %.3f, Volume %.3f" %(area, volume)
```

## Lecture 4¶

### Module:`lec04_exercise_set_1` — Demonstrate the use of some string functions for parts 3 and 4.¶

Code:

```
name2 = "Rensselaer Polytechnic Institute"

##a -> 1,  e->a, 1->e
name2 = name2.replace("a","1")
name2 = name2.replace("e","a")
name2 = name2.replace("1","e")

print name2

word = 'Bring back the swarm'

word = word.title()
word = word.replace(" ", "")
word = "#" + word
print word

word = 'Bring back the swarm'

word = "#" + (word.title()).replace(" ","")
print word
```

### Module:`lec04_exercise_set_2` — Demonstrate the use of the math module¶

Code:

```"""
Write a program to
compute its area and
print it.

"""

import math

## or

print "The area of a circle is:", area
print "The area of a circle is: %.2f" %area
```

### Module:`lec04_cylinder` — Demonstrate the use of some math modules to compute the area and volume of a cylinder.¶

Code:

```""" Author CS-1 Staff

of a cylinder and outputs the area and volume.

"""
import math

# This is a comment
print "Computing the area and volume of a cylinder"
height = float(raw_input("Enter height ==> "))

print "Area is %.2f" % area
print "Volume is %.2f" %volume
```

### Module:`lec04_triangle` — Class exercise to calculate the hypotenuse of a right triangle¶

Code:

```""" Author CS-1 Staff

Purpose: This program reads the lengths a and b
of the sides of a right triangle and outputs the
hypotenuse.

"""
import math

print "Computing the hypotenuse of a right triangle"
a = float(raw_input("Enter side a ==> "))
b = float(raw_input("Enter side b ==> "))

c  = math.sqrt(a**2 + b**2)

print "Hypotenuse is %.2f" % c
```

## Lecture 5¶

### Module:`lec05_surface_area` — Use two functions to compute surface area¶

Code:

```'''
Demonstrate the writing and use of two functions that compute the area
of a circle and the surface area of a cylinder.
'''

import math

return math.pi * radius ** 2

height_area = 2 * radius * math.pi * height
return 2*circle_area + height_area

print 'The area of a circle of radius 1 is', area_circle(1)
r = 2
height = 10
print 'The surface area of a cylinder with radius', r
print 'and height', height, 'is', area_cylinder(r,height)
```

## Lecture 6¶

### Module:`lec06_height` — Use if statements to compare height¶

Code:

```""" Author: CS1 Staff

Simple program to demonstrate an if statement.
"""

name1 = "Dale"
height1 = int(raw_input("Enter the height of %s in cm ==> " %name1))
name2 = "Erin"
height2 = int(raw_input("Enter the height of %s in cm ==> " %name2,))
if height1 < height2:
print "%s is taller" %name2
max_height = height2
elif height1 > height2:
print "%s is taller" %name1
max_height = height1
else:
print "%s and %s have the same height!" %(name1, name2)
max_height = height1

print "The max height is %d" %max_height
```

## Lecture 7¶

### Module:`lec07_ex1` — First image example: resize and convert¶

Code:

```from PIL import Image

filename = "chipmunk.jpg"
im = Image.open(filename)
print '\n' '********************'
print "Here's the information about", filename
print im.format, im.size, im.mode
im.show()

gray_im = im.convert('L')
scaled = gray_im.resize( (128,128) )
print "After converting to gray scale and resizing,"
print "the image information has changed to"
print scaled.format, scaled.size, scaled.mode

scaled.show()
scaled.save(filename + "_scaled.jpg")
```

### Module:`lec07_ex2` — Second image example: crop and paste¶

Code:

```from PIL import Image

im = Image.open("lego_movie.jpg")
w,h = im.size

## Crop out three columns from the image
## Note: the crop function returns a new image
part1 = im.crop((0,0,w/3,h))
part2 = im.crop((w/3,0,2*w/3,h))
part3 = im.crop((2*w/3,0,w,h))

## Create a new image
newim = Image.new("RGB",(w,h))

## Paste the image in different order
## Note: the paste function changes the image it is applied to
newim.paste(part3, (0,0))
newim.paste(part1, (w/3,0))
newim.paste(part2, (2*w/3,0))
newim.show()
```

## Lecture 9¶

### Module:`lec09_overview` — Some basic while loop constructs¶

Code:

```"""
This is a general program for practicing different loop
methods. The following are examples of:

1. Loops that count up or down, loops that end

Loop block
Printing (print all on one line)
Changing a list (make upper case)

Accumulate a value
Count by 1, 3 (print three in a line, check
for three letters in a word, ending conditions?)
Is it true that there are two consecutive repeated letters?

Count all farmer's markets in Albany

2. Loops that are undeterministic

Depends on an external condition
(while user does not say stop)

------ WE will continue with these the next time
Depends on a complex condition
(while found or end of list, farmer's market)

3. Double loops

Find all possible pairs of agents
Find pairs of agents with the same first letter in their name

"""

months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', \
'jul', 'aug', 'sep', 'oct', 'nov', 'dec']

agents = ['skye','may','fitz','simmons','caulson',\
'hunter', 'mack', 'morse', 'triplett', \
'hartley', 'deathlok', 'koenig', \
'gonzales', 'fury']

word = 'bookkeeper'

i=0
while i< len(months):
print "Month: %d is %s" %(i+1, months[i].capitalize() )
i += 1

print months

print
print agents

## Capitalize the values in list "agents"

i=0
while i < len(agents):
agents[i] = agents[i].capitalize()
i += 1

## Check if capitalized
print
print agents

##Accumulation of values

i = 0
cnt = 0
while i < len(agents):
if agents[i] == 'S':
cnt += 1
i += 1

print "%d agents with first name starts with 'S'" %cnt

##Find if there any agents who name starts with F
##Print Yes if any agent with such name, No otherwise

i = 0
found = False
while i < len(agents):
if agents[i] == 'F':
found = True
i += 1

if found:
print 'Yes'
else:
print 'No'

print
print "This is a loop that counts up to 7"
i = 0
while i < 7:
i += 1
print i

print
print "This is a loop that counts 10 down to 1"

i=10
while i > 0:
print i
i -= 1

print
print "This is loop that counts by 2, starting with 1 and ending with 19"
i = 1
while i <= 20:
print i
i += 2

```

### Module:`lec09_user_stop` — Stop a while loop based on user input¶

Code:

```""" This program shows how to write a loop that ends
on a given user input. So, we must make sure that
while loop executes once initially and also that we
set the conditions that would stop the loop manually
when the correct input is given.

"""

### write a loop that reads user input, until the
### user types stop

finished = False
while not finished:
cmd = raw_input("Enter a command (stop to stop) => ")
if cmd == 'stop':
finished = True
```

### Module:`lec09_co2` Use a while loop to process a list¶

Code:

```"""
Illustrating while loops with the CO2 example
"""

co2_levels = [ (2001, 320.03), (2003, 322.16), (2004, 328.07),\
(2006, 323.91), (2008, 341.47), (2009, 348.92),\
(2010, 357.29), (2011, 363.77), (2012, 361.51),\
(2013, 382.47) ]

"""
First example, sum
"""
i=0
sum=0
while i< len(co2_levels):
sum += co2_levels[i]
i += 1

print
print "Total co2_levels is", sum

"""
Reverse order
"""
i=len(co2_levels)
while i > 0:
i -= 1
print "Year", co2_levels[i], \
"CO2 levels:", co2_levels[i]

"""
Levels above 350
"""
print
i=0
num = 0
while i < len(co2_levels):
if co2_levels[i] > 350:
num += 1
i += 1
print "%d years had CO2 levels greater than 350" % num

"""
Percent change
"""
print
i=1
num = 0
while i < len(co2_levels):
percent = 100 * (co2_levels[i] - co2_levels[i-1]) / co2_levels[i-1]
print "Percent change from %d to %d was %.2f" % (co2_levels[i-1], co2_levels[i], percent)
i+=1

"""
Levels that went down
"""
print
i=1
num = 0
while i < len(co2_levels):
if co2_levels[i] < co2_levels[i-1]:
print "From %d to %d CO2 levels went down" % (co2_levels[i-1], co2_levels[i])
i+=1

```

## Lecture 10 (carry over from Lecture 9)¶

### Module:`lec10-closest` Find the two closest values in a list¶

Code:

```'''
Purpose:  Demonstrate the use of nested loops to find the two closest values in a list.
This could also be implemented - probably better - using for loops.  The values
are stored in a list L, but in practice it would be better to input them from the user.

Author: Chuck Stewart

Date:  March 3, 2016
'''

L = [34, 21, 12, 78, 28, 61 ]

#  Initialize two variables to hold information about the minimum.  The
#  first is a tuple holding the indices of the two closest values.  The
#  second is the minimum distance. These values are initialized from the
#  first two values in the list.
min_pair = (0,1)
min_dist = abs( L - L )

#  In order to test each possible pair of indices, the index of the first
#  component of the pair must start out 0.
i = 0
while i<len(L):
#  The second index starts out at i+1 and runs through the end of
#  the list.
j=i+1
while j < len(L):
dist = abs(L[i]-L[j])

#  If the distance between the current pair of points is less than
#  the current minimum, we have a new minimum pair
if dist < min_dist:
min_pair = (i,j)
min_dist = dist
j += 1

#  This is outside the inner while loop so that i is incremented after
#  the inner while loop ends.
i += 1

closest_i = min_pair
closest_j = min_pair
print "Closest values are %d and %d at indices %d and %d."\
%(L[closest_i], L[closest_j], closest_i, closest_j)
```

## Lecture 11¶

### Module:`lec11_walk.py` Turtle performs a random walk¶

Code:

```'''
Lecture 11 Example of a Random Walk

This code was started in class on March 7 and completed on March 10.
It simulates a random walk by turtle who in each time unit randomly
takes a step to the left or a step to the right until it falls off.

This is represented by creating a board of n spaces and starting the
turtle in space n/2.  A step to the left decreases the turtle
position.  A step to the right increases the turtle position.

The simulation is run with a delay between each step so we can watch
what is happening.  Without this delay, the board would print too
fast.
'''
import random
import sys
import time    # so that we can delay

def print_board( steps, n, turtle_pos):
'''
Print the board with the current turtle position on it.  This assumes the turtle
position is at least 0 and less than n.
'''
board = '_' * turtle_pos + 'T' + '_'*(n-1-turtle_pos)
print "%4d: %s" %(steps, board)

def take_step( n, turtle_pos ):
'''
Take a step, return turtle tuple with the new position, and False if
turtle fell off
'''
ran_value = random.random()
if ran_value < 0.5:
'''  Step to the left '''
turtle_pos -= 1
else:
''' Step to the right '''
turtle_pos += 1
fell_off = turtle_pos < 0 or turtle_pos >= n
return (turtle_pos, fell_off)

if __name__ == '__main__':
'''  Read the input and check to make sure it is a positive integer '''
n = raw_input('Enter the board size for the turtle walk => ')
if not n.isdigit():
print 'Need a positive number'
sys.exit()
n = int(n)
print n

'''  Initialize the turtle position in the middle and print the board. '''
turtle_pos = (n-1)/2
print_board( 0, n, turtle_pos )

'''  Run one step at a time until the turtle falls off the board.  '''
fell_off = False
steps = 0
while not fell_off:
(turtle_pos, fell_off) = take_step( n, turtle_pos )
steps += 1
if not fell_off:
print_board( steps, n, turtle_pos )
time.sleep(0.1)   # delay by the given number of seconds so we can see what is happening

print 'The turtle fell off after', steps, ' steps.'
```

## Lecture 13¶

### Module:`lec13_scores` Read scores and output them in decreasing order¶

Code:

```'''
Read a file of scores, with one score per line, and output them
in order from greatest to smallest.
'''
f = open('scores.txt')
scores_list = []
for line in f:
score = int(line)
scores_list.append( score )

scores_list.sort()

#  Reverse the list and then output it
scores_list = scores_list[::-1]
for i in range(len(scores_list)):
print "%d: %3d" %(i,scores_list[i])

'''
# As an alternative to reversing the list we can
# index from the end of the list.
for i in range(len(scores_list)):
print "%d: %3d" %(i, scores_list[-1-i])
'''
```

### Module:`lec13_legos` Read and format a legos file¶

Code:

```'''
Exercise from Lecture 13 on parsing a legos file and putting it into the form
we expected from HW 4.

For example, if legos.txt has the following three lines:
2x1, 2
2x2, 6
4x2  ,   3

Then at the end of the following, the legos list will be
['2x1', '2x1', '2x2', '2x2', '2x2', '2x2', '2x2', '2x2', '4x2', '4x2', '4x2']

When we developed this in class, we added a bit of complexity and tested it as
we went.  This included making some mistakes.  At the end we have the following
completed solution.  Notice that the legos += ...  statement can be replaced
by the for loop that is commented out...
'''

lego_f = open('legos.txt')

legos = []
for line in lego_f:
line = line.split(',')
block = line.strip()
count = int(line)
'''
for i in range(count):
legos.append(block)
'''
legos += [block]*count

print legos
```

## Lecture 14¶

Code:

### Module:`lec14_counts` Two different approaches to counting scores¶

Code:

```'''
Lecture 14
Spring 2016
Prof. Chuck Stewart

Here are two different solutions to the problem of counting the number
of occurrences of each integer in an input sequence of integers. These
are the implementations of two of the four solutions we came up with
in class.

I have rearranged the code into functions, with one function
implementing one solution.  Of course, if you were in class you noted
(and in many cases participated in) the development of the solutions,
involving several steps of writing the code, testing it, and refining
it.  What you see here is just the final product.
'''

def print_scores_v1( scores ):
'''
The first solution finds the minimum and maximum scores, and then
counts each score in this range, only outputting the scores with
non-zero counts.  This is short and easy to write, but it only
works well when the scores are not widely distributed.  For
example, if there were only two scores, 0 and 1,000,000, this
would be a very slow solution.
'''

'''  Preliminary output.  Not necessary for the solution. '''
print 'Min score', min(scores)
print 'Max score', max(scores)
print 'Length', len(scores)

''' Generate and print a count for each score '''
print '\nVersion 1 output:'
for score in range(min(scores), max(scores)+1 ):
count = scores.count(score)
if count > 0:
print "%3d: %2d" %(score,count)

def print_scores_v2( scores ):
'''
The second solution is based on sorting.  In doing so, all values
that are the same are adjacent to each other in the sorted list,
making them much easier to count.  We start by making a copy of
the list in case the user wanted to work with the original list.
'''
scores_c = scores[::]
scores_c.sort()
count = 1
print '\nVersion 2 output:'
for i in range(1,len(scores_c)):
if scores_c[i-1] == scores_c[i]:  # seeing same score as the previous
count += 1
else:
''' The current score is not the same as the previous, so
output the previous along with its count. '''
print "%3d: %2d" %(scores_c[i-1],count)
count = 1

# Print count for last item in the list
print "%3d: %2d" %(scores_c[-1],count)

if __name__ == "__main__":
'''  Read in the scores, storing them in a list '''
in_file = open('scores.txt')
scores = []
for line in in_file:
scores.append( int(line) )

print_scores_v1(scores)
print_scores_v2(scores)

```

## Lecture 15¶

### Module:`lec15_find_names_start` Starting point for an actor find routine¶

Code:

```imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()
name_list = []
for line in open(imdb_file):
words = line.strip().split('|')
name = words.strip()
```

## Lecture 16¶

### Module:`lec16_imdb_list.py` Find the busiest person (slowly) in the IMDB using a list¶

Code:

```'''
Author: Chuck Stewart

Purpose: Using a list that keeps track of actors and the number of
movies they have been in, find the person who was in the most movies
listed in our data from the Internet Movie Database.  This
demonstrates a very slow --- O(N^2) --- solution to this problem.  A
dictionary-based solution and a solution based on sorting are both
faster.
'''
def insert_name_and_count( count_list, name ):
i=0
while i<len(count_list) and count_list[i] != name:
i += 1
if i == len(count_list):
# name is not already in the list
count_list.append( [name,1] )
else:
count_list[i] += 1

if __name__ == "__main__":
imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()

'''  Do the counting '''
count_list = []
for line in open(imdb_file):
words = line.strip().split('|')
name = words.strip()
insert_name_and_count( count_list, name )

''' Find the max '''
max_movies = count_list
max_name = count_list
for i in range(1,len(count_list)):
if count_list[i] > max_movies:
max_name = count_list[i]
max_movies = count_list[i]

print '%s was involved in the most movies, %d' %(max_name, max_movies)

```

### Module:`lec16_imdb_dict.py` Find the busiest person (quickly) in the IMDB using a dictionary¶

Code:

```'''
Author: Chuck Stewart

Purpose: Using a dictionary that associates names with the number of
movies, find the person who was in the most movies listed in our data
from the Internet Movie Database.
'''

import time

if __name__ == "__main__":
imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()
start_time = time.time()

'''  Do the counting '''
counts = {}
for line in open(imdb_file):
words = line.strip().split('|')
name = words.strip()
if name in counts:
counts[name] += 1
else:
counts[name] = 1

''' Find the max '''
max_movies = 0
max_name = ''
for name in counts.keys():
if counts[name] > max_movies:
max_name = name
max_movies = counts[name]
end_time = time.time()

print '%s was involved in the most movies, %d' %(max_name, max_movies)
print 'Dictionary version took %1.2f seconds' %(end_time-start_time)

```

### Module:`lec16_imdb_list_sort.py` Find the busiest person (quickly) in the IMDB using sorting¶

Code:

```'''
Author: Chuck Stewart

Purpose: Here is a fast, list-based solution to our problem of finding
the busiest person in the internet movie database. It takes a
different approach, one involving sorting.
'''

import time
if __name__ == "__main__":
imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()
start_time = time.time()

'''  Append each name '''
names = []
for line in open(imdb_file):
words = line.strip().split('|')
names.append( words.strip() )

names.sort()

'''
Scan through the list, adding to a running counter when the name
is the same as the previous.  When they are different check to see
if a new max has been reached.  If so, then update the max and
reset the counter to 1.  If not, just reset the counter.
'''
max_movies = 0
max_name = ''
current_count = 1
for i in range(1,len(names)):
if names[i] == names[i-1]:
current_count += 1
elif current_count > max_movies:
max_movies = current_count
max_name = names[i-1]
current_count = 1
else:
current_count = 1

'''
Check the special case of the last actor being the busiest.
'''
if current_count > max_movies:
max_movies = current_count
max_name = names[-1]

end_time = time.time()

print '%s was involved in the most movies, %d' %(max_name, max_movies)
print 'List and sorting version took %1.2f seconds' %(end_time-start_time)
```

## Lecture 17¶

### Module:`lec17_years_to_movies.py` Find the year in the IMDB using a dictionary¶

Code:

```'''
Author:  Chuck Stewart

Purpose: Lecture 17 IDMB example of a dictionary associating a year
with the set of movies from that year and then using the dictionary to
find the year with the most movies.
'''

if __name__ == "__main__":
##  Form the dictionary
imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()

years_to_movies = {}
for line in open(imdb_file):
words = line.strip().split('|')
movie_name = words.strip()
year = int(words)

#  Create an empty set entry if the year is new
if year not in years_to_movies:
years_to_movies[year] = set()

#  Add the movie to the year

# A little bit of extra printed information
print 'Earliest year is', min(years_to_movies.keys())
print 'Last year is', max(years_to_movies.keys())

# Find the busiest year by keeping track of the maximum size set from
# the dictionary and the year that had that maximum size.
max_year = 0
max_count = 0
for y in years_to_movies.keys():
count = len(years_to_movies[y])
if count > max_count:
max_year = y
max_count = count

print 'Year %d had max movies: %d' %(max_year, max_count)
```

### Module:`lec17_actors_and_movies.py` Find all movies for an actor and actors in the same movie¶

Code:

```'''
Author:  Chuck Stewart

Purpose: Lecture 17 IDMB example where two dictionaries are built, one
associating an actor with the set of movies they appear in and the
other associating a movie with the set of actors.  We can use this to
find actors that appeared together in a movie.
'''

if __name__ == "__main__":
imdb_file = raw_input("Enter the name of the IMDB file ==> ").strip()
actor_name = raw_input("Enter the name of an actor (last, first) ==> ").strip()

#  Form the two dictionaries.
actors_to_movies = {}
movies_to_actors = {}
for line in open(imdb_file):
words = line.strip().split('|')
actor = words.strip()
movie = words.strip()

#  Additions to the first dictionary
if not actor in actors_to_movies:
actors_to_movies[actor] = set()

#  Additions to the second dictionary
if not movie in movies_to_actors:
movies_to_actors[movie] = set()

# Let's evaluate the movies
print "\n%s has been in %d movies" %(actor_name, len(actors_to_movies[actor]))
print "Here they are:"
movie_list = sorted(list(actors_to_movies[actor_name]))
for i in range(len(movie_list)):
print "\t%3d: %s" %(i+1, movie_list[i])

#  Find other actors that this actor appeared with
other_actors = set()
for movie in actors_to_movies[actor_name]:
other_actors |= movies_to_actors[movie]

print '\n%d other actors appeared with %s' %(len(other_actors), actor_name)
print 'Here they are:'
actor_list = sorted(list(other_actors))
for i in range(len(actor_list)):
print "\t%3d: %s" %(i+1, actor_list[i])

```

## Lecture 18¶

### Module:`lec18_points.py` A simple implementation of a point class¶

Code:

```""" Class example, a simple class of 2d objects

"""

class Point2d(object):
def __init__(self, x0, y0):
"""Initialize to make sure each point has an x, y value. """
self.x = x0
self.y = y0

def length(self):
""" Return the length of a point. """
return (self.x**2 + self.y**2)**(0.5)

def __str__(self):
""" Returns the string representation of object.
Call as:

str(x)
print x  ##calls this function and prints the result string

"""
return "(%d, %d)" %(self.x, self.y)

def distance(self, other):
""" Returns the distance between two points. """
d = (self.x-other.x)**2 + (self.y-other.y)**2
return d**(0.5)

""" Adds two points and returns a new point with the
addition of values. You can call this as:

pt1+pt2

"""

new = Point2d(self.x, self.y)
new.x += other.x
new.y += other.y
return new

def __sub__(self, other):
""" Subtracts other from self, and returns a new point
containing the result. You can call this as:

pt1.__sub__(pt2)
pt1-pt2

"""
new = Point2d(self.x, self.y)
new.x -= other.x
new.y -= other.y
return new

if __name__ == "__main__":
##Test code here
pt1 = Point2d(10, 20)
pt2 = Point2d(3, 4)

print pt1.x, pt1.y
print pt2.x, pt2.y

print pt1 ## calls the __str__ method
print str(pt1) ## this is identical to the above call

print "Length of pt1 is", pt1.length()
print "Length of pt2 is", pt2.length()

print "Distance between", pt1, "and", pt2, "is:", pt1.distance(pt2)
print pt1  ##calls str

pt3 = pt1+pt2
print pt3

print "Subtraction:", pt1-pt2
print "Pt1:", pt1, "Pt2:", pt2
print "Add/Subtract do not change the input objects"
```

## Lecture 19¶

### Module:`lec19_time_skeleton.py` A framework for the time class¶

Code:

```
""" Class for storing time. Time is reported on a military (24 hour) clock

"""

class Time(object):
def __init__(self, hr, min, sec):
pass

def convert(self):
pass

def __str__(self):
pass

pass

def __sub__(self, other):
pass

if __name__ == '__main__':
pass
```

### Module:`lec19_time.py` Completed time class¶

Code:

```
""" Class for storing time.

"""

class Time(object):
def __init__(self, hr, min, sec):
if hr > 24:
hr = hr%24
self.seconds = hr*60*60 + min*60 + sec

def convert(self):
hr = self.seconds/3600
min = (self.seconds - hr*3600)/60
sec = self.seconds - hr*3600 - min*60
return hr, min, sec

def __str__(self):
hr, min, sec = self.convert()
return '%02d:%02d:%02d' \
%(hr, min, sec)

total = self.seconds + other.seconds
hr = total/3600
min = (total - hr*3600)/60
sec = total - hr*3600 - min*60
return Time(hr, min, sec)

def __sub__(self, other):
total = self.seconds - other.seconds
if total < 0:
total += 24*3600
hr = total/3600
min = (total - hr*3600)/60
sec = total - hr*3600 - min*60

return Time(hr, min, sec)
```

### Module:`lec19_restaurant_exercise.py` Main routine for the yelp data¶

Code:

```'''
Use the business class to manage a set of restaurants
and get user inputs on how to proceed.
'''

import webbrowser

def convert_input_to_restaurant(line):
m = line.strip().split("|")

def build_restaurant_list():
restaurants = []
f = open('yelp.txt')

restaurants = []
for line in f:
restaurants.append(convert_input_to_restaurant(line))
return restaurants

if __name__ == "__main__":

restaurants = build_restaurant_list()
num_restaurants = len(restaurants)

while (True):
#  Get the index of the restaurant and check it.
print "Enter the index of the restaurant from 1 to %d or stop to end ==> " %num_restaurants,
index = raw_input()
print index
if index == 'stop':
break
index = int(index)
if index < 1 or index > num_restaurants:
print "The index is out of range.  Sorry."
else:
print(restaurants[index-1])
```

### Module:`lec19_business_class.py` Code for the business class¶

Code:

```###import points
from lec18_points import Point2d

def __init__(self, name, lat, lon, address, url, category, scores):
self.name = name
self.loc = Point2d(float(lon), float(lat))
self.url = url
self.category = category

## convert scores into integer
for i in range(len(scores)):
scores[i] = int(scores[i])
self.scores = scores

def avgscore(self):
if len(self.scores) < 3:
return sum(self.scores)/float(len(self.scores))
else:
s = list(self.scores)
s.sort() ## we do not want to change the actual ordering of scores
return ( sum(s[1:-1])/float(len(s)-2) )

def minscore(self):
return min(self.scores)

def maxscore(self):
return max(self.scores)

def __str__(self):
return "%s (%s)\n\t%s\n\tLocation: %s\nAvg Score: %.1f (%d - %d)" \
%(self.name, self.category, self.address, self.loc, self.avgscore(), self.minscore(), self.maxscore())

```

## Lecture 20¶

### Module:`lec20_smallest_two.py` Find the smallest two values in a list¶

Code:

```"""
Problem: Find the index of the two smallest values
We will also learn how to time running time of algorithms
using the time module

Algorithm:

Idea 1:
Make a copy of list
Sort the copy
Find the two smallest values (index 0,1)
Find the index of these values**

Idea 2:
Initialize two smallest values to 0,1
Then, iterate through list
and remember the smallest two values
and their index

Idea 3:
Make a list of value, index
Sort the list
Return the index for the first two

Idea 4: (implement this yourself)
Make a copy of list
find min in copy
find index of min in copy
remove min from list copy
find next min in copy
find index of min in the next copy

"""

import random
import time

def smallest_two1(L):
""" Assume n items in List L.
Complexity:  O(nlogn + 3n) =mostly costly element= O(nlogn)

"""

L1 = list(L)  ### O(n): read and append to new list for n elements
L1.sort()     ### O(nlogn): sorting: we will see this in sorting lecture
min1,min2 = L1, L1  ## O(1)
i1 = L.index(min1)  ### O(n): compare against every element in worst case
i2 = L.index(min2)  ### O(n): compare against every element in worst case
if i2 == i1:
i2 = L.index(min2, i1+1)
return i1, i2

def smallest_two2(L):
""" Assume n items in List L.
Complexity: O(n)

"""
if L < L:
i1, i2 = 0,1
else:
i1, i2 = 1,0
for i in range(2,len(L)):  ### O(n)
if L[i] < L[i1]:
i1, i2 = i, i1
elif L[i] < L[i2]:
i2 = i
return i1, i2

def smallest_two3(L):
""" Assume n items in List L.
Complexity: O(n+nlog n) =mostly costly element= O(nlogn)
Note: Compared
to smallest_two3, we are sorting a more complex list
(list of 2-tuples). So efficiency will depend on the implementation
of that sort

"""

L1 = []
for (i,val) in enumerate(L):  ## O(n): read and append each element
L1.append( (val, i) )
L1.sort()      ## O(nlogn): sorting, we will see why
return L1, L1

if __name__ == "__main__":
print "Test cases"

L = range(100000)
random.shuffle(L)

start = time.time()
a,b = smallest_two1(L)
end = time.time()
print "smallest_two1 took %f seconds" %(end-start)

start = time.time()
a,b = smallest_two2(L)
end = time.time()
print "smallest_two2 took %f seconds" %(end-start)

start = time.time()
a,b = smallest_two3(L)
end = time.time()
print "smallest_two3 took %f seconds" %(end-start)
```

### Module:`lec20_searching.py` Find a specific value in a sorted list¶

Code:

```"""
Input: a sorted list and a value

Find the index of value if value is in list
of if it is not, return the index of where
value would be inserted to keep the list sorted.

"""
import random
import time

def search(L,val):
""" Linear search, each item has to be searched. """

for i in range(len(L)):  ## O(n)
if L[i] >= val:
return i
return len(L)-1

def binsearch(L, val):
""" Binary search: always look at the middle value
of a list, then look at the middle value of the remaining
list. You can do this at most O(log n) times, where
log is base 2.

"""

low = 0
high = len(L)-1
while low != high:
mid = (low+high)/2
#print low, high, mid
#raw_input()
if L[mid] < val:
low = mid+1
else:
high = mid
return low

if __name__ == "__main__":

print "Time tests"
k = 500000
L = range(k)
loops = 100

start = time.time()
for i in range(loops):
val = L[random.randrange(500000)] + 0.5
val = k+1
a = search(L, val)
end = time.time()
total = end-start
print "Linear search took", total/loops, "seconds, value found at", a

start = time.time()
for i in range(1000*loops):
val = L[random.randrange(500000)] + 0.5
val = k+1
a = binsearch(L,val)
end = time.time()
total = end-start
print "Binary search took", total/(1000*loops), "seconds, value found at", a
```

## Lecture 21¶

### Module:`test_sort.py` Module and code to test the sorting functions¶

Code:

```'''
Testing code for Computer Science 1, Lecture 21 on sorting. This
assumes that the sort functions are all in file sorts.py, each taking
one list as its only argument, and that their names are sel_sort
ins_sort merge_sort

All tests are based on random permutations of integers.

. In most of our tests, these permutations are completely random,
meaning that a value is equally likely to end up anywhere in the
list.

. In the final test we will explore the implications of working
with lists that are "almost sorted" by only moving values a small
distance from the correct location.  You can see that insertion sort
is very fast in this case by removing the # char in front of
generate_local_perm
'''

import sorts_sol
import time
import random

def run_and_time(name, sort_fcn, v, known_v):
'''
Run the function passed as sort_fcn, timing its performance and
double-checking if it correct.  The correctness check is probably
not necessary.
'''
print "Testing " + name
t0 = time.time()
sort_fcn(v)
t1 = time.time()
print "Time: %.4f seconds" %(t1-t0)
# print "Is correct?", v==known_v
print

def run_and_time_python_sort(v):
'''
Run and time the Python list sort function on the list.
'''
print "Running Python's list sort function"
t0 = time.time()
v.sort()
t1 = time.time()
print "Time: %.4f seconds" %(t1-t0)
print

def generate_local_perm(v,max_shift):
'''
Generate a local permutation by randomly moving each value up to
max_shift locations in the list
'''
for i in range(len(v)):
min_i = max(0,i-max_shift)
max_i = min(len(v)-1, i+max_shift)
new_i = random.randint( min_i, max_i )
v[i], v[new_i] = v[new_i], v[i]

####################################################

if __name__ == '__main__':
n = int(raw_input("Enter the number of values ==> "))
print "----------"
print "Running on %d values" %n
print "----------"

v = range(n)
v1 = v[:]
random.shuffle(v1)
# generate_local_perm(v1, 10)
v2 = v1[:]
v3 = v1[:]
v4 = v1[:]

run_and_time("merge sort", sorts_sol.merge_sort, v3, v )   # passing functions as an arg to a fcn
run_and_time_python_sort(v4 )
run_and_time("selection sort", sorts_sol.sel_sort, v1, v )
run_and_time("insertion sort", sorts_sol.ins_sort, v2, v )

```

### Module:`sorts_start.py` Start of sorting algorithm implementations¶

Code:

```'''
CS 1, Lecture 21

Implementation of a variety of sorting algorithms, including
.  Selection Sort,
.  Insertion Sort
.  Merge Sort
Details will be filled in during lecture.

The main code gives tests for these functions.
'''

def sel_sort( v ):
'''
Sort based on teh O(N^2) selection sort algorithm.  The ideas is
discussed in the text book.  Students are not responsible for
knowing this algorithm.
'''
for i in range(0, len(v)-1):
k = i
for j in range(i+1,len(v)):
if v[j] < v[k]:
k = j
v[i],v[k] = v[k],v[i]

def ins_sort( v ):
'''
The Insertion Sort algorithm
'''
#  Fill in here
for i in range(1,len(v)):
x = v[i]
j = i-1
while j >= 0 and v[j] > x:
v[j+1] = v[j]
j -= 1
v[j+1] = x

def merge(L1,L2):
'''
Merge the contents of two lists, each of which is already sorted
into a single sorted list.
'''
i1 = 0
i2 = 0
L = []

'''
Repeated choose the smallest remaining item from the lists until one
list has no more items that have not been merged.
'''
while i1 < len(L1) and i2 < len(L2):
if L1[i1] < L2[i2]:
L.append( L1[i1] )
i1 += 1
else:
L.append( L2[i2] )
i2 += 1
L.extend(L1[i1:])   #  copy remaining items from L1, if any
L.extend(L2[i2:])   #  copy remaining items from L2, if any
return L

def merge_sort(v):
'''
Implementation of the merge sort algorithm.
'''
if len(v) <= 1:
return

'''
Start by creating the list of singleton lists '''
lists = []
for item in v:
lists.append( [item] )
# print 'Before', lists

'''
Merge the lists in pairs until there is one unmerged list remaining.
A number of print statements, used to see what is happening, are here
in the code but have been commented out.
'''
i = 0
while i < len(lists)-1:
# print '****** i =', i
# print 'input', lists[i]
# print 'input', lists[i+1]
new_list = merge(lists[i], lists[i+1])
lists.append( new_list )
# print 'merged', new_list
i += 2

'''
This is where I made a mistake in class.  I had v = lists[-1], but
that makes v refer to a new list, and the reference is gone when the
function ends.  Instead, by writing v[::], v still refers to the original
list, but it is copied over.
'''
v[::] = lists[-1]

if __name__ == "__main__":
'''
v =  [ 10, 5, 3, 2, -4 ]
ins_sort(v)
print v
v = []
ins_sort(v)
print v
v = [ 5, 6, 7, 6, 5, 5]
ins_sort(v)
print v
'''

'''
v1 = [ 26, 35, 145]
v0 = [ 0, 0, 9, 9, 9.4, 9.6, 15, 21 ]
print v0
print v1
print merge(v0,v1)
'''

v = [ 9.1, 17.5, 9.8, 6.3, 12.4, 1.7 ]
merge_sort(v)
print v

```

### Module:`sorts_sol.py` Solved sorting algorithm implementations (including one fix)¶

Code:

```'''
CS 1, Lecture 21

Implementation of a variety of sorting algorithms, including
.  Selection Sort,
.  Insertion Sort
.  Merge Sort
Details will be filled in during lecture.

The main code gives tests for these functions.
'''

def sel_sort( v ):
'''
Sort based on teh O(N^2) selection sort algorithm.  The ideas is
discussed in the text book.  Students are not responsible for
knowing this algorithm.
'''
for i in range(0, len(v)-1):
k = i
for j in range(i+1,len(v)):
if v[j] < v[k]:
k = j
v[i],v[k] = v[k],v[i]

def ins_sort( v ):
'''
The Insertion Sort algorithm
'''
#  Fill in here
for i in range(1,len(v)):
x = v[i]
j = i-1
while j >= 0 and v[j] > x:
v[j+1] = v[j]
j -= 1
v[j+1] = x

def merge(L1,L2):
'''
Merge the contents of two lists, each of which is already sorted
into a single sorted list.
'''
i1 = 0
i2 = 0
L = []

'''
Repeated choose the smallest remaining item from the lists until one
list has no more items that have not been merged.
'''
while i1 < len(L1) and i2 < len(L2):
if L1[i1] < L2[i2]:
L.append( L1[i1] )
i1 += 1
else:
L.append( L2[i2] )
i2 += 1
L.extend(L1[i1:])   #  copy remaining items from L1, if any
L.extend(L2[i2:])   #  copy remaining items from L2, if any
return L

def merge_sort(v):
'''
Implementation of the merge sort algorithm.
'''
if len(v) <= 1:
return

'''
Start by creating the list of singleton lists '''
lists = []
for item in v:
lists.append( [item] )
# print 'Before', lists

'''
Merge the lists in pairs until there is one unmerged list remaining.
A number of print statements, used to see what is happening, are here
in the code but have been commented out.
'''
i = 0
while i < len(lists)-1:
# print '****** i =', i
# print 'input', lists[i]
# print 'input', lists[i+1]
new_list = merge(lists[i], lists[i+1])
lists.append( new_list )
# print 'merged', new_list
i += 2

'''
This is where I made a mistake in class.  I had v = lists[-1], but
that makes v refer to a new list, and the reference is gone when the
function ends.  Instead, by writing v[::], v still refers to the original
list, but it is copied over.
'''
v[::] = lists[-1]

if __name__ == "__main__":
'''
v =  [ 10, 5, 3, 2, -4 ]
ins_sort(v)
print v
v = []
ins_sort(v)
print v
v = [ 5, 6, 7, 6, 5, 5]
ins_sort(v)
print v
'''

'''
v1 = [ 26, 35, 145]
v0 = [ 0, 0, 9, 9, 9.4, 9.6, 15, 21 ]
print v0
print v1
print merge(v0,v1)
'''

v = [ 9.1, 17.5, 9.8, 6.3, 12.4, 1.7 ]
merge_sort(v)
print v

```

## Lecture 24¶

### Module:`lec24_examples.py` Some simple examples of recursion¶

Code:

```"""
Recursion: Example functions

Basis/Stopping condition:
Define when your function should stop
calling itself recursively

Inductive/Recursive step:
Define how the function can compute its
output by calling itself recursively and then
use the result.

Example:

Recursive step:

factorial(n) =  factorial(n-1)*n

If you had the correct output for  factorial(n-1),
you can multiply it with n to find the correct output.

"""

def blast(n):
if n <= 0: ##basis step
print "Blast off!"
else: ## recursive step
print n
blast(n-1)
print n

def factorial(n):
if n == 1:
return 1
else:
x = factorial(n-1)
return x*n

def factorial_iterative(n):
"""Many recursive functions can be written without recursion. """
x = 1
for i in range(n+1):
x *= i
return x

def fib(n):
"""Fibonacci sequence: Even though it is defined recursively
this function would be much more efficient to write without
recursion.

"""
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)

if __name__ == "__main__":
##Testing code here.
val = int(raw_input("Number => "))
print "Factorial of %d is %d" %(val, factorial(val))

for i in range(10):
print "fib(%d) = %d" %(i, fib(i))

```

### Module:`lec24_sierpinksi.py` Module and code to demonstrate recursion to create a fractal¶

Code:

```"""
Example program shows the use of recursion to create fractals,
in this case, the Sierpinski Triangle. See function:

draw_triangles

for the recursion. The rest is TkInter program allowing the
user to change properties of the Sierpinski triangle drawn.

"""

from Tkinter import *
import math

class MyApp(object):
def __init__(self, parent):
##Function local to init to simplify repetitive button creation process
def put_button(parent, name, functionname, placement):
newbutton = Button(parent, text=name, command=functionname)
newbutton.pack(side=placement)
newbutton.configure(width=button_width,\
return newbutton

## constants used  in the initialization
button_width = 10

## variables used in the program
self.maxlevel = 6
self.size = 600  #3**self.maxlevel
self.maxy = int(self.size*math.sqrt(3)/2)
self.stopped = False
self.depth = 2
self.wait_time = 1
self.parent = parent

## interface elements
## all frames
self.main_frame = Frame(parent)
self.main_frame.pack()
self.top_frame = Frame(self.main_frame)
self.top_frame.pack(side=TOP)
self.bottom_frame = Frame(self.main_frame)
self.bottom_frame.pack(side=BOTTOM)

## canvases: top for info, buttom for drawing Triangles
self.infocanvas = Canvas(self.top_frame, \
width=self.size, height=30)
self.infocanvas.pack(side=TOP)
self.text_area = self.infocanvas.create_text(30,10,anchor='nw')
self.canvas = Canvas(self.top_frame, \
width=self.size, height=self.maxy)
self.canvas.pack(side=BOTTOM)

## buttons: for controlling the program
self.drawbutton = put_button(self.bottom_frame, 'Draw', self.draw, LEFT)
self.clearbutton = put_button(self.bottom_frame, 'Clear', self.clear, LEFT)
self.fasterbutton = put_button(self.bottom_frame, \
"Faster", self.faster, LEFT)
self.slowerbutton = put_button(self.bottom_frame, \
"Slower", self.slower, LEFT)
self.increasebutton = put_button(self.bottom_frame, \
"Depth+1", self.increase, LEFT)
self.decreasebutton = put_button(self.bottom_frame, \
"Depth-1", self.decrease, LEFT)
self.quitbutton = put_button(self.bottom_frame, \
"Quit", self.quit, RIGHT)
## display settings for the program on the info canvas
self.put_info()

def put_info(self):
""" Function for displaying the settings for the program,
depth and wait time for the animation effect.

"""

info = "Wait time: %d ms" %(self.wait_time)
if self.depth == self.maxlevel+3:
info += " "*10+ "Depth: %d (max level reached)" %self.depth
elif self.depth <= 2:
info += " "*10+ "Depth: 2 (min level reached)"
else:
info += " "*10+ "Depth: %d" %self.depth
self.infocanvas.itemconfigure(self.text_area, text=info)

def clear(self):
""" Clear the drawing (used in self.clearbutton). """
self.canvas.delete("all")

def faster(self):
""" Make the animation faster (used in self.fasterbutton). """
self.wait_time /= 2
if self.wait_time <= 0:
self.wait_time = 1
self.put_info()

def slower(self):
""" Make the animation slower (used in self.slowerbutton). """
self.wait_time *= 2
self.put_info()

def increase(self):
""" Increases the depth for recursion (used in self.fasterbutton). """
if self.depth < self.maxlevel+3:
self.depth += 1
self.put_info()

def decrease(self):
""" Decreases the depth for recursion (used in self.slowerbutton). """
if self.depth > 2:
self.depth -= 1
self.put_info()

def draw(self):
""" Clear the canvas and draws the Sierpinksi triangles (used in self.drawbutton). """
padding = 20 ##just leave some space off the corners
if not self.stopped:
self.clear()

def draw_triangles(self, x, y, length, depth):
""" Draws two triangles: one with x,y as the bottom left corner,
in red and a second inverted one inside between the midpoints
of the outside triangle, in white.

"""
if depth <= self.depth:
## Triangle 1: Outside Triangle
mid = length/2
self.canvas.create_polygon(x, y, \
x+length, y, \
x+mid, y-math.sqrt(3)*mid,\
fill = "red")

## Triangle 2: Inside Triangle
leftmid = ( x+(mid)/2, y-(math.sqrt(3)*mid)/2 )
rightmid = (  x+(length+mid)/2, y-(math.sqrt(3)*mid)/2 )
bottommid = ( x+mid, y )

self.canvas.create_polygon( leftmid, leftmid, \
rightmid, rightmid, \
bottommid, bottommid, \
fill = "white" )
self.draw_triangles(x, y, length/2, depth+1)
self.draw_triangles(leftmid, leftmid, length/2, depth)
self.draw_triangles(x+length/2, y, length/2, depth+1)
self.canvas.update()
self.canvas.after(self.wait_time)

def quit(self):
self.stopped = True
self.parent.destroy()

if __name__ == "__main__":
root = Tk()
root.title("Recursion Example with Sierpinski Triangles")
myApp = MyApp(root)
root.mainloop()
```

### Module:`lec24_merge_sort.rec.py` Recursive definition for the merge sort¶

Code:

```
"""

We rewrite merge_sort using recursion and compare to the
iterative version. The recursive version is natural to write
and does not require a list/loop to maintain sublists. As a
result, it is slightly more efficient.

"""

import time
import random

def time_function(L, func):
""" Illustrates how you can send a function as an argument
to another function as well. Runs the function called func,
and returns the time.

"""

L1 = list(L)
start = time.time()
func(L1)
end = time.time()
print "Method: %s took %f seconds" \
%((func.__name__).ljust(20), end-start)

def merge(L1, L2):
""" Assume L1 and L2 are sorted.
Create a new list L that is the merged
version of L1&L2.

This is the efficient version of merge
that does not modify the input lists, as pop
is costly, even though it is a constant time operation.

"""

L = []
i = 0
j = 0
while i < len(L1) and j < len(L2):
if L1[i] < L2[j]:
val = L1[i]
L.append( val )
i += 1
else:
val = L2[j]
L.append( val )
j += 1
## at this point, either L1 or L2 has run out of values
## add all the remaining values to the end of L.
L.extend(L1[i:])
L.extend(L2[j:])
return L

def merge_sort_iterative(L):
""" Complexity: O(n* log n)
See earlier version of this code for explanation.

"""

L1 = []
for val in L:
L1.append( [val] )

while len(L1) > 1:
L2 = []
for i in range(0, len(L1)-1, 2):
Lmerged = merge( L1[i], L1[i+1] )
L2.append( Lmerged )

if len(L1)%2 == 1:
L2.append( L1[-1] )
L1 = L2
return L1

def merge_sort_recursive(L):
""" Complexity: O(n logn)
The function calls itself recursively logn times,
and each time about n elements are merged.

"""

numitems = len(L)
if numitems <= 1:
return L
else:
mid = numitems/2
L1 = merge_sort_recursive( L[:mid] )
L2 = merge_sort_recursive( L[mid:] )
return merge(L1, L2)

if __name__ == "__main__":
##Testing code
k = 100000
L = range(k)
random.shuffle(L)

time_function( L, merge_sort_iterative )
time_function( L, merge_sort_recursive )
time_function( L, list.sort )

```