Difference between revisions of "CSC111 Lab 13 2015"

From dftwiki3
Jump to: navigation, search
 
(23 intermediate revisions by the same user not shown)
Line 16: Line 16:
 
Write a graphics program that uses a white background, and makes a fish appear wherever the user clicks the mouse.   
 
Write a graphics program that uses a white background, and makes a fish appear wherever the user clicks the mouse.   
 
Once the fish appears on the screen it moves slowly to one side and disappears.  While the fish is moving, the user may click on the screen, and make other fish appear.  The new fish will then move at the same pace as the first fish, assuming it is still visible.
 
Once the fish appears on the screen it moves slowly to one side and disappears.  While the fish is moving, the user may click on the screen, and make other fish appear.  The new fish will then move at the same pace as the first fish, assuming it is still visible.
 +
<br />
 +
Your program should stop when the user clicks in the top-left area of the screen.  Imagine a 30x30 square at the top left of the screen; if the user clicks the mouse in this square, then the program exits and closes the window.
 +
<br />
 +
Helpful links:
 +
# [[Fish_for_an_Aquarium| page with fish images]]
 +
# [http://mcsp.wartburg.edu/zelle/python/graphics/graphics.pdf Documentation for the graphics library]
 +
# [[Zelle%27s_Graphics.py_for_Python_3| Zelle's graphic library]]
 +
<br />
 +
==Submission==
 +
<br />
 +
Locate the LAB13 PB 1 links on your Moodle page, and submit a running version of your program, called '''lab13_1.py''', as well as a '''screen capture''' of the graphics window showing several fish. 
 
<br />
 
<br />
 
=Problem 2=
 
=Problem 2=
 
<br />
 
<br />
The file at URL [http://cs.smith.edu/dftwiki/media/1000movies.txt http://cs.smith.edu/dftwiki/media/1000movies.txt] contains the list of the best 1000 movies of all times, according to [http://www.nytimes.com/ref/movies/1000best.html The New York Times].
+
==Part 1==
 
<br />
 
<br />
 +
The file at URL [http://cs.smith.edu/dftwiki/media/1000movies0.txt http://cs.smith.edu/dftwiki/media/1000movies0.txt] contains the list of the best 1000 movies of all times, according to [http://www.nytimes.com/ref/movies/1000best.html The New York Times] (the file actually contains 1004 movies).  Note, also, that some foreign characters have been removed from the movie titles to prevent Python from crashing on non standard characters (it could crash in some implementations, and work fine in others).
 +
<br />
 +
 
Write a program that will:
 
Write a program that will:
 
# Ask the user for the year she was born in, e.g. 1995,
 
# Ask the user for the year she was born in, e.g. 1995,
# Read the contents of the file at the URL specified above
+
# Read the contents of the file at the URL specified above (you may want to take a look back at the [[CSC111_Lab_5_2015|Lab 5 companion program]] that reads a page of text stored at a URL).
 
# Find all the movies that were released in the year specified by the user
 
# Find all the movies that were released in the year specified by the user
 
# Output the movies sorted by alphabetical order.  The year (or parentheses around the year) should '''not''' appear in the lines listing the movie titles.  
 
# Output the movies sorted by alphabetical order.  The year (or parentheses around the year) should '''not''' appear in the lines listing the movie titles.  
# Save the list to a file called movies1995.txt (replace 1995 by whatever number the user specified as year).
+
# Save the list to a file called '''movies.txt'''.
 +
<br />
 +
==Typical Output File==
 +
<br />
 +
* Below is the contents of movies.txt for a user born in 1995:
 +
<br />
 +
<source lang="text">
 +
Apollo 13
 +
Clueless
 +
Dead Man Walking
 +
Leaving Las Vegas
 +
Living in Oblivion
 +
Persuasion
 +
Sense and Sensibility
 +
The Usual Suspects
 +
Toy Story
 +
 
 +
</source>
 +
<br />
 +
==Part 2==
 +
<br />
 +
When your program works for Part 1, change the URL to this: [http://cs.smith.edu/dftwiki/media/1000movies.txt http://cs.smith.edu/dftwiki/media/1000movies.txt].  The new URL contains extra lines that do not contain valid movie names.  For example a line containing only the letter '''B''', indicating that all following movie titles start with '''B'''.  Make your program work with the new URL, assuming the same interaction with the user.
 +
<br />
 +
=Important Requirement=
 
<br />
 
<br />
 +
* Your program must include a '''main()''' function that is the main entry point of your program.  The test program will call your '''main()''' function to run your program, and if there isn't a '''main()''' function, your program will not be tested correctly.
 
<br />
 
<br />
There is nothing to submit to Moodle this week.  Just concentrate on making sure you get working versions of the solution programs for this lab.
+
=Submission=
 
<br />
 
<br />
 +
Submit your solution to the second problem to Moodle, in the Lab13 section.
 
<br />
 
<br />
 
</showafterdate>
 
</showafterdate>
 
<br />
 
<br />
 +
 
<br />
 
<br />
 
<showafterdate after="20150501 11:00" before="20150601 00:00">
 
<showafterdate after="20150501 11:00" before="20150601 00:00">
Line 41: Line 81:
 
<br />
 
<br />
 
<source lang="python">
 
<source lang="python">
 +
# lab13_1.py
 +
# D. Thiebaut
 +
# Graphics program that puts fish wherever the user
 +
# clicks on the window.  The fish wrap around when they go
 +
# off the window, although this was not a required feature in
 +
# the lab.
 +
# The program stops when the user clicks close to the top-left
 +
# corner of the window (within 20 pixels of the point 0,0).
 +
from graphics import *
 +
import random
 +
 +
WIDTH = 800
 +
HEIGHT = 600
 +
 +
class Fish:
 +
    """A class that represents a fish, with an image."""
 +
   
 +
    def __init__( self, refP ):
 +
        """constructs the fish with an image"""
 +
        self.image = Image( refP, "fish10.gif" )
 +
   
 +
    def draw( self, win ):
 +
        """draws the fish on the window..."""
 +
        self.image.draw( win )
 +
 +
    def autoMove( self ):
 +
        """make the fish move to the right, some random distance"""
 +
        self.image.move( random.randrange( 4 ), 0 )
 +
        if self.image.getAnchor().getX() > WIDTH+50:
 +
            self.image.move( -WIDTH-100, 0 )
 +
 +
def isInCorner( p ):
 +
    """Returns True if the point p is within 20 pixels of the top left
 +
    corner of the window, and False otherwise."""
 +
    if p.getX() < 20 and p.getY() < 20:
 +
        return True
 +
    return False
 +
       
 +
def main():
 +
    win = GraphWin( "Lab 13", WIDTH, HEIGHT )
 +
 +
    # get ready to add fish...
 +
    fishList = []
 +
   
 +
    #animation loop
 +
    while True:
 +
        p = win.checkMouse()
 +
 +
        # user clicked the mouse...
 +
        if p != None:
 +
 +
            # is it in the upper-left corner?
 +
            if isInCorner( p ):
 +
                break
 +
 +
            fish = Fish( p )
 +
            fish.draw( win )
 +
            fishList.append( fish )
 +
 +
        # move all the fish, a tiny bit...
 +
        for fish in fishList:
 +
            fish.autoMove()
 +
 +
    win.close()
 +
 +
main()
 +
       
  
 
</source>
 
</source>
 +
<br />
 
=Program 2=
 
=Program 2=
 
<br />
 
<br />
 
<source lang="python">
 
<source lang="python">
 +
 +
# lab13_2.py
 +
# D. Thiebaut
 +
# This program reads a text file stored at a given URL and
 +
# extracts information that matches the user's specified string.
 +
#
 +
import urllib.request  # the lib that handles the url stuff
 +
 +
url = "http://cs.smith.edu/dftwiki/media/1000movies.txt"
 +
 +
 +
def getText( url ):
 +
    """gets the contents of the text file at the given URL"""
 +
    # fetch the file and put its contents in the
 +
    # string text.
 +
    response = urllib.request.urlopen( url )
 +
    text    = response.read().decode( 'UTF-8' )
 +
    return text
 +
 +
def saveToFile( fileName, text ):
 +
    """save the text into the given file """
 +
    file = open( fileName, "w" )
 +
    file.write( text + "\n" )
 +
    file.close()
 +
   
 +
def main():
 +
    """retrieve the file at the given URL, gets a year
 +
    from the user, and outputs all the lines containing that
 +
    given year.  The output is also saved to a file."""
 +
    text = getText( url )
 +
 +
    year = input( "Year you were born? " ).strip()
 +
 +
    list = []
 +
    for line in text.split( "\n" ):
 +
        index = line.find( "(" + year )
 +
        if index != -1:
 +
            line = line[0:index].strip()
 +
            #print( line )
 +
            list.append( line )
 +
 +
    list.sort()
 +
    for line in list:
 +
        print( line )
 +
 +
    saveToFile( "movies"+year+".txt", "\n".join( list ) )
 +
 +
 +
if __name__=="__main__":  main()
 +
 +
 +
 +
 +
</source>
 +
 +
<br />
 +
<onlydft>
 +
 +
=VPL=
 +
<br />
 +
==vpl_run.sh==
 +
<br />
 +
<source lang="bash">
 +
</source>
 +
<br />
 +
==vpl_debug.sh==
 +
<br />
 +
<source lang="bash">
 +
</source>
 +
<br />
 +
==vpl_evaluate.sh==
 +
<br />
 +
<source lang="bash">
 +
#! /bin/bash
 +
 +
cat  > vpl_execution <<EOF
 +
#! /bin/bash
 +
 +
# --- Python ----
 +
if [[ `hostname -s` = "beowulf2" ]]; then
 +
  python=/usr/bin/python3.3
 +
else
 +
  python=/usr/local/bin/python3.4
 +
fi
 +
 +
 +
\$python evaluate.py
 +
 +
EOF
 +
 +
chmod +x vpl_execution
 +
  
 
</source>
 
</source>
 
<br />
 
<br />
 +
==vpl_evaluate.cases==
 +
<br />
 +
<br />
 +
==evaluate.py==
 +
<br />
 +
<source lang="python">
 +
# evaluate.py
 +
# D. Thiebaut
 +
# This program is used to test a student's python program on Moodle.
 +
 +
import sys
 +
import random
 +
import subprocess
 +
#import pyminifier
 +
 +
#--- GLOBALS ---
 +
#--- define what the student program is called, and what the solution
 +
#--- program name is.
 +
 +
debug  = False #True
 +
module = "lab13_2"
 +
solutionModule = "lab13_2sol"
 +
userOutSplitPattern = ""      # pattern used to start recording the user
 +
                              # output.  Useful when program does several
 +
                              # input() statements, and user output starts
 +
                              # after that.
 +
stripOutputsBeforeCompare = True
 +
                              # set to True if extra spaces at beginning or
 +
                              # end of user output is ok
 +
 +
interpreter = sys.executable
 +
 +
def commentLong( line ):
 +
    print( "<|--\n" + line  + "\n --|>" )
 +
 +
def commentShort( text ):
 +
    print( "Comment :=>> " + text )
 +
 +
def comment( text ):
 +
    commentShort( text )
 +
 +
def printGrade( grade ):
 +
    print( "Grade :=>> ", grade )
 +
 +
# remove if __name__==...
 +
def removeIfNameEqMain( fileName ):
 +
    file = open( fileName, "r" )
 +
    lines = file.read()
 +
    file.close()
 +
 +
    newLines = ""
 +
    for line in lines.split( "\n" ):
 +
        if line.find( "__name__" )!=-1 and line.find( "__main__" )!=-1 and line.find( "if True" )==-1:
 +
            line = "if True: #" + line
 +
        newLines += line + "\n"
 +
 +
    # write it back
 +
    file = open( fileName, "w" )
 +
    file.write( newLines )
 +
    file.close()
 +
 +
# add if __name__=="__main__": to the program
 +
def addIfNameEqMain( fileName ):
 +
    file = open( fileName, "r" )
 +
    lines = file.read()
 +
    file.close()
 +
 +
    newLines = ""
 +
    for line in lines.split( "\n" ):
 +
        if line.find( "main()" )==0:
 +
            line = 'if __name__=="__main__":  main()'
 +
        newLines += line + "\n"
 +
 +
    # write it back
 +
    file = open( fileName, "w" )
 +
    file.write( newLines )
 +
    file.close()
 +
 +
def createEmptyFile( fileName ):
 +
    file = open( fileName, "w" )
 +
    file.write( "\n" )
 +
    file.close()
 +
 +
# generateInputFileWithRandomInputs
 +
# generate a file with name "inputFileName" with some random input
 +
# for the program.
 +
# MAKE SURE TO EDIT THIS TO MATCH THE PROGRAM BEING TESTED
 +
def generateTestModule( moduleName, i ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    code = """
 +
from hw12_1 import *
 +
 +
def main():
 +
    A = %s
 +
    low, high = smallestLargest( A )
 +
    print( low, high )
 +
 +
if __name__=="__main__":
 +
    main()
 +
"""
 +
    if debug: print( "generateTestModule(", moduleName, ", ", i ,")" )
 +
    if i==0:
 +
        s = "[1, -100, 200, 5, 0]"
 +
    if i==1:
 +
        s = "[100]"
 +
    if i==2:
 +
        s = "[]"
 +
    if i==3:
 +
        s = '[ "lucy", "marie", "joe", "larry"]'
 +
 +
    file = open( moduleName+".py", "w" )
 +
    file.write( code % s )
 +
    file.write( "\n" )
 +
    file.close()
 +
    return s
 +
 +
def generateSolutionModule( moduleName, i ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    code = """
 +
def smallestLargest( A ):
 +
    if len( A )==0:
 +
        return None, None
 +
 +
    if len( A )==1:
 +
        return A[0], A[0]
 +
 +
    theMin, theMax = smallestLargest( A[1: ] )
 +
 +
    if A[0] < theMin:
 +
        theMin = A[0]
 +
    if A[0] > theMax:
 +
        theMax = A[0]
 +
 +
    return theMin, theMax
 +
 +
def main():
 +
    A = %s
 +
    low, high = smallestLargest( A )
 +
    print( low, high )
 +
 +
if __name__=="__main__":
 +
    main()
 +
"""
 +
    if i==0:
 +
        s = "[1, -100, 200, 5, 0]"
 +
    if i==1:
 +
        s = "[100]"
 +
    if i==2:
 +
        s = "[]"
 +
    if i==3:
 +
        s = '[ "lucy", "marie", "joe", "larry"]'
 +
 +
    file = open( moduleName+".py", "w" )
 +
    file.write( code % s )
 +
    file.write( "\n" )
 +
    file.close()
 +
    return s
 +
 +
# checkForFunctionPresence
 +
# checks that "functionName" is defined and called in the program.
 +
# MAKE SURE TO EDIT TO MATCH PROGRAM BEING TESTED
 +
def checkForFunctionPresence( module, functionName ):
 +
    foundDef = False
 +
    foundCall = False
 +
 +
    for line in open( module+".py", "r" ).readlines():
 +
        # remove comments
 +
        idx = line.find( "#" )
 +
        if ( idx >=0 ): line = line[0:idx]
 +
 +
        if line.startswith( "def " + functionName + "(" ):
 +
            foundDef = True
 +
            continue
 +
        if line.startswith( "def " + functionName + " (" ):
 +
            foundDef = True
 +
            continue
 +
        if line.find( functionName+"(" ) != -1:
 +
            foundCall = True
 +
            continue
 +
 +
    return (foundDef, foundCall)
 +
 +
 +
 +
# ==================================================================
 +
# NO EDITS NEEDED BELOW!
 +
# ==================================================================
 +
 +
def clearLog():
 +
    open( "log.txt", "w" ).write( "" )
 +
 +
def log( message ):
 +
    file = open( "log.txt", "a" )
 +
    file.write( message + "\n" )
 +
    file.flush()
 +
    file.close()
 +
 +
 +
# checkModuleRunsOK: runs the module as a shell subprocess and
 +
# look for errors in the output.  This is required, because otherwise
 +
# importing the module in this program will make this program crash.
 +
# It's not possible (as far as I can tell0 to catch exceptions from
 +
# the import or __module__ statements.
 +
# returns True, none if no errors, otherwise False, string if there's
 +
# an exception, and the error message (string) is in the returned 2nd
 +
# arg.
 +
# The module name is assumed to not include ".py"
 +
def checkModuleRunsOk( module, inputFileName ):
 +
    global interpreter
 +
    p = subprocess.Popen( [ interpreter, module+".py" ],
 +
                          stdout=subprocess.PIPE,
 +
                          stderr=subprocess.PIPE,
 +
                          stdin=subprocess.PIPE)
 +
 +
    #print( "inputFileName = ", inputFileName )
 +
    #print( "open( inputFileName, r).read() = ", open( inputFileName, "r" ).read() )
 +
 +
    p.stdin.write( bytes( open( inputFileName, "r" ).read(), 'UTF-8' ) )
 +
    try:
 +
      data = p.communicate( timeout=2 )  # timeout after 10sec
 +
    except subprocess.TimeoutExpired:
 +
      error = "Your program timed out. Very likely an infinite loop!"
 +
      return False, error
 +
    p.stdin.close()
 +
 +
    error = data[1].decode( 'UTF-8' )
 +
    if len( error ) > 1:
 +
        return False, error
 +
    return True, None
 +
 +
def firstLastLines( text ):
 +
    lines = text.split( "\n" )
 +
    if len( lines ) > 20:
 +
        text = "\n".join( lines[0:5] )+"\n...\n" + "\n".join( lines[-5:] )
 +
    return text
 +
 +
# extractTextFromErrorMessage( sys_exc_info ):
 +
def extractTextFromErrorMessage( sys_exc_info ):
 +
    if debug: print( "sys_exec_info = ", sys_exc_info )
 +
    text = ""
 +
    try:
 +
        for field in sys_exc_info:
 +
            if type( field )==type( " " ):
 +
                text += field + "\n"
 +
    except:
 +
        text = sys_exc_info
 +
    return text
 +
 +
# runModule:
 +
# runs the module, passes it data from the input file on its stdin
 +
# and get its output on stdout captured in outputFileName.
 +
# We assume the module will not crash, because we already tested
 +
# it with checkModuleRunsOk().
 +
def runModule( module, inputFileName, outputFileName ):
 +
    global userOutSplitPattern
 +
 +
    error = False
 +
 +
    #--- make stdin read information from the text file
 +
    sys.stdin = open( inputFileName, "r" )
 +
 +
    #--- capture the stdout of the program to test into a file
 +
    saveStdOut = sys.stdout
 +
    saveStdErr = sys.stderr
 +
 +
    sys.stdout = open( outputFileName, "w" )
 +
    sys.stderr = open( "errorOut", "w" )
 +
 +
    #--- run the student program ---
 +
    try:
 +
        _module = __import__(  module  )
 +
        _module.main()
 +
    except:
 +
        error = True
 +
        sys.stderr.close()
 +
        sys.stderr = saveStdErr
 +
        sys.stdout.close()
 +
        sys.stdout = saveStdOut
 +
        text = sys.exc_info()[0]
 +
        text = extractTextFromErrorMessage( text )
 +
        #print( "*** sys.exc_info() = ", text )
 +
        try:
 +
            text = open( outputFileName, "r" ).read() + "\n" + text
 +
        except:
 +
            pass
 +
        return error, text, 0
 +
 +
 +
 +
    #--- filter out junk from output of program ---
 +
    sys.stdout.close()
 +
    sys.stdout = saveStdOut
 +
    sys.stderr.close()
 +
    sys.stderr = saveStdErr
 +
 +
    file = open( outputFileName, "r" )
 +
    text = file.read()
 +
    file.close()
 +
    if debug:
 +
        print( "runModule( ", module, " ) returns text = <", text , ">" )
 +
 +
    return False, text, 0
 +
 +
def removeBlankLines( lines ):
 +
    newLines = []
 +
    log( "removeBlankLines: lines = " + str( lines ) )
 +
    for line in lines.split( "\n" ):
 +
        if len( line )==0:
 +
            continue
 +
        newLines.append( line )
 +
 +
    return ( "\n".join( newLines ) ) + "\n"
 +
 +
def compareUserExpected( inputLines, userOutText, expectedOutText ):
 +
    global stripOutputsBeforeCompare
 +
 +
    log( "compareUserExpected:\nuserOutText = " + userOutText )
 +
    log( "expectedOutText = " + expectedOutText )
 +
 +
    userOutText = removeBlankLines( userOutText )
 +
    expectedOutText = removeBlankLines( expectedOutText )
 +
    misMatchLineNumbers = []
 +
    userTextOutLines = userOutText.split( "\n" )
 +
    expectedOutTextLines = expectedOutText.split( "\n" )
 +
 +
    log( "-" * 60 )
 +
    log( "userTextOutLines = " + str( userTextOutLines ) )
 +
    log( "expectedOutTextLines = " + str( expectedOutTextLines ) )
 +
    log( "-" * 60 )
 +
 +
    for i in range( len( userTextOutLines ) ):
 +
        lineNo = i+1
 +
        userLine = userTextOutLines[i]
 +
        if i >= len( expectedOutTextLines ):
 +
            misMatchLineNumbers.append( lineNo )
 +
            break
 +
        expectedLine = expectedOutTextLines[i]
 +
        log( "compareUserExpected: comparing:\n  "+userLine+"\n  "+expectedLine )
 +
        if stripOutputsBeforeCompare:
 +
            userLine = userLine.strip()
 +
            expectedLine = expectedLine.strip()
 +
        if userLine != expectedLine:
 +
            log( "\ndifference:\n  user    >" + userTextOutLines[i] + "<" )
 +
            log( "\n  expected >" + expectedOutTextLines[i] + "<" )
 +
            misMatchLineNumbers.append( lineNo )
 +
 +
    return misMatchLineNumbers
 +
 +
 +
 +
def main():
 +
    global module
 +
    global solutionModule
 +
    studentModule = module
 +
 +
    #--- remove if __name__=="__main__" statement, if it's here...
 +
    addIfNameEqMain( studentModule+ ".py" )
 +
 +
    #--- clear debug log ---
 +
    clearLog()
 +
 +
    #--- remove comments ---
 +
    file = open( studentModule+".py", "r" )
 +
    text = file.read( )
 +
    file.close()
 +
 +
    #text = pyminifier.removeComments( text )
 +
    #file = open( studentModule+".py", "w" )
 +
    #file.write( text + "\n" )
 +
    #file.close()
 +
 +
    #--- check that the main module uses a main() function
 +
    #foundDef, foundCall = checkForFunctionPresence( studentModule, "min" )
 +
    #if foundCall:
 +
    #    commentShort( "You are using the function min(), which was not allowed." )
 +
    #    printGrade( 5 )
 +
    #    return
 +
 +
    #foundDef, foundCall = checkForFunctionPresence( studentModule, "max" )
 +
    #if foundCall:
 +
    #    commentShort( "You are using the function max(), which was not allowed." )
 +
    #    printGrade( 5 )
 +
    #    return
 +
 +
 +
    # test that module runs on its own without problem
 +
    file = open( "input.txt", "w" )
 +
    file.write( "\n" )
 +
    file.close()
 +
 +
    Ok, errorMessage = checkModuleRunsOk( module, "input.txt" )
 +
    if not Ok:
 +
        errorMessage = firstLastLines( errorMessage )
 +
        commentLong( "- Your program crashed...\n"
 +
                        + "Error message:\n"
 +
                    + errorMessage + "\n" )
 +
        printGrade( 5 )
 +
        return
 +
 +
    gradeIncrement = 25
 +
    grade          = 0
 +
    inputYears = [1977, 1960, 1981, 1995, 1993, 1962, 1964, 1980, 1992, 1961, 1964, 1947 ]
 +
    for testNo in [0, 1, 2, 3]:
 +
        if testNo == 0:  inputYear  = random.choice( inputYears[0:3] )
 +
        if testNo == 1:  inputYear  = random.choice( inputYears[3:6] )
 +
        if testNo == 2:  inputYear  = random.choice( inputYears[6:9] )
 +
        if testNo == 3:  inputYear  = random.choice( inputYears[9: ] )
 +
        inputFile = open( "input.txt", "w" )
 +
        inputFile.write( str( inputYear ) + "\n\n\n" )
 +
        inputFile.close()
 +
 +
        dummy, expectedOutText, score2 = runModule( solutionModule,
 +
                                                    "input.txt", "expectedOut" )
 +
        if debug: print( "expectedOutText = ", expectedOutText )
 +
 +
 +
        outputFileName = "movies" + str(inputYear) + ".txt"
 +
        file = open( outputFileName, "r" )
 +
        expectedOutText = file.read()
 +
        file.close()
 +
 +
        error, userOutText, score2  = runModule( module, "input.txt", "userOut" )
 +
 +
        if debug: print( "runModule user:", error, userOutText, score2 )
 +
        if error:
 +
            commentLong( "- Your program crashed...\n"
 +
                        + "Error message:\n"
 +
                        + userOutText + "\n" )
 +
 +
        userOutText = ""
 +
        try:
 +
            file = open( outputFileName, "r" )
 +
            userOutText = file.read( )
 +
            file.close()
 +
        except:
 +
            commentLong( "Your program does not seem to have created a file called "+outputFileName
 +
                        +".\nCannot read this file.\n" )
 +
            printGrade( 10 )
 +
            exit()
 +
 +
        missMatches = compareUserExpected( ["\n"], userOutText, expectedOutText )
 +
        if debug: print( " missMatches = ", missMatches )
 +
 +
        if len( missMatches ) != 0:
 +
            commentLong( "- Incorrect output for year " +str( inputYear ) + "...\n"
 +
                        +"input list = \n"
 +
                        +"Expected output:\n"
 +
                        +expectedOutText + "\n"
 +
                        +"Your output:\n"
 +
                        +userOutText + "\n" )
 +
            #printGrade( len( missMatches ) * 20 )
 +
            grade += 10
 +
        else:
 +
            commentLong( "- Your program passes the test\n"
 +
                        + "Test year = " + str( inputYear )  +"\n" )
 +
            grade += gradeIncrement
 +
 +
    printGrade( grade )
 +
 +
main()
 +
 +
</source>
 +
<br />
 +
==lab13_2sol.py==
 +
<br />
 +
<source lang="python">
 +
# lab13_2.py
 +
# D. Thiebaut
 +
# This program reads a text file stored at a given URL and
 +
# extracts information that matches the user's specified string.
 +
#
 +
import urllib.request  # the lib that handles the url stuff
 +
 +
url = "http://cs.smith.edu/dftwiki/media/1000movies.txt"
 +
 +
 +
def getText( url ):
 +
    """gets the contents of the text file at the given URL"""
 +
    # fetch the file and put its contents in the
 +
    # string text.
 +
    response = urllib.request.urlopen( url )
 +
    text    = response.read().decode( 'UTF-8' )
 +
    return text
 +
 +
def saveToFile( fileName, text ):
 +
    """save the text into the given file """
 +
    file = open( fileName, "w" )
 +
    file.write( text + "\n" )
 +
    file.close()
 +
 +
def main():
 +
    """retrieve the file at the given URL, gets a year
 +
    from the user, and outputs all the lines containing that
 +
    given year.  The output is also saved to a file."""
 +
    text = getText( url )
 +
 +
    year = input( "Year you were born? " ).strip()
 +
 +
    list = []
 +
    for line in text.split( "\n" ):
 +
        if line.find( year ) != -1:
 +
            index = line.find( "(" )
 +
            line = line[0:index].strip()
 +
            print( line )
 +
            list.append( line )
 +
 +
    saveToFile( "movies"+year+".txt", "\n".join( list ) )
 +
 +
 +
if __name__=="__main__":  main()
 +
 +
 +
 +
 +
 +
 +
</source>
 +
<br />
 +
 +
 +
</onlydft>
 
<br />
 
<br />
 
[[Category:CSC111]][[Category:Labs]]
 
[[Category:CSC111]][[Category:Labs]]

Latest revision as of 07:23, 21 June 2015

--D. Thiebaut (talk) 09:59, 27 April 2015 (EDT)




<showafterdate after="20150429 13:00" before="20150601 00:00">

This lab is a preparation for the Final Exam. You will notice that the amount of explanations is limited, and you are asked to start from scratch writing a program. The lab will start with a general discussion about approaching the problems, and getting started with such assignments.
Feel free to work in pair programming mode on this assignment.


Problem 1


Write a graphics program that uses a white background, and makes a fish appear wherever the user clicks the mouse. Once the fish appears on the screen it moves slowly to one side and disappears. While the fish is moving, the user may click on the screen, and make other fish appear. The new fish will then move at the same pace as the first fish, assuming it is still visible.
Your program should stop when the user clicks in the top-left area of the screen. Imagine a 30x30 square at the top left of the screen; if the user clicks the mouse in this square, then the program exits and closes the window.
Helpful links:

  1. page with fish images
  2. Documentation for the graphics library
  3. Zelle's graphic library


Submission


Locate the LAB13 PB 1 links on your Moodle page, and submit a running version of your program, called lab13_1.py, as well as a screen capture of the graphics window showing several fish.

Problem 2


Part 1


The file at URL http://cs.smith.edu/dftwiki/media/1000movies0.txt contains the list of the best 1000 movies of all times, according to The New York Times (the file actually contains 1004 movies). Note, also, that some foreign characters have been removed from the movie titles to prevent Python from crashing on non standard characters (it could crash in some implementations, and work fine in others).

Write a program that will:

  1. Ask the user for the year she was born in, e.g. 1995,
  2. Read the contents of the file at the URL specified above (you may want to take a look back at the Lab 5 companion program that reads a page of text stored at a URL).
  3. Find all the movies that were released in the year specified by the user
  4. Output the movies sorted by alphabetical order. The year (or parentheses around the year) should not appear in the lines listing the movie titles.
  5. Save the list to a file called movies.txt.


Typical Output File


  • Below is the contents of movies.txt for a user born in 1995:


Apollo 13
Clueless
Dead Man Walking
Leaving Las Vegas
Living in Oblivion
Persuasion
Sense and Sensibility
The Usual Suspects
Toy Story


Part 2


When your program works for Part 1, change the URL to this: http://cs.smith.edu/dftwiki/media/1000movies.txt. The new URL contains extra lines that do not contain valid movie names. For example a line containing only the letter B, indicating that all following movie titles start with B. Make your program work with the new URL, assuming the same interaction with the user.

Important Requirement


  • Your program must include a main() function that is the main entry point of your program. The test program will call your main() function to run your program, and if there isn't a main() function, your program will not be tested correctly.


Submission


Submit your solution to the second problem to Moodle, in the Lab13 section.
</showafterdate>


<showafterdate after="20150501 11:00" before="20150601 00:00">

Solution Programs


Program 1


# lab13_1.py
# D. Thiebaut
# Graphics program that puts fish wherever the user
# clicks on the window.   The fish wrap around when they go
# off the window, although this was not a required feature in
# the lab.
# The program stops when the user clicks close to the top-left
# corner of the window (within 20 pixels of the point 0,0).
from graphics import *
import random

WIDTH = 800
HEIGHT = 600

class Fish:
    """A class that represents a fish, with an image."""
    
    def __init__( self, refP ):
        """constructs the fish with an image"""
        self.image = Image( refP, "fish10.gif" )
    
    def draw( self, win ):
        """draws the fish on the window..."""
        self.image.draw( win )

    def autoMove( self ):
        """make the fish move to the right, some random distance"""
        self.image.move( random.randrange( 4 ), 0 )
        if self.image.getAnchor().getX() > WIDTH+50:
            self.image.move( -WIDTH-100, 0 )

def isInCorner( p ):
    """Returns True if the point p is within 20 pixels of the top left
    corner of the window, and False otherwise."""
    if p.getX() < 20 and p.getY() < 20:
        return True
    return False
        
def main():
    win = GraphWin( "Lab 13", WIDTH, HEIGHT )

    # get ready to add fish...
    fishList = []
    
    #animation loop
    while True:
        p = win.checkMouse()

        # user clicked the mouse...
        if p != None:

            # is it in the upper-left corner?
            if isInCorner( p ):
                break

            fish = Fish( p )
            fish.draw( win )
            fishList.append( fish )

        # move all the fish, a tiny bit...
        for fish in fishList:
            fish.autoMove()

    win.close()

main()


Program 2


# lab13_2.py
# D. Thiebaut
# This program reads a text file stored at a given URL and 
# extracts information that matches the user's specified string.
#
import urllib.request  # the lib that handles the url stuff

url = "http://cs.smith.edu/dftwiki/media/1000movies.txt"


def getText( url ):
    """gets the contents of the text file at the given URL"""
    # fetch the file and put its contents in the
    # string text.
    response = urllib.request.urlopen( url )
    text     = response.read().decode( 'UTF-8' )
    return text

def saveToFile( fileName, text ):
    """save the text into the given file """
    file = open( fileName, "w" )
    file.write( text + "\n" )
    file.close()
    
def main():
    """retrieve the file at the given URL, gets a year
    from the user, and outputs all the lines containing that
    given year.  The output is also saved to a file."""
    text = getText( url )

    year = input( "Year you were born? " ).strip()

    list = []
    for line in text.split( "\n" ):
        index = line.find( "(" + year )
        if index != -1:
            line = line[0:index].strip()
            #print( line )
            list.append( line )

    list.sort()
    for line in list:
        print( line )

    saveToFile( "movies"+year+".txt", "\n".join( list ) )


if __name__=="__main__":  main()



...