Difference between revisions of "CSC111 Lab 8 2015"

From dftwiki3
Jump to: navigation, search
 
(23 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
----
 
----
  
<showafterdate after="20150325" before="20150601">
 
  
 +
<tanbox>
 +
The submission page for this lab is here: [http://tinyurl.com/CSC111Lab8Submit http://tinyurl.com/CSC111Lab8Submit]
 +
<br />
 +
The long URL is [http://cs.smith.edu/dftwiki/index.php?title=CSC111_Lab_8_Submission_2015  http://cs.smith.edu/dftwiki/index.php?title=CSC111_Lab_8_Submission_2015].
 +
</tanbox>
 +
 +
<br />
 +
<showafterdate after="20150325 11:00" before="20150601 00:00">
 +
<br />
 +
<bluebox>
 +
Work out all the problems of this lab, and when you are done demonstrate your working program to the lab instructor or a TA.  Upon verification that your programs work well, you will be given a URL explaining what your have to submit on Moodle for this lab.  The deadline for submitting on Moodle is Friday 11:00 a.m., just before class.
 +
</bluebox>
 +
<br />
 +
<br />
 
=Preamble=
 
=Preamble=
 
<br />
 
<br />
Line 45: Line 58:
 
</source>
 
</source>
 
<br />
 
<br />
Complete the function '''getPositiveNumber()''' so that it asks the user for a number larger than 0, and keeps on prompting the user as long as she doesn't enter a valid number.
+
Remove the '''return 10''' statement in ''getPositiveNumber()'', and complete the function so that it asks the user for a number larger than 0, and keeps on prompting the user as long as she doesn't enter a valid number.
  
 
Below is an example of the interaction between computer and user.
 
Below is an example of the interaction between computer and user.
Line 72: Line 85:
  
 
<br />
 
<br />
Same idea as in Exercise 1, but this time the new function, called '''getYesNo()''' will keep on asking a question until the user's input is "YES", "yes", "y", "NO", "no", or "n".  Any combination of lower/upper case in the spelling is accepted ("yES" is valid).
+
Same idea as in Exercise 1, but this time the new function, called '''likesChoco()''' will keep on asking a question until the user's input is "YES", "yes", "y", "NO", "no", or "n".  Any combination of lower/upper case in the spelling is accepted ("yES" is valid).  The function will return '''True''' if the user answers yes, and '''False''' otherwise.
 
<br />
 
<br />
 
;Source
 
;Source
 
<br />
 
<br />
 
::<source lang="python">
 
::<source lang="python">
def getYesNo():
+
def likesChoco():
 
     #
 
     #
 
     # put your code here
 
     # put your code here
 
     #
 
     #
     return "Y"   # just to make sure the code works as is.
+
     return True   # just to make sure the code works as is.
 
              
 
              
 
def main():
 
def main():
 
     # Part1, Exercise 2
 
     # Part1, Exercise 2
     likesChoco = getYesNo()
+
     if likesChoco() == True:
    if likesChoco in ["YES", "Y" ]:
 
 
         print( "Me too!" )
 
         print( "Me too!" )
 
     else:
 
     else:
Line 233: Line 245:
  
 
# define constants for indicating the winner of a round
 
# define constants for indicating the winner of a round
HUMAN   = "H"
+
HUMANWINS   = 1
COMPUTER = "C"
+
COMPUTERWINS = 2
TIE     = "T"
+
TIE         = 3
  
 
# playRound: asks the user for her play, and compares it
 
# playRound: asks the user for her play, and compares it
Line 244: Line 256:
 
     human    = input( "\nYour play (R, P, or S)? " ).upper()
 
     human    = input( "\nYour play (R, P, or S)? " ).upper()
 
     computer = "R"
 
     computer = "R"
     return COMPUTER
+
     return COMPUTERWINS
  
  
Line 256: Line 268:
  
 
         # see if human wins
 
         # see if human wins
         if winner == HUMAN:
+
         if winner == HUMANWINS:
 
             print( "You win!" )
 
             print( "You win!" )
  
 
         # or if the computer wins
 
         # or if the computer wins
         elif winner == COMPUTER:
+
         elif winner == COMPUTERWINS:
 
             print( "I win!" )
 
             print( "I win!" )
 
              
 
              
Line 281: Line 293:
 
|-
 
|-
 
|
 
|
==Challenge #1: Keeping track of the winners==
+
==Challenge #1: Keeping track of the wins==
 
|}
 
|}
 
[[Image:QuestionMark5.jpg|right|120px]]
 
[[Image:QuestionMark5.jpg|right|120px]]
Line 304: Line 316:
 
I win!
 
I win!
 
Human: 0
 
Human: 0
Computer: 2
+
Computer: 3
  
 
</source>
 
</source>
 
<br />
 
<br />
* Modify the program so that the function '''playRound()''' will return HUMAN instead of COMPUTER.  Verify that your other counter works.
+
* Modify the program so that the function '''playRound()''' returns HUMAN instead of COMPUTER.  Verify that your other counter works.
* Same exercise, make ''' '''playRound()''' return TIE, and verify that the two counters do not change.
+
* Same exercise, make '''playRound()''' return TIE, and verify that the two counters do not change.
 
<br />
 
<br />
 
<br />
 
<br />
Line 316: Line 328:
 
|
 
|
  
==Challenge #2: Computer Picks Random Shape==
+
==Challenge #2: Figuring out who wins==
 
|}
 
|}
 
[[Image:QuestionMark6.jpg|right|120px]]
 
[[Image:QuestionMark6.jpg|right|120px]]
 +
<br />
 +
* This is probably the most challenging part of this program.
 +
* Given the user's play ('R', 'S', or 'P') and the computer's play (one of the same 3 letters), you need to make the program decide who wins or if there's a tie.
 +
* Because your program currently picks a play that is fixed, it will be time-consuming to test your code with all possible combinations of user and computer plays, and verify that it works in all cases.
 +
* <font color="magenta">A much better alternative</font> is to create another program, very short, that can run through all possible cases for you, and allow you to verify whether you have the right logic for deciding the winner.
 +
* Create a new program, called '''testRPSAlgorithm.py''' with the code below:
 +
<br />
 +
::<source lang="python">
 +
# testRPSWinner.py
 +
# D. Thiebaut
 +
# This program tests all the possible combinations
 +
# of user and computer plays in the game of rock
 +
# paper, scissors.
 +
# Rules:
 +
# user  computer winner
 +
#  R      R      Tie
 +
#  R      P      C
 +
#  R      S      H
 +
#  P      R      H
 +
#  P      P      Tie
 +
#  P      S      C
 +
#  S      R      C
 +
#  S      P      H
 +
#  S      S      Tie
 +
 +
HUMANWINS    = 1
 +
COMPUTERWINS = 2
 +
TIE          = 3
 +
 +
def winner( user, computer ):
 +
    if user=='R' and computer=='R':
 +
        return HUMANWINS
 +
    else:
 +
        return COMPUTERWINS
 +
   
 +
 +
print( "user computer winner" )
 +
for user in [ 'R', 'P', 'S' ]:
 +
    for computer in [ 'R', 'P', 'S' ]:
 +
        win = winner( user, computer )
 +
        if win == HUMANWINS:
 +
            win = "human"
 +
        elif win == COMPUTERWINS:
 +
            win = "computer"
 +
        else:
 +
            win = "tie"
 +
        print( "#  ", user, "    ", computer, "    ", winner( user, computer ) )
 +
 +
 +
</source>
 +
<br />
 +
* Run the program.  Notice that it lists all the possible combinations for a play by the user and by the computer.  The outcome, though, is not correct.
 +
* Modify the code in the '''winner()''' function so that it returns the correct output in all cases.
 +
* There are many different ways to solve this...  Don't worry about efficiency too much.  Concentrate on having something that works correctly.  <font color="magenta"> Note that there are 3 cases when the user wins, 3 cases for which the computer wins, and 3 cases when we have a tie.  </font>
 +
* Once you have the correct behavior for your '''winner() ''' function, copy/paste it into your  ''' Lab8RPS.py''' program.  Make '''playRound()''' use this function to figure out what to return to the main program.
 +
 +
 +
<br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
 +
==Challenge #3: Computer Picks Random Character==
 +
|}
 +
[[Image:QuestionMark9.jpg|right|120px]]
 
<br />
 
<br />
 
* Try this code section in the Python Console.   
 
* Try this code section in the Python Console.   
Line 332: Line 409:
 
<br />
 
<br />
 
* We have seen the '''choice()''' function of the '''random''' library before.  Once you have remembered how it works, add some code to '''playRound()''' so that the computer picks randomly between ''Rock'', ''Paper'', and ''Scissors''.
 
* We have seen the '''choice()''' function of the '''random''' library before.  Once you have remembered how it works, add some code to '''playRound()''' so that the computer picks randomly between ''Rock'', ''Paper'', and ''Scissors''.
 +
* Run your program, and verify that it shows what the computer picks, and who wins the round.
 
<br />
 
<br />
 
<br /><br />
 
<br /><br />
Line 338: Line 416:
 
|
 
|
  
==Challenge #3: Adding some Robustness==
+
==Challenge #4: Adding some Robustness==
 
|}
 
|}
 
[[Image:QuestionMark7.jpg|right|120px]]
 
[[Image:QuestionMark7.jpg|right|120px]]
 
<br />
 
<br />
Try running your program and entering characters that are not 'R', 'P', or 'S'.  The program gets confused.
+
* Try running your program and entering characters that are not 'R', 'P', or 'S'.  The program gets confused.
 +
<br />
 +
* Adapt one of your solution functions of Part 1 and add a new function to your program called '''getUserInput()''', that will prompt the user for a letter, and will keep prompting her until the letter entered is either 'R', 'P', or 'S'.  Make '''playRound()''' use this function to get the user's play.
 +
* Test your program well.  Enter letters that are not valid and verify that your program keeps prompting for a new input every time.
 +
<br />
 
<br />
 
<br />
Adapt one of your solution functions of Part 1 to force your program to keep asking the user for a letter until it is valid, i.e. 'R', 'P', or 'S'.
 
 
 
  
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
==Challenge #5: Keeping scores ==
 +
|}
 +
[[Image:QuestionMark5.jpg|right|120px]]
 +
<br />
 +
Modify your program so that it will allow the user to play only 3 rounds against the computer, and then stop, announcing who the winner is.
  
 
<br />
 
<br />
Line 355: Line 442:
 
|-
 
|-
 
|
 
|
 +
==Challenge #6: Keeping Playing until Difference between Scores is 3==
 +
|}
 +
[[Image:QuestionMark8.jpg|right|120px]]
 +
<br />
 +
* This is a bit trickier.  Modify your program so that it will let the user play against the computer as long as the difference between the two scores is less than 3.  When the difference is equal to 3, then the program stops and displays the winner.
 +
 +
</showafterdate>
 +
<br />
 +
<!-- ============================================================== -->
 +
<!-- ============================================================== -->
 +
<!-- ============================================================== -->
 +
 +
<showafterdate after="20150327 11:00" before="20150601 00:00">
 +
=Solution Programs=
 +
<br />
 +
==Part 1==
 +
<br />
 +
<source lang="python">
 +
# Lab8sol.py
 +
# D. Thiebaut
 +
 +
 +
def getPositiveNumber():
 +
    while True:
 +
        x = int( input( "Please enter a number greater than 0: " ) )
 +
        if x > 0:
 +
            return x
 +
        print( x, "is invalid." )
 +
 +
 +
def likesChoco():
 +
    # list all allowed valid answers
 +
    validAns = ['y','yes','n','no']
 +
 +
    # seed the loop
 +
    x = ""
 +
    while x in validAns == False:
 +
        x = input("Do you like chocolate (y/n)? ")
 +
        x = x.lower()
 +
 +
    if x in ['y', 'yes']:
 +
        return True
 +
    else:
 +
        return False
 +
 +
def createFile( fileName ):
 +
    file = open( fileName, "w" )
 +
    file.write("""
 +
    Haikus from http://www.toyomasu.com/haiku/
 +
    An old pond!
 +
    A frog jumps in-
 +
    The sound of water.
 +
    <<<END>>>
 +
    Feel free to use anything from this page as
 +
    long as you make references and links to HAIKU
 +
    for PEOPLE. Last updated: Jan 10th. 2001.
 +
    Edited by Kei Grieg Toyomasu,
 +
    kei at toyomasu dot com""" )
 +
    file.close()
 +
 +
def readFileTillMarker( fileName ):
 +
    file = open( fileName, "r" )
 +
    lines = []
 +
    for line in file:
 +
        if line.find( "<<<END>>>" ) != -1:
 +
            return lines
 +
        else:
 +
            lines.append( line )
 +
    return lines
  
==Challenge #5: Keeping scores (Optional)==
+
def computePi():
|}
+
    sum = 0
[[Image:QuestionMark5.jpg|right|120px]]
+
    multiplier = 1
 +
   
 +
    for i in range( 1, 20, 2 ):
 +
        sum = sum + multiplier * 4.0 / i
 +
        multiplier = -multiplier
 +
        print( "Pi = ", sum )
 +
 
 +
def computePi2():
 +
    sum = 0
 +
    multiplier = 1
 +
 
 +
    i = 1
 +
    while ( not ( 3.14 <= sum < 3.15 ) ):
 +
        sum = sum + multiplier * 4.0 / i
 +
        i = i+2
 +
        multiplier = -multiplier
 +
        print( "Pi = ", sum )
 +
    print( "Final version of Pi = ", sum )
 +
       
 +
def main():
 +
 
 +
    # Part 1, Exercise 1
 +
    x = getPositiveNumber()
 +
    print( "getPositiveNumber() returned", x )
 +
 
 +
    # Part 1, Exercise 2
 +
    if likesChoco() == True:
 +
        print( "Me too!" )
 +
    else:
 +
        print( "Sorry to hear that!" )
 +
 
 +
    # Part 1, Exercise 3
 +
    createFile( "lab8Demo.txt" )
 +
    lines = readFileTillMarker( "lab8Demo.txt" )
 +
    print( "Lines found by readFileTillMarker(): " )
 +
    for line in lines:
 +
        print( line.strip() )
 +
 
 +
    # Part 1, Exercise 4
 +
    computePi2()
 +
   
 +
if __name__=="__main__":
 +
    main()
 +
 
 +
</source>
 +
<br />
 +
==Part 2==
 
<br />
 
<br />
Modify your program from Challenge 3 and make it keep tack of the score. At the end of the 3 rounds the program will announce who won the 3 rounds.
+
<source lang="python">
 +
# lab8RPS_solution.py
 +
# D. Thiebaut
  
This is tricky.  Try to figure it out on your own and don't give up for 5 minutes.  Try hard.  If after that long you still can't figure it out, ask the TAs or your instructor for hints...
+
from random import choice
  
 +
# define constants for indicating the winner of a round
 +
HUMANWINS    = 1
 +
COMPUTERWINS = 2
 +
TIE          = 3
 +
 +
 +
# getUserInput(): prompts the user for a letter that is
 +
# either 'R', 'S' or 'P'.  Keeps prompting until input is
 +
# correct.
 +
def getUserInput():
 +
    while True:
 +
        ans = input( "\n\nYour play (R, S, P)? " ).upper()
 +
        if ans in ['R', 'S', 'P']:
 +
            return ans
 +
        print( "invalid input.\n" )
 +
       
 +
# winner(): decides who the winner is from the two characters
 +
# passed, representing the user's and the computer's play.
 +
def winner( user, computer ):
 +
    # create a string with the 2 letters
 +
    userComputer = user + computer
 +
 +
    # test two-letters and combinations of user winning
 +
    if userComputer in [ "RS", "PR", "SP" ]:
 +
        return HUMANWINS
 +
 +
    # test two-letters and combinations of ties
 +
    if userComputer in [ "RR", "PP", "SS" ]:
 +
        return TIE
 +
 +
    # if we haven't returned yet, then the computer wins
 +
    return COMPUTERWINS
 +
 +
 +
 +
# playRound: asks the user for her play, and compares it
 +
# to the play picked by the computer.  Returns HUMAN if
 +
# the user wins, COMPUTER if the user loses, or TIE if
 +
# it's a tie.
 +
def playRound():
 +
    human    = getUserInput()
 +
    computer = choice( ['R', 'P', 'S'] )
 +
    win = winner( human, computer )
 +
    print( "human:", human, "  computer:", computer )
 +
    return win
 +
 +
 +
# main program.  Allows the user to play against the computer,
 +
# and reports on the winner of each rounds.
 +
def main():
 +
    hCount = 0    # human win-counter
 +
    cCount = 0    # computer win-counter
 +
   
 +
    # play rounds
 +
    while True:
 +
        # play one round between computer and human
 +
        winner = playRound()
 +
 +
        # see if human wins
 +
        if winner == HUMANWINS:
 +
            hCount += 1
 +
            print( "You win!  Scores: computer:", cCount, " you:", hCount )
 +
 +
        # or if the computer wins
 +
        elif winner == COMPUTERWINS:
 +
            cCount += 1
 +
            print( "I win!  Scores: computer:", cCount, " you:", hCount )
 +
           
 +
        # otherwise it's a tie
 +
        else:
 +
            print( "It's a tie!  Scores: computer:", cCount, " you:", hCount )
 +
 +
        if abs( cCount - hCount ) >= 3:
 +
            break
 +
 +
    # announce the winner of the game
 +
    if cCount > hCount:
 +
        print( "\nYou lost the game!" )
 +
    else:
 +
        print( "\nCongrats, you won this, fair and square!" )
 +
 +
 +
if __name__=="__main__":
 +
    main()
 +
 +
</source>
 +
<br />
 
</showafterdate>
 
</showafterdate>
 
<br />
 
<br />
 +
----
 +
<onlydft>
 +
=VPL Module: Part 1=
 +
 +
==vpl_run.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 evaluateRun.py
 +
 +
EOF
 +
 +
chmod +x vpl_execution
 +
 +
 +
</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>
 +
<br />
 +
==vpl_evaluate.cases==
 +
<br />
 +
<source lang="text">
 +
</source>
 +
<br />
 +
==evaluate.py==
 +
<br />
 +
<source lang="python">
 +
# evaluateFunction.py
 +
# D. Thiebaut
 +
import random
 +
 +
def comment(s):
 +
    '''formats strings to create VPL comments'''
 +
    print('Comment :=>> ' + s)
 +
 +
def grade(num):
 +
    '''formats a number to create a VPL grade'''
 +
    print('Grade :=>> ' + str(num))
 +
 +
# 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 generateInputFileWithRandomInputs( inputFileName ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    nums=["zero", "one", "two", "three", "four", "five", "six", "seven",
 +
          "eight", "nine" ]
 +
    expectedResult = []
 +
    file = open( inputFileName, "w" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
        expectedResult.append( nums[i] )
 +
 +
    file.write( "<<<END>>>\n" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
 +
    file.close()
 +
 +
    #--- return text saved to file by reading it back ---
 +
    return expectedResult
 +
 +
 +
expectedResult = generateInputFileWithRandomInputs( "input.txt" )
 +
 +
# does the file exist?
 +
try:
 +
    import lab8
 +
except:
 +
    comment("unable to import your program lab8")
 +
    grade(10)
 +
    exit()
 +
 +
# does the function exist?
 +
try:
 +
    lab8.readFileTillMarker
 +
except:
 +
    comment("Your lab8.py program does not contain a file called readFileTillMarker()" )
 +
    grade(25)
 +
    exit()
 +
 +
# does the function return a list of strings?
 +
try:
 +
    retVal = lab8.readFileTillMarker( "input.txt" )
 +
except:
 +
    comment("Your function readFileTillMarker() crashed")
 +
    grade(40)
 +
    exit()
 +
 +
if type( retVal ) != type( [ "a", "b" ] ):
 +
    comment("Your function does not return a list.")
 +
    grade(45)
 +
    exit()
 +
 +
if type( retVal[0] ) != type( "string" ):
 +
    comment("Your function does not return a list of string.")
 +
    grade(50)
 +
    exit()
 +
 +
# compare the list returned by the function to the expected list
 +
list = lab8.readFileTillMarker( "input.txt" )
 +
try:
 +
    list = [ st.strip() for st in list if len( st.strip() )!= 0 ]
 +
except:
 +
    comment("Your function returns a list that contains non-string items" )
 +
    grade(60)
 +
    exit()
 +
 +
expectedResult = [ st.strip() for st in expectedResult if len( st.strip() )!= 0 ]
 +
 +
if list != expectedResult:
 +
    comment( "Your function does not return the expected list" )
 +
    comment( "expected: " + str( expectedResult ) )
 +
    comment( "your output: " + str( list ) )
 +
    grade( 70 )
 +
    exit()
 +
else:
 +
    comment( "Congrats, your function runs well!" )
 +
    grade( 100 )
 +
    exit()
 +
 +
</source>
 +
<br />
 +
==evaluateRun.py==
 +
<br />
 +
<source lang="python">
 +
# evaluateRun.py
 +
# D. Thiebaut
 +
#
 +
import random
 +
 +
def comment(s):
 +
    '''formats strings to create VPL comments'''
 +
    #print('Comment :=>> ' + s)
 +
    print( s )
 +
 +
def commentLong( line ):
 +
    #print( "<|--\n" + line  + "\n --|>" )
 +
    print( line )
 +
 +
 +
def grade(num):
 +
    '''formats a number to create a VPL grade'''
 +
    #print('Grade :=>> ' + str(num))
 +
    print( "Your grade:", num )
 +
 +
# 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 generateInputFileWithRandomInputs( inputFileName ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    nums=["zero", "one", "two", "three", "four", "five", "six", "seven",
 +
          "eight", "nine" ]
 +
    expectedResult = []
 +
    file = open( inputFileName, "w" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        line =  nums[random.randrange( len(nums) )]
 +
        file.write( line  + "\n" )
 +
        expectedResult.append( line )
 +
 +
    file.write( "<<<END>>>\n" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        line =  nums[random.randrange( len(nums) )]
 +
        file.write( line + "\n" )
 +
 +
    file.close()
 +
 +
    #--- return text saved to file by reading it back ---
 +
    return expectedResult
 +
 +
 +
expectedResult = generateInputFileWithRandomInputs( "input.txt" )
 +
 +
# does the file exist?
 +
try:
 +
    import lab8
 +
except:
 +
    comment("unable to import your program lab8.py")
 +
    #grade(10)
 +
    exit()
 +
 +
# does the function exist?
 +
try:
 +
    lab8.readFileTillMarker
 +
except:
 +
    comment("Your lab8.py program does not contain a file called readFileTillMarker()" )
 +
    #grade(25)
 +
    exit()
 +
 +
# does the function return a list of strings?
 +
try:
 +
    retVal = lab8.readFileTillMarker( "input.txt" )
 +
except:
 +
    comment( "Your function readFileTillMarker() crashed")
 +
    comment( "when the file 'input.txt' was passed to it")
 +
    comment( "input.txt contained: " )
 +
    commentLong( open( "input.txt", "r" ).read() )
 +
    #grade(40)
 +
    exit()
 +
 +
if type( retVal ) != type( [ "a", "b" ] ):
 +
    comment("Your function does not return a list.")
 +
    #grade(45)
 +
    exit()
 +
 +
if type( retVal[0] ) != type( "string" ):
 +
    comment("Your function does not return a list of string.")
 +
    #grade(50)
 +
    exit()
 +
 +
# compare the list returned by the function to the expected list
 +
list = lab8.readFileTillMarker( "input.txt" )
 +
try:
 +
    list = [ st.strip() for st in list if len( st.strip() )!= 0 ]
 +
except:
 +
    comment("Your function returns a list that contains non-string items" )
 +
    #grade(60)
 +
    exit()
 +
 +
comment( "Your function was given a file containing:" )
 +
commentLong( open( "input.txt", "r" ).read() )
 +
comment( "and returned:" )
 +
commentLong( str( list ) )
 +
exit()
 +
 +
expectedResult = [ st.strip() for st in expectedResult if len( st.strip() )!= 0 ]
 +
 +
if list != expectedResult:
 +
    comment( "Your function does not return the expected list" )
 +
    comment( "expected: " + str( expectedResult ) )
 +
    comment( "your output: " + str( list ) )
 +
    #grade( 70 )
 +
    exit()
 +
else:
 +
    comment( "Congrats, your function runs well!" )
 +
    #grade( 100 )
 +
    exit()
 +
 +
 +
</source>
 +
<br />
 +
=VPL Module: Part 2=
 +
 +
==vpl_run.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
 +
 +
prog=evaluateRun.py
 +
\$python \$prog
 +
 +
EOF
 +
 +
chmod +x vpl_execution
 +
</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>
 +
<br />
 +
==vpl_evaluate.cases==
 +
<br />
 +
<source lang="text">
 +
</source>
 +
<br />
 +
==evaluate.py==
 +
<br />
 +
<source lang="python">
 +
# evaluate.py
 +
# D. Thiebaut
 +
import random
 +
 +
def comment(s):
 +
    '''formats strings to create VPL comments'''
 +
    print('Comment :=>> ' + s)
 +
 +
def grade(num):
 +
    '''formats a number to create a VPL grade'''
 +
    print('Grade :=>> ' + str(num))
 +
    return
 +
 +
# 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 generateInputFileWithRandomInputs( inputFileName ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    nums=["zero", "one", "two", "three", "four", "five", "six", "seven",
 +
          "eight", "nine" ]
 +
    expectedResult = []
 +
    file = open( inputFileName, "w" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
        expectedResult.append( nums[i] )
 +
 +
    file.write( "<<<END>>>\n" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
 +
    file.close()
 +
 +
    #--- return text saved to file by reading it back ---
 +
    return expectedResult
 +
 +
 +
expectedResult = generateInputFileWithRandomInputs( "input.txt" )
 +
 +
# does the file exist?
 +
try:
 +
    import lab8RPS
 +
except:
 +
    comment("unable to import your program lab8RPS")
 +
    grade(10)
 +
    exit()
 +
 +
# does the function exist?
 +
try:
 +
    lab8RPS.winner
 +
except:
 +
    comment("Your lab8RPS.py program does not contain a function called winner()" )
 +
    grade(25)
 +
    exit()
 +
 +
# does the function return a list of strings?
 +
try:
 +
    retVal = lab8RPS.winner( "R", "R" )
 +
except:
 +
    comment( "Your function winner() crashed.")
 +
    comment( "Did you write it so that it receives two parameters?" )
 +
    comment( "Are the parameters strings?" )
 +
    grade(40)
 +
    exit()
 +
 +
if type( retVal ) != type( 3 ):
 +
    comment("Your function does not return an int.")
 +
    grade(45)
 +
    exit()
 +
 +
#if type( retVal[0] ) != type( "string" ):
 +
#    comment("Your function does not return a list of string.")
 +
#    grade(50)
 +
#    exit()
 +
 +
# compare the list returned by the function to the expected list
 +
#list = lab8RPS.winner(  )
 +
#try:
 +
#    list = [ st.strip() for st in list if len( st.strip() )!= 0 ]
 +
#except:
 +
#    comment("Your function returns a list that contains non-string items" )
 +
#    grade(60)
 +
#    exit()
 +
res = 0
 +
resList = []
 +
for first in "RPS":
 +
  for second in "RPS":
 +
      try:
 +
        res = lab8RPS.winner( first, second )
 +
      except:
 +
        comment( "your function crashed when it was called" )
 +
        comment( "as follows: winner( %s, %s )" % ( first, second ) )
 +
        grade( 50 )
 +
        exit()
 +
      resList.append( res )
 +
 +
wins = [ (resList.count( 1 ),1),
 +
        (resList.count( 2 ),2),
 +
        (resList.count( 3 ),3) ]
 +
if resList.count( 1 ) != 3 or resList.count( 2 ) != 3 or resList.count( 3 ) != 3:
 +
    comment( "Your function winner() is not fair" )
 +
    wins.sort()
 +
    for count, play in wins:
 +
        comment( "It outputs %d %d times" %(  play , count ) )
 +
    grade( 75 )
 +
else:
 +
    comment( "Congrats, your function works well!" )
 +
    grade( 100 )
 +
</source>
 +
<br />
 +
==evaluateRun.py==
 +
<br />
 +
<source lang="python">
 +
# evaluateFunction.py
 +
# D. Thiebaut
 +
import random
 +
 +
def comment(s):
 +
    '''formats strings to create VPL comments'''
 +
    #print('Comment :=>> ' + s)
 +
    print( s )
 +
 +
def grade(num):
 +
    '''formats a number to create a VPL grade'''
 +
    #print('Grade :=>> ' + str(num))
 +
    return
 +
 +
# 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 generateInputFileWithRandomInputs( inputFileName ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    nums=["zero", "one", "two", "three", "four", "five", "six", "seven",
 +
          "eight", "nine" ]
 +
    expectedResult = []
 +
    file = open( inputFileName, "w" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
        expectedResult.append( nums[i] )
 +
 +
    file.write( "<<<END>>>\n" )
 +
 +
    for i in range( random.randrange( 10 ) ):
 +
        file.write( nums[i] + "\n" )
 +
 +
    file.close()
 +
 +
    #--- return text saved to file by reading it back ---
 +
    return expectedResult
 +
 +
 +
expectedResult = generateInputFileWithRandomInputs( "input.txt" )
 +
 +
# does the file exist?
 +
try:
 +
    import lab8RPS
 +
except:
 +
    comment("unable to import your program lab8RPS")
 +
    grade(10)
 +
    exit()
 +
 +
# does the function exist?
 +
try:
 +
    lab8RPS.winner
 +
except:
 +
    comment("Your lab8RPS.py program does not contain a function called winner()" )
 +
    grade(25)
 +
    exit()
 +
 +
# does the function return a list of strings?
 +
try:
 +
    retVal = lab8RPS.winner( "R", "R" )
 +
except:
 +
    comment( "Your function winner() crashed.")
 +
    comment( "Did you write it so that it receives two parameters?" )
 +
    comment( "Are the parameters strings?" )
 +
    grade(40)
 +
    exit()
 +
 +
if type( retVal ) != type( 3 ):
 +
    comment("Your function does not return an int.")
 +
    grade(45)
 +
    exit()
 +
 +
 +
res = 0
 +
resList = []
 +
for first in "RPS":
 +
  for second in "RPS":
 +
      try:
 +
        res = lab8RPS.winner( first, second )
 +
      except:
 +
        comment( "your function crashed when it was called" )
 +
        comment( "as follows: winner( %s, %s )" % ( first, second ) )
 +
        grade( 50 )
 +
        exit()
 +
      resList.append( res )
 +
 +
comment( "Ok, your function seems to be working fine." )
 +
comment( "It will be tested and evaluated after the deadline." )
 +
comment( "The test will subject it to all possible plays of" )
 +
comment( "R, P, and S by the humand and by the computer, and" )
 +
comment( "will verify that it returns the righ number" )
 +
comment( "in all cases." )
 +
exit( )
 +
 +
wins = [ (resList.count( 1 ),1),
 +
        (resList.count( 2 ),2),
 +
        (resList.count( 3 ),3) ]
 +
if resList.count( 1 ) != 3 or resList.count( 2 ) != 3 or resList.count( 3 ) != 3:
 +
    comment( "Your function winner() is not fair" )
 +
    wins.sort()
 +
    for count, play in wins:
 +
        comment( "It outputs %d %d times" %(  play , count ) )
 +
    grade( 75 )
 +
else:
 +
    comment( "Congrats, your function works well!" )
 +
    grade( 100 )
 +
 +
</source>
 +
<br />
 +
</onlydft>
 
<br />
 
<br />
 
<br />
 
<br />

Latest revision as of 05:52, 27 March 2015

--D. Thiebaut (talk) 14:10, 22 March 2015 (EDT)



The submission page for this lab is here: http://tinyurl.com/CSC111Lab8Submit
The long URL is http://cs.smith.edu/dftwiki/index.php?title=CSC111_Lab_8_Submission_2015.


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

Work out all the problems of this lab, and when you are done demonstrate your working program to the lab instructor or a TA. Upon verification that your programs work well, you will be given a URL explaining what your have to submit on Moodle for this lab. The deadline for submitting on Moodle is Friday 11:00 a.m., just before class.



Preamble


For this lab you will write a long program called lab8.py that will

  1. include all the functions that are the solutions to the various exercises.
  2. contain one main() function that will call and test all your functions.
  3. have the following code at the end where you will call main():


if __name__=="__main__":
    main()


Part 1: While Loops


Exercise 1: Robust Input with While Loops

QuestionMark1.jpg


def getPositiveNumber():
    #
    # put your code here
    #
    return 10   # just to make sure the code is accepted by Idle


def main():

    # Part 1, Exercise 1
    x = getPositiveNumber()
    print( "getPositiveNumber() returned", x )

if __name__=="__main__":
    main()


Remove the return 10 statement in getPositiveNumber(), and complete the function so that it asks the user for a number larger than 0, and keeps on prompting the user as long as she doesn't enter a valid number.

Below is an example of the interaction between computer and user.

Please enter a number greater than 0: -1
-1 is invalid.
Please enter a number greater than 0: -3
-3 is invalid.
Please enter a number greater than 0: 0
0 is invalid.
Please enter a number greater than 0: 20
getPositiveNumber() returned 20
>>>



Exercise 2: Ask for Yes/No answer

QuestionMark2.jpg



Same idea as in Exercise 1, but this time the new function, called likesChoco() will keep on asking a question until the user's input is "YES", "yes", "y", "NO", "no", or "n". Any combination of lower/upper case in the spelling is accepted ("yES" is valid). The function will return True if the user answers yes, and False otherwise.

Source


def likesChoco():
    #
    # put your code here
    #
    return True    # just to make sure the code works as is.
            
def main():
    # Part1, Exercise 2
    if likesChoco() == True:
        print( "Me too!" )
    else:
        print( "Sorry to hear that!" )
        
if __name__=="__main__":
    main()


Example output


Do you like chocolate (Y/N)? possibly
please enter by 'Yes' or 'No'

Do you like chocolate (Y/N)? I don't know
please enter by 'Yes' or 'No'

Do you like chocolate (Y/N)? Oui
please enter by 'Yes' or 'No'

Do you like chocolate (Y/N)? y
Me too!



Exercise 3: While Loop and Reading File

QuestionMark3.jpg


# createFile: creates a text file containing a haiku followed by the line <<<END>>>
# followed by some text about the source of the haiku and the rights of use.
def createFile( fileName ):

    # open the file
    file = open( fileName, "w" )

    # write some text
    file.write("""
    An old pond!
    A frog jumps in-
    The sound of water.
    <<<END>>>
    Haikus from http://www.toyomasu.com/haiku/
    Feel free to use anything from this page as
    long as you make references and links to HAIKU
    for PEOPLE. Last updated: Jan 10th. 2001.
    Edited by Kei Grieg Toyomasu,
    kei at toyomasu dot com""" )

    # close the file
    file.close()

def readFileTillMarker( fileName ):
    #
    # add your code here
    #
    return []   # just to make sure the code compiles. 

def main():
    # Part 1, Exercise 3
    # create a sample text file for testing.  The file will contain the string <<<END>>>
    # in it.
    createFile( "lab8Demo.txt" )

    # get all the lines before but not including <<<END>>>
    lines = readFileTillMarker( "lab8Demo.txt" )

    # display the lines returned.  We strip them to remove the extra \n at the end and
    # the extra spaces at the front of each line.
    print( "Lines found by readFileTillMarker(): " )
    for line in lines:
        print( line.strip() )
        
if __name__=="__main__":
    main()


Same idea as the previous 2 exercises. This time you need to add code to the function readFileTillMarker() so that it will read all the lines contained in the file whose name is passed as a parameter, and that appear before the marker string <<<END>>>. In other words, the function reads the lines, adds them to a list of lines, until it finds a line containing the string <<<END>>>. It returns a list of all the lines read.

The function createFile() creates a simple file you can use for testing. Take a look at it to make sure you understand the format of the data.

Here's an example of how your program should work.


Lines found by readFileTillMarker(): 

An old pond!
A frog jumps in-
The sound of water.



Exercise 4: A bit of mathematics

QuestionMark4.jpg


Pi can be computed by adding the following terms (http://en.wikipedia.org/wiki/Pi):

Pi expansion.png


Below is a program that loops 10 times and add up the terms of the series. The program shows how the variable sum, where we accumulate the terms, gets closer and closer to PI as the loop progresses.

def computePi():
    sum = 0
    multiplier = 1
    
    for i in range( 1, 20, 2 ):
        sum = sum + multiplier * 4.0 / i
        multiplier = -multiplier
        print( "Pi = ", sum )

Modify this program so that it stops when the first 3 digits of sum are equal to 3.14. It is not acceptable to run a large number of iterations to figure out how many are necessary and change the limit of the for-loop to make it stop at the right place. Instead, your solution should use a while loop, which will stop when the sum is a number of the form 3.14xxxxxxx. Make your modified function print only the last value of sum, not all the different values it takes.




Part 2: Playing Rock-Paper-Scissors


Playing Rock, Paper, Scissors With the Computer


RockPaperScissors.jpg

Create a program called Lab8RPS.py, and start with the code shown below. Run it to see how it operates.


# lab8RPS.py
# D. Thiebaut

# define constants for indicating the winner of a round
HUMANWINS    = 1
COMPUTERWINS = 2
TIE          = 3

# playRound: asks the user for her play, and compares it
# to the play picked by the computer.  Returns HUMAN if
# the user wins, COMPUTER if the user loses, or TIE if
# it's a tie.
def playRound():
    human    = input( "\nYour play (R, P, or S)? " ).upper()
    computer = "R"
    return COMPUTERWINS


# main program.  Allows the user to play against the computer,
# and reports on the winner of each rounds.
def main():
    # play rounds
    while True:
        # play one round between computer and human
        winner = playRound()

        # see if human wins
        if winner == HUMANWINS:
            print( "You win!" )

        # or if the computer wins
        elif winner == COMPUTERWINS:
            print( "I win!" )
            
        # otherwise it's a tie
        else:
            print( "It's a tie!" )

if __name__=="__main__":
    main()


You will notice that this program is not fair at all. That's ok for right now. If you need the rules for this game, check this URL: http://en.wikipedia.org/wiki/Rock-paper-scissors.





Challenge #1: Keeping track of the wins

QuestionMark5.jpg


  • Modify your program and add two counters that will keep track of how many times the user or the computer win.
  • Make your program output these two counters after every round.
  • Example:


Your play (R, P, or S)? R
I win!
Human: 0
Computer: 1

Your play (R, P, or S)? S
I win!
Human: 0
Computer: 2

Your play (R, P, or S)? P
I win!
Human: 0
Computer: 3


  • Modify the program so that the function playRound() returns HUMAN instead of COMPUTER. Verify that your other counter works.
  • Same exercise, make playRound() return TIE, and verify that the two counters do not change.



Challenge #2: Figuring out who wins

QuestionMark6.jpg


  • This is probably the most challenging part of this program.
  • Given the user's play ('R', 'S', or 'P') and the computer's play (one of the same 3 letters), you need to make the program decide who wins or if there's a tie.
  • Because your program currently picks a play that is fixed, it will be time-consuming to test your code with all possible combinations of user and computer plays, and verify that it works in all cases.
  • A much better alternative is to create another program, very short, that can run through all possible cases for you, and allow you to verify whether you have the right logic for deciding the winner.
  • Create a new program, called testRPSAlgorithm.py with the code below:


# testRPSWinner.py
# D. Thiebaut
# This program tests all the possible combinations
# of user and computer plays in the game of rock
# paper, scissors.
# Rules:
# user  computer winner
#   R      R       Tie
#   R      P       C
#   R      S       H
#   P      R       H
#   P      P       Tie
#   P      S       C
#   S      R       C
#   S      P       H
#   S      S       Tie

HUMANWINS    = 1
COMPUTERWINS = 2
TIE          = 3

def winner( user, computer ):
    if user=='R' and computer=='R':
        return HUMANWINS
    else:
        return COMPUTERWINS
    

print( "user computer winner" )
for user in [ 'R', 'P', 'S' ]:
    for computer in [ 'R', 'P', 'S' ]:
        win = winner( user, computer )
        if win == HUMANWINS:
            win = "human"
        elif win == COMPUTERWINS:
            win = "computer"
        else:
            win = "tie"
        print( "#  ", user, "    ", computer, "     ", winner( user, computer ) )


  • Run the program. Notice that it lists all the possible combinations for a play by the user and by the computer. The outcome, though, is not correct.
  • Modify the code in the winner() function so that it returns the correct output in all cases.
  • There are many different ways to solve this... Don't worry about efficiency too much. Concentrate on having something that works correctly. Note that there are 3 cases when the user wins, 3 cases for which the computer wins, and 3 cases when we have a tie.
  • Once you have the correct behavior for your winner() function, copy/paste it into your Lab8RPS.py program. Make playRound() use this function to figure out what to return to the main program.



Challenge #3: Computer Picks Random Character

QuestionMark9.jpg


  • Try this code section in the Python Console.


>>> from random import choice
>>> options = [ "fruit", "dog", "farm", 3.14159, "blue" ]
>>> choice( options )
>>> choice( options )
>>> choice( options )
>>> choice( options )


  • We have seen the choice() function of the random library before. Once you have remembered how it works, add some code to playRound() so that the computer picks randomly between Rock, Paper, and Scissors.
  • Run your program, and verify that it shows what the computer picks, and who wins the round.




Challenge #4: Adding some Robustness

QuestionMark7.jpg


  • Try running your program and entering characters that are not 'R', 'P', or 'S'. The program gets confused.


  • Adapt one of your solution functions of Part 1 and add a new function to your program called getUserInput(), that will prompt the user for a letter, and will keep prompting her until the letter entered is either 'R', 'P', or 'S'. Make playRound() use this function to get the user's play.
  • Test your program well. Enter letters that are not valid and verify that your program keeps prompting for a new input every time.



Challenge #5: Keeping scores

QuestionMark5.jpg


Modify your program so that it will allow the user to play only 3 rounds against the computer, and then stop, announcing who the winner is.



Challenge #6: Keeping Playing until Difference between Scores is 3

QuestionMark8.jpg


  • This is a bit trickier. Modify your program so that it will let the user play against the computer as long as the difference between the two scores is less than 3. When the difference is equal to 3, then the program stops and displays the winner.

</showafterdate>

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

Solution Programs


Part 1


# Lab8sol.py
# D. Thiebaut


def getPositiveNumber():
    while True:
        x = int( input( "Please enter a number greater than 0: " ) )
        if x > 0:
            return x
        print( x, "is invalid." )


def likesChoco():
    # list all allowed valid answers
    validAns = ['y','yes','n','no']

    # seed the loop
    x = ""
    while x in validAns == False:
        x = input("Do you like chocolate (y/n)? ")
        x = x.lower()

    if x in ['y', 'yes']:
        return True
    else:
        return False

def createFile( fileName ):
    file = open( fileName, "w" )
    file.write("""
    Haikus from http://www.toyomasu.com/haiku/
    An old pond!
    A frog jumps in-
    The sound of water.
    <<<END>>>
    Feel free to use anything from this page as
    long as you make references and links to HAIKU
    for PEOPLE. Last updated: Jan 10th. 2001.
    Edited by Kei Grieg Toyomasu,
    kei at toyomasu dot com""" )
    file.close()

def readFileTillMarker( fileName ):
    file = open( fileName, "r" )
    lines = []
    for line in file:
        if line.find( "<<<END>>>" ) != -1:
            return lines
        else:
            lines.append( line )
    return lines

def computePi():
    sum = 0
    multiplier = 1
    
    for i in range( 1, 20, 2 ):
        sum = sum + multiplier * 4.0 / i
        multiplier = -multiplier
        print( "Pi = ", sum )

def computePi2():
    sum = 0
    multiplier = 1

    i = 1
    while ( not ( 3.14 <= sum < 3.15 ) ):
        sum = sum + multiplier * 4.0 / i
        i = i+2
        multiplier = -multiplier
        print( "Pi = ", sum )
    print( "Final version of Pi = ", sum )
        
def main():

    # Part 1, Exercise 1
    x = getPositiveNumber()
    print( "getPositiveNumber() returned", x )

    # Part 1, Exercise 2
    if likesChoco() == True:
        print( "Me too!" )
    else:
        print( "Sorry to hear that!" )

    # Part 1, Exercise 3
    createFile( "lab8Demo.txt" )
    lines = readFileTillMarker( "lab8Demo.txt" )
    print( "Lines found by readFileTillMarker(): " )
    for line in lines:
        print( line.strip() )

    # Part 1, Exercise 4
    computePi2()
    
if __name__=="__main__":
    main()


Part 2


# lab8RPS_solution.py
# D. Thiebaut

from random import choice

# define constants for indicating the winner of a round
HUMANWINS    = 1
COMPUTERWINS = 2
TIE          = 3


# getUserInput(): prompts the user for a letter that is
# either 'R', 'S' or 'P'.  Keeps prompting until input is
# correct.
def getUserInput():
    while True:
        ans = input( "\n\nYour play (R, S, P)? " ).upper()
        if ans in ['R', 'S', 'P']:
            return ans
        print( "invalid input.\n" )
        
# winner(): decides who the winner is from the two characters
# passed, representing the user's and the computer's play.
def winner( user, computer ):
    # create a string with the 2 letters
    userComputer = user + computer

    # test two-letters and combinations of user winning
    if userComputer in [ "RS", "PR", "SP" ]:
        return HUMANWINS

    # test two-letters and combinations of ties
    if userComputer in [ "RR", "PP", "SS" ]: 
        return TIE

    # if we haven't returned yet, then the computer wins
    return COMPUTERWINS



# playRound: asks the user for her play, and compares it
# to the play picked by the computer.  Returns HUMAN if
# the user wins, COMPUTER if the user loses, or TIE if
# it's a tie.
def playRound():
    human    = getUserInput()
    computer = choice( ['R', 'P', 'S'] )
    win = winner( human, computer )
    print( "human:", human, "  computer:", computer )
    return win


# main program.  Allows the user to play against the computer,
# and reports on the winner of each rounds.
def main():
    hCount = 0    # human win-counter
    cCount = 0    # computer win-counter
    
    # play rounds
    while True:
        # play one round between computer and human
        winner = playRound()

        # see if human wins
        if winner == HUMANWINS:
            hCount += 1
            print( "You win!  Scores: computer:", cCount, " you:", hCount )

        # or if the computer wins
        elif winner == COMPUTERWINS:
            cCount += 1
            print( "I win!  Scores: computer:", cCount, " you:", hCount )
            
        # otherwise it's a tie
        else:
            print( "It's a tie!  Scores: computer:", cCount, " you:", hCount )

        if abs( cCount - hCount ) >= 3:
            break

    # announce the winner of the game
    if cCount > hCount:
        print( "\nYou lost the game!" )
    else:
        print( "\nCongrats, you won this, fair and square!" )


if __name__=="__main__":
    main()


</showafterdate>



...