Computer Science 110
Foundations of Computing through Digital Media

Denison

CS 110 Lab Project 2

Conditionals

Due: By classtime, Monday, September 30th

In this lab, you will practice with conditionals and with their underlying boolean expressions.

The first set of problems will be basic Python programs, with a traditional input-compute-output sequence, where you are given a word problem that requires the use of a conditional to solve the problem, and you are to write the corresponding Python program.

The main part of this homework set is the Rock/Paper/Scissors program, which will allow us to combine and enhance our graphics programming skills with the use of conditionals in the resulting program. It is interesting that, because of the event style programming here, we can do everything we need to with just functions and conditionals.

For each of the programs, I expect good variable names, good functions, and good commenting practices, with docstrings for each function, describing what the function does in terms of its parameters (sometimes called the function's 'givens') and detailing any return value and any output performed by the function. For RPS, the type contract and the examples do not really add to the user's understanding of the event functions, and may be omitted.

Each program should be structured, at a minimum, as a definition of a main function followed by its invocation. You should use functions to help package together related/coherent sets of Python statements, and I will be looking for good use of functions in my grading.

Problem 1: Conditionals in Python Programs

1. (GradeReport.py)   Write a full Python program (main() function definition with main() invocation) with the following functionality; prompt the user for their test grade.  If their grade is 90 or above, print "You got an A!"  If the grade is between 80 and 89, print "You got a B!"  If the grade is between 70 and 79, print "You got a C."  And if the grade is below 70, print "Uh oh... you should probably see me."  One and only one output should be printed for any particular value.  

2. (Divisible.py)   Write a full Python program that prompts the user to enter an integer.  Then report to the user whether that number is divisible by 2, 3 and 5.  For example, if the user enters 15, the output should be "15 is not divisible by 2, is divisible by 3, and is divisible by 5."  If the user enters 64, the output should be "15 is divisible by 2, is not divisible by 3, and is not divisible by 5."  Use only 3 if-statements.

3. (BMI.py)   Write a full Python program that, given a user's weight and height, entered in response to prompts from the program, then calculates and outputs the BMI corresponding to that height and weight, along with a message indicating whether the resultant BMI indicates an optimal weight, an underweight condition, or an overweight condition. BMI is calculated with the formula:

BMI = weight x 703 / (height)**2

A sedentary person's weight is considered to be optimal if his or her BMI is between 18.5 and 25. If the BMI is less than 18.5, the person is considered to be underweight. If the BMI is greater than 25, the person is considered to be overweight.

Problem 2: Rock / Paper / Scissors

Write the game Rock, Paper, Scissors. In a file called RPS.py, write a program that allows a user to play against the computer in a GUI version of the Rock, Paper, Scissors game. Below, I will recommend a staged approach that will allow you to focus on different parts of the solution at a time.

User Interface

The user interface for the game consists of a set of five buttons, along with two communications areas. The five buttons include three for the user to choose between their choices of Rock, Paper, or Scissors, and two buttons for control of the game ... an Execute button that tells the program to generate its choice and to then determine the win/loss outcome, and a Reset button that allows the program to return to an initial state with no user choice, no computer choice, and no outcome.

The first communication area has three labeled text areas that will record the User and the Computer's Choice, and, if Executed, the Outcome. The second communication area allows a place for the program to instruct the user and to inform them of uncommon situations, such as the user selecting Execute when they have not first made their own choice.

For the final version of the game, we want the buttons for Rock, Paper, and Scissors to show pictures of their respective objects, and for the entire picture area to be responsive to a mouse click indicating a user choice selection.

See the three figures below for examples from my initial (non-picture) implementation. You are welcome to innovate and create your own style for your own implementation:

Operation

Implementation Guidance

GUI Event Driven Programming

When applications are written to provide a graphical user interface (GUI), whereby the user controls the application by using buttons, menus, dialog boxes, and the like, development systems provide considerable support to both be able to provide a consistent user interface and to also make the programmers' job easier. The development system handles the often-complex details of interacting with the operating system and multiplexing between various graphical elements and controlling the waiting and polling involved with interpreting actions by the user and mapping them to a relatively simple set of "Events" that the programmer must handle. The set of events that we are concerned with in this program are the ones associated with a button-push in the GUI, and, more generally, with when a mouse button is pressed and released. The programmer writes individual functions that are, in the program, associated with the events of interest, and then the development system of performing the appropriate function invocation to call the associated event functions. This is why event-driven programs consist of a set of function definitions and a main function to get things set up, but do not have (visible) the loop looking for user actions and we do not see the explicit function invocations.

One important implication of this type of programming is that the programmer must have functions whose parameters conform to the expectation of the system. A button function has two parameters, one for the object that was pressed, the other for an object describing the event. See the Calico Graphics Button documentation. In that example, the function printit is the event action function, and it takes two parameters, where o is the object and e is the event, and the system takes care of invoking printit when the button is pushed. But what should the programmer do if s/he needs additional information from other parts of the program? The function may need the window object and other objects. We need a namespace frame that is available to all of the functions, and in which we can place the variables needed by these event functions to do their job.

I include below a prefix from my own implementation of RPS.py. We start with the imports, and I include an import of the random module, whose use I'll describe below. The code continues with the use of a set of assignments. I have said that we should not have executable statements at the global level outside of functions. The safe time to do this is what is illustrated below ... to assign some of the constants that are used throughout the program so that I can use variable/symbolic versions, which makes for more readable and more maintainable code. The next block of code, beginning with "class G" is the part of the example I want you to pay particular attention to. This "class" is a mechanism that Python gives us for creating a Namespace Frame. We can create the frame and establish the variable that we need our functions to access. Then, by using notation with the name of the class frame, G, along with the name of the variable, we can access these variables from any function throughout the lifetime of our program. In the first part of main, I show an example of this by assigning the Window object to G.win.

from Graphics import *
import random

SCALE = 20
GUI_WIDTH = 23 * SCALE
GUI_HEIGHT = 19 * SCALE

ROCK    = 1
PAPER   = 2
Scissors = 3

PICDIRECTORY = "/Volumes/SHARED/BRESSOUD/CS110-01/Resources/lab02/"

#---------------------------------------------------------------------------------------
class G:
    """
    The G class is used to create a Namespace Frame with the set of variables
    needed by GUI Event functions, since they will not be called directly by
    our main() or subordinate functions, and so we cannot use argument/parameter
    for these pieces of information needed by the functions.
    """
    win = None

    userPickText = None
    userPickInt = 0

    computerPickText = None
    computerPickInt = 0

    outcomeText = None
    instructionText = None

#---------------------------------------------------------------------------------------
def main():

    random.seed()

    G.win = Window('Rock, Paper, Scissors', GUI_WIDTH, GUI_HEIGHT)
Staged Development Approach
Some advice for development.
  1. Begin by designing the user interface. Add in all of the requisite buttons and text labels, laid out cleanly in a Window. Make sure you group like things together in functions, like we learned to do in the first programming project.
  2. Focus on getting one button to operate the way you desire. Say that you start with the Rock button, ... connect a function to it and use it to print out that you detected a click. Then use the G namespace frame variables to keep track of anything that you need to create when the Rock button is clicked that other functions, or even the "Rock Button Function", may need on subsequent button pushes.
  3. Expand to the other User Choice buttons.
  4. Next work on the Execute button function. Its operation is outlined above, and we will need to use conditionals for two things here: after we generate a random number between one and three, conditionals will allow us to do different processing based on the random number generated, the second use for conditionals will be to sort out the winner based on the rules of Rock/Paper/Scissors.
  5. If you perform an import random as shown at the beginning of my example, you can generate a random value between 1 and 3 (inclusive) by performing the function invocation: random.randint(1,3) -- that should be sufficient for the computer to "pick" one of Rock, Paper, or Scissors if we maintain in our program a correspondence between Rock being represented by an integer 1, Paper being represented by an integer 2, and Scissors being represented by an integer 3. Of course, there will be times when our program needs to display strings for each of the choices, but our conditionals will allow us to perform that processing.
  6. Shape objects in Calico, once drawn into a window, may be "undrawn" from a window. The shape.undraw() method performs this. This can allow a previous choice by the user, if one exists, to be removed from the window and a new one put in its place. This can also come in handy for implementing the Reset functionality.
  7. Don't forget to make the program user friendly. Use the instruction communication area to provide guidance to the user. A parent or grandparent should be able to play your game without you having to tell them what to do next.
Enhancements
You will be graded in part on your creativity. Make the user interface fun and engaging in some manner. Extra credit will be given based on how creative you get beyond the basic interface. Some suggestions for enhancements:
  1. Use jpeg pictures of the three objects, scaled down to fit in your GUI, to make the rectangles associated with the buttons. A basic implementation of this design is shown below. I have included these particular three jpegs on the Share drive in the folder/directory given by the string named PICDIRECTORY in my example above.
  2. Instead of relying on the Calico Button objects, a picture-based button would be more intuitive for the user. This would be where the entire picture, for instance of the Rock, could be clicked on and have that constitute a user choice. This involves writing a function for the mouse-up event (see Calico Mouse), finding the coordinates of the mouse at the time of the event, and using conditionals to determine which, if any, of the user choices the mouse was over at the time of the event.
  3. Any fans of the Big Bank Theory? There is an extension of the classic Rock/Paper/Scissors game called Rock/Paper/Scissors/Lizard/Spock. A little Google-ing should get you all the information you need. That would be a definite extra credit extension!