#-------------------------------------------------------------------------- # KCA.log # # Descript: Kamehameha Coding Academy at Kamehameha High School. # This document is a log of what we did... often summarizing. # Author: Kathy Cooksey # Collaborators: Michelle Correia # # Key: # [name]> or [name]$ or In [#]: command line of shell or ipython # # comments # ? questions # @ answers # ! ideas, to do # Website: http://guavanator.uhh.hawaii.edu/~kcooksey/teaching/CS.html #-------------------------------------------------------------------------- 30 Sep 2015 #Today we set up individual student accounts on the LC computers #First, we used the Mac OSX app Launchpad to find and open X11 (a terminal window; more specifically, an xterm) #Then we held down the mouse button on X11 icon to "Keep in dock" (under options) #In X11, we ran the following command to open the Aquamacs app: bash-3.2$ open /Applications/Aquamacs.app #As a test of what was going to happen next, I had everyone check whether the shell could find ipython by: bash-3.2$ which ipython #That printed nothing #Then we used the graphical user interface (GUI) properties of Aquamacs to create and save a .bashrc in the home directory. --the .bashrc looked like the following ~~~~~ BEGIN .bashrc ~~~~~ ## Find packages export PATH="/opt/local/bin:/opt/local/sbin:$PATH" ## aliases to prevent accidental deletion, etc. alias ls="ls -a" alias rm="rm -i" alias mv="mv -i" alias cp="cp -i" alias aquamacs="open /Applications/Aquamacs.app" ## Color prompts and listing export CLICOLOR=1 export LSCOLORS=ExFxCxDxBxegedabagacad ## Making the prompt spiffy ## [KCA] directory $ PS1="\[\033[1;30m\][\[\033[1;34m\]KCA\[\033[1;30m\]] \[\033[0;32m\]\W \[\033[1;30m\]\$\[\033[0m\] " ## Enable bash command history ## http://superuser.com/questions/174306/how-can-i-enable-the-bash-command-history set -o history HISTFILE=$HOME/.bash_history HISTFILESIZE=500 HISTSIZE=500 ~~~~~ END .bashrc ~~~~~ #Except now I've added some comment lines (after pound (#) signs) and some options to make nice colors and prompt (thought I'm not sure whether the prompt will work --I also looked up how to enable recording of bash history so we'll try that too #We sourced the .bashrc (i.e., bash configuration file) as follows: bash-3.2$ . .bashrc --note, this only works when one is in her/his home directory --if there were errors, the terminal would "bark" at you by printing something #We tested we did everything correctly (because even if the shell didn't bark at us, we may have had mistakes): bash-3.2$ which ipython /opt/local/bin/ipython #That second line should have been the response to our which command #We then made a "working directory." From the home directory, we: bash-3.2$ mkdir KCA #Then we navigated into that directory from the command line: bash-3.2$ cd KCA #We then actually started playing with Python: bash-3.2$ ipython Python 2.7.10 (default, Aug 21 2015, 13:13:42) Type "copyright", "credits" or "license" for more information. IPython 4.0.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: print('Hello, World') Hello, World In [2]: print("Hello, World") Hello, World #And a few iterations of that to demonstrate how single, double, triple-single, and triple-double quotes work #We did some math: In [3]: 17+4+6+4+2 Out[3]: 33 #That was our estimate for my age #We got sucked into playing with importing from the math package In [4]: from math import pi, sin In [5]: print(pi) 3.14159265359 In [6]: sin(90) Out[6]: 0.8939966636005579 In [7]: sin(pi/2) Out[7]: 1.0 In [8]: sin(pi) Out[8]: 1.2246467991473532e-16 #We discussed how this showed (1) that the function sin() expects angles in radians and (2) there's a limit to the number of digits that a computer can keep in memory (pi should be irrational with an infinite number of digits and sin(pi) should be exactly zero) #We looked at the help file/manual for the built-in sin() function from the math package as follows: In [9]: help(sin) #This brought up a screen that looked like: Help on built-in function sin in module math: sin(...) sin(x) Return the sine of x (measured in radians). (END) #It explicitly says it's expecting the input x in radians. --in the terminal, hit q to quit and return to the ipython prompt #Upon request from Mrs. Correia, we wrote our own function to work on degrees. #To do this, we opened up a new file in our ~/KCA/ directory called my_sin.py. We wrote our own function my_sin() in our program/package file my_sin.py. It looked like: ~~~~~ BEGIN my_sin.py ~~~~~ from math import pi, sin def my_sin(x): x_in_rad = x*pi/180 # radians return sin(x_in_rad) ~~~~~ END my_sin.py ~~~~~ #Then we could call it (and this is the preferred way): In [10]: import my_sin as my_sin In [11]: my_sin.my_sin(90) 1.0 #We ended up adding some more functions to our package file my_sin.py: ~~~~~ BEGIN my_sin.py ~~~~~ from math import pi, sin def my_sin(x): x_in_rad = x*pi/180 # radians return sin(x_in_rad) def hello_world(): print('Hello, World!') def hello(x): print('Hello, {0}!'.format(x)) ~~~~~ END my_sin.py ~~~~~ #We can access these changes by reloading our my_sin.py package: In [12]: reload(my_sin) Out[12]: In [13]: my_sin.hello_world() Hello, World! In [14]: my_sin.hello('Mrs. Correia') Hello, Mrs. Correia! In [15]: my_sin.hello(pi/2) Hello, 1.57079632679! #This showed a function, hello_world(), that accepts no inputs but does something (print 'Hello, World!') and a function, hello(), that takes an input ('Mrs. Correia' or pi/2) and does something (prints 'Hello,' plus what was passed into the function, then '!') #One can quit ipython by simply entering quit: In [16]: quit #Then the shell prompt returns bash-3.2$ #So next time we'll get more formal --we'll update our .bashrc if people haven't already --We'll make a codes/ directory under our KCA/ directory --We'll morph my_sin.py into a my_math.py and work more with that --we'll discuss more about UNIX #Everyone should read the tutorial on the website (listed above) where this file is linked #How to get history in Python (ipython only?): http://stackoverflow.com/questions/6558765/how-do-you-see-the-entire-command-history-in-interactive-python In [17]: import readline; print '\n'.join([str(readline.get_history_item(i)) for i in range(readline.get_current_history_length())]) 21 Oct 2015 #Some time was spent getting new people set up on computers (e.g., opening Aquamacs, creating/editing .bashrc in the home directory, sourcing it, creating KCA/ directory in the home directory, navigating into it, starting ipython) #Everyone is encouraged to review the UNIX, Emacs, & IDL Tutorial on the course website (ignore IDL unless on wants to learn about another programming language) #Everyone is encouraged to review Ch 2 of the Computational Physics textbook by Newman #Two UNIX tricks of the day: --Ctrl+C is the UNIX cancel key combo in case anything starts behaving funning, iPython session included --The command clear will flush the window and tidy it up, in the UNIX shell and in the iPython session #We started off by getting familiar with syntax (and jargon) #First, we revisited our old friend the print() function: In [1]: print('Hello, world!') Hello, world! #Python print() function takes the string 'Hello, world!' and echoes it back to the terminal #We can just enter code into the iPython session without using a function or an assignment statement (i.e., we can use the iPython session as a calculator or echo chamber) In [2]: 2015-1980 Out[2]: 35 In [3]: 'Hello, world!' Out[3]: 'Hello, world!' #As opposed to the first call, these commands result in an Out[#] prompt. #More often it's useful to define a variable instead of dumping to screen: In [4]: age = 2015-2000 In [5]: print(age) 15 #We can modify this variable (and it will be evaluated before being printed in this case): In [6]: print(age+35) 50 #Python has "loose typing" meaning that we can change age from a number to a string: In [7]: age='Hello, World' In [8]: age Out[8]: 'Hello, World' In [9]: print(age) Hello, World #Notice how the string quotes were there when we dumped to screen versus when we properly printed (in addition to the Out[#] prompt going away) #Lines 4 and 7 were assignment statements. The right-hand side of the equals sign was assigned to the variable on the left-hand side #Variable names can be a range of words, letters, and underscores (_). They must start with a letter. Capitalization matters (i.e., x is different from X). --some words are "reserved" meaning they can't be used as a variable name because Python needs that word for its fundamental working --I tried to use the example of True (a boolean; see below) but that worked, much to my surprise. Here's a better example: In [10]: for = 2 File "", line 1 for = 2 ^ SyntaxError: invalid syntax #This shows that 'for' cannot be a variable name. #Good coding necessitates useful ("readable") variable names. For example, line 7 was weird... an "age" is a string "Hello, World"? #Similarly, overly long variable names are cumbersome. For example, In [11]: age_of_kathy_cooksey=34 In [12]: print(age_of_kathy_cooksey) 34 #The variable name is very readable but so long (much longer than the variable... better would have been e.g., age_kc) #We touched on type compatibility. For example: In [13]: age='34' In [14]: age+5 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () ----> 1 age+5 TypeError: cannot concatenate 'str' and 'int' objects #In line 13, I defined age to be a string, even though it was a number in that string. Python can't add a number to a string (at least not without some help) #The error mention mentions "concatenate." That's joining strings together: In [15]: age+"5" Out[15]: '345' #The string doesn't become '39' because that would require math, but math only works on numbers and a string is not a number #This led to the formal introduction of data types. --whole numbers are integers, which can be positive or negative: -1, 15, 0 --numbers with decimal places are floats (short floting-point precision): -1., 0.15, 3.141592653589793 -roughly, a float can have 16 non-zero digits --complex numbers exist in Python (a complex number deals with the "imaginary" number that is the square-root of -1, which mathematicians denote with i). In Python, complex numbers use j instead of i: 3j, 1+0j, 3.1415+3.1415j --boolean means True or False (capital important to Python) and act like they say. We did a brief example of this: In [20]: if ques: ....: print('Hello, World') ....: Hello, World #This introduced the control element: if-statement --in this case, we assigned the variable ques with the boolean True --so the if-statement read: "if ques is true, then print 'Hello, World'" which it did #We covered some mathematical operators, first we started with division: / In [21]: 5/2 Out[21]: 2 #This showed that Python 2.7, which is what we're using, defaults to "integer division" (also called "truncated division") when the numerator (top of "fraction") and denominator (bottom) are integers --it rounds down: In [22]: -5/2 Out[22]: -3 #We can change this behavior by making at least the numerator or denominator a float, by adding a decimal place In [23]: 5./2 Out[23]: 2.5 In [24]: 5/2. Out[24]: 2.5 #The complement to "integer division" is to determine the remainder with the "modulo" operator (%): In [25]: 5%2 Out[25]: 1 In [26]: -5%2 Out[26]: 1 #This means that 2 divides into 5 an even two times with a remainder of +1/2 while 2 divides into -5 an even three times with a remainder of +1/2 #The basic list of mathematical operators include: --addition: + --subtraction: - --multiplication: * --division: / --integer division: // --modulo: % --exponent: ** #To demonstrate some of those: --even if both numerator and denominator are integers, we can force integer division with //: In [27]: 5.//2. Out[27]: 2.0 note that the output is a float (has a decimal place) --We can take any number to any power with ** In [28]: 10**9 Out[28]: 1000000000 In [29]: 3.14**2 Out[29]: 9.8596 #We revisited importing from Python packages, for example, getting the constant pi In [30]: from math import pi In [31]: pi Out[31]: 3.141592653589793 #Note that pi is echoed with 16 significant figures. I tried multiplying by increasingly large numbers, to get the surprising result that a new digit "appeared" and changed: In [32]: pi*10**16 Out[32]: 3.1415926535897932e+16 In [33]: pi*1e18 Out[33]: 3.1415926535897933e+18 --in this latter case, I changed to the "scientific notation": 1e18 to be 1 times 10^18... some calculators have an EE or E button for entering scientific notation (and Python also allows capital E: 1E18) --note: other programming languages use the caret (~) to for exponentials, like most calculators #I also showed a conversion function, float(), in addition to introducing that infinity does exist in Python though it can only render 16 significant figures In [34]: float('inf') Out[34]: inf #Now how this conversion of a string 'inf' to a float differs from just entering the string 'inf' In [35]: 'inf' Out[35]: 'inf' #For example, if I assign both to variables, one can be used for mathematical operations while the other is only a string: In [36]: bignum=float('inf') In [37]: string='inf' In [38]: 1/bignum Out[38]: 0.0 In [39]: 1/string --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () ----> 1 1/string TypeError: unsupported operand type(s) for /: 'int' and 'str' In [40]: '1/'+string Out[40]: '1/inf' #Then we moved on to writing a function into the file test.py saved in the home directory's KCA/ directory. It started as: ~~~~~ BEGIN test.py ~~~~~ def count(N): for ii in range(N): print(ii) ~~~~~ END test.py ~~~~~ #Aquamacs nicely colors this and---way more importantly---helps with the formatting because indentation is very important to Python --the reserved word 'def' defines a function, which we called 'count' (could have been anything) then the parenthesis surrounds the arguments (the variable N in this case, could have been anything) --notice that N is not defined anywhere in the code... it's waiting for the user to provide it... then it's defined and has the "scope" of inside the function count() (meaning we didn't get an N variable that meant anything on the "outside" of the function) #We imported this "package" so we could use (and reload) the function: In [41]: import test as test In [42]: test.count(10) 0 1 2 3 4 5 6 7 8 9 #First to notice is that Python counts from 0... 0 to 9 is 10 numbers #Other people discovered that it wouldn't work with negative integer and it would crash (produce error message) with floats (e.g., test.count(3.14)) #We showed how indentation matters (sort of) by adding to our code: ~~~~~ BEGIN test.py ~~~~~ def count(N): for ii in range(N): print(ii+1) print('done') ~~~~~ END test.py ~~~~~ #To incorporate that small change we had to reload (i.e., recompile): In [43]: reload(test) In [44]: test.count(10) 0 1 2 3 4 5 6 7 8 9 done #If we had indented print('done') it would have printed out N times, after each number (try it!) #The task became how to make Python count from 1 to the given number. The solution was in the print statement ~~~~~ BEGIN test.py ~~~~~ def count(N): for ii in range(N): print(ii+1) print('done') ~~~~~ END test.py ~~~~~ In [45]: reload(test) Out[45]: In [46]: test.count(10 1 2 3 4 5 6 7 8 9 10 done #Then the question was how to make it count by two's: ~~~~~ BEGIN test.py ~~~~~ def count(N): for ii in range(N): print(ii*2) print('done') ~~~~~ END test.py ~~~~~ #We started discussing the built-in Python function range() In [47]: range(10) Out[47]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #The range() function starts with zero (Python counting default) and increments by 1 up until (but not including) the provided argument, 10 in this case #But the function range() can take more than one argument and this will make it behave differently: In [48]: range(1,10) Out[48]: [1, 2, 3, 4, 5, 6, 7, 8, 9] #We ended by my asking, how could we use the functionality of range() to "count" from 1 to whatever number the user provided (and that's inclusive of the number provided) 4 Nov 2015 #We reviewed the basic data types from last time: --int (whole numbers), float (decimal places), boolean (true/false) #We continued with test.py and its count() function. --since Python starts counting from zero, we have to modify what's printed or the built-in Python function range() -Python's range() can be given one argument: range(N) to count from zero up to but not including N -if two arguments: range(1,N), it counts from the first argument (e.g., 1) up to but not including the second argument (N) -if three arguments: range(1,N,2), it counts from the first argument (e.g., 1) up to but including the second argument (N), in increments of the third argument (2) #Thus we modified our count() function in our test.py to "count by blah" where "blah" is some number (2 or 5) and we determined that if we told a kid to "count by blah" s/he would start with "blah" thus our function ended up looking like: ~~~~~ BEGIN test.py ~~~~~ def count(N,by): ## Enter for-loop and set ii to 0 up to N for ii in range(by,N+1,by): print(ii) print('done') ~~~~~ END test.py ~~~~~ --note that the line beginning with a hashtag or pound sign (#) is a "comment line" and are generally useful for documenting code -for yourself when you return to the code in two weeks and for someone else looking at your code #To compile this code: In [1]: import test as test #To run it: In [2]: test.count(10,3) 3 6 9 done #We started coding count() in order to show how a "control statement" works, in this case, a for-loop --for-loops interrupt the first-to-last execution of a code an allow a repetitive block of code be executed (in this case letting ii increment up and printing to screen) #We explored if-else (and later if-elif-else) statements as another example of a control statement, which includes a "conditional statement" #We wrote the evenodd() function in our test.py (because many functions can be in one package, which test.py is) ~~~~~ BEGIN test.py ~~~~~ def evenodd(N): if N%2 == 1: print('The number {0} is odd.'.format(N)) else: print('The number {0} is even.'.format(N)) ~~~~~ END test.py ~~~~~ --This re-introduced the mathematical operator "modulo" (%) which returns the remainder, thus an even number modulo 2 will have no remainder and an odd number modulo 2 will have a remainder equal exactly (==) to 1. #To re-compile the code: In [3]: test.evenodd(17) The number 17 is odd. #Then came the FizzBuzz challenge, a common software-engineer interview question (see http://c2.com/cgi/wiki?FizzBuzzTest) "FizzBuzz challenge: print the numbers 1 to 100. if the number is divisible by 3, print 'Fizz' if the number is divisible by 5, print 'Buzz' if the number is divisible by both 3 and 5, print 'FizzBuzz'" #We determine that output should look like (at least for the first few iterations): Output: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 #We set up a new function in test.py with some variables and set to work trying to implement the FizzBuzz challenge: ~~~~~ BEGIN test.py ~~~~~ def fizzbuzz(): nfizz = 3 fizz = 'Fizz' nbuzz = 5 buzz = 'Buzz' ~~~~~ END test.py ~~~~~ #Most people got to the point of importing count() functionality and placed some if-elif-else statements in the for-loop to get something like: ~~~~~ BEGIN test.py ~~~~~ def fizzbuzz(): nfizz = 3 fizz = 'Fizz' nbuzz = 5 buzz = 'Buzz' for ii in range(1,101): if ii%5 == 0: print('Buzz') if ii%3 == 0: print('Fizz') else: print(ii) ~~~~~ END test.py ~~~~~ #This code isn't correct... we're exploring this more next time but one reason we instantiated the variables is to use them, so the above code is more generically written as: ~~~~~ BEGIN test.py ~~~~~ def fizzbuzz(): nfizz = 3 fizz = 'Fizz' nbuzz = 5 buzz = 'Buzz' for ii in range(1,101): if ii%nbuzz == 0: print(buzz) if ii%nfizz == 0: print(fizz) else: print(ii) ~~~~~ END test.py ~~~~~ #This allows us to be more generic... we can then evolve the code to be the real FizzBuzz game (https://en.wikipedia.org/wiki/Fizz_buzz) where we could have 'Tick' be printed when the number is divisible by 4 and 'Tock' when divisible by 7 or 'Marco' when divisible by 3 and 'Polo" when divisible by 11 #This is the notion of versatility (or "being generic") which is a solid way to code and requires abstracting the problem, which is tough well worth pursuing 25 Nov 2015 #Small crowd today but we did tackle making the fizzbuzz() function in test.py generic #The keys are to remember: --the modulo operator (%) gives the remainder of the integer division of the left-hand number by the right-hand number. For example: In [1]: 7%3 Out[1]: 1 --A conditional is True if non-zero and False if zero. Thus, since 7%3 returns 1 then In [2]: if 7%3: ...: print('hi') ...: hi --Multiple conditionals can be combined with 'and' or 'or'. For example, if I want to check if 7 is divisible by 3 and 4: In [3]: if 7%3 == 0 and 7%4 == 0: ...: print('hi') ...: prints nothing! --a function can accept arguments, either required or optional. We saw this with our first count() function in test.py: def count(N): for ii in range(N): print(ii+1) where N is the required argument. One cannot call the count() function without providing a value for N. -it could be that we define N in the Python session and then pass it in: In [4]: import test as test In [5]: val = 5 In [6]: test.count(val) 1 2 3 4 5 Note that the variable in the session doesn't have to have the same name as used in the count() function. We could also enter a number: In [7]: test.count(3) 1 2 3 -the point is that in our defintion of count, the variable N is never defined before it is used in the range() call --as for the optional argument, in Python, one has to set default value(s), for example, if we want our count() function to "count by", we could define it as: def count(N,by=1): for ii in range(by,N+1,by): print(ii) The default would then be to count from 1 (i.e., by = 1) to N+1 (inclusive): In [8]: test.count(10) 1 2 3 4 5 6 7 8 10 But if we want to "count to 10 by 3's, it'd be: In [9]: test.count(10,by=3) 3 6 9 #All this combined can lead one to design a robust, generic fizzbuzz() function. #Tonight's attendees were also informed about commenting codes. Not just to make it readable for future posterity but also to help them understand and learn. Pepper your code with comments! #Thus, I copied test.py to fizzbuzz.py for clarity and posterity and added lots of comments (preceded by hashtag or pound sign, i.e., # or between triple quotes). It looks as follows: ~~~~~ BEGIN fizzbuzz.py ~~~~~ ## ######### ## Written by Kathy Cooksey ## November 2015 ## for Kamehameha Coding Academy ## ## To use this package, in a python or ipython session, compile: ## In [1]: import fizzbuzz as fb ## ## Then run a function: ## In [2]: fb.fizzbuzz() ## ## If changes are made to this file (fizzbuzz.py), re-compile: ## In [3]: reload(fb) ## ## Then re-run as in line [2] above. ## ## To see information about the functions (and this header): ## In [4]: help(fb) ## ######### def count(N,by): """ Count from by to N (inclusive) in increments of by. N and by must be integers (i.e., whole numbers). For example, "count to 100 by 3's": fb.count(100,3) """ ## Use following syntax for Python's range() function: ## by: first argument, starting number ## N+1: second argument, ending number (non-inclusive) ## by: third argument, increment for ii in range(by,N+1,by): print(ii) def evenodd(N): """ Print whether the input number N is even or odd. N must be an integer. """ ## The percent sign (%) is the modulo operator, that returns the ## remainder of the integer division of the first number by the ## second. For odd numbers, the remainder when dividing by 2 is ## always 1. if N%2 == 1: print('The number {0} is odd.'.format(N)) else: print('The number {0} is even.'.format(N)) def fizzbuzz(N=100,fizz=(3,'Fizz'),buzz=(5,'Buzz')): """ For nn = 1 to N, evaluate the number nn, if nn is divisible by fizz[0] only, print fizz[1]; divisible by buzz[0] only, print buzz[1]; divisible by both, print fizz[1]+buzz[1]; else print nn. N must be an integer. fizz and buzz must be 2-element tuples or lists with an integer and a string (or something to be printed) For example: fizzbuzz(50,fizz=[4,'Tick'],buzz=(7,"Tock")) """ ## The optional arguments to the fizzbuzz() function ## have default values as given. ## The fizz and buzz variables are tuples. A tuple is a Python ## "container" of anything; it cannot be changed (immutable). ## They could be given by the user as lists (square ## brackets). Lists are Python "containers" o anything; they can ## be changed (mutable) ## Loop over nn from 1 to N (inclusive, noting that Python counts ## from 0 and the second argument to the range() function is ## non-inclusive) for nn in range(1,N+1): ## It is expedient to save the modulos of the number nn, where ## the modulo yields the remainder of the division of the left ## variable by the right (e.g., nn divided by fizz[0]) mod_fizz = nn % fizz[0] mod_buzz = nn % buzz[0] ## Most stringent requirement is a number divisible by both, ## thus check it first. if mod_fizz == 0 and mod_buzz == 0: print(fizz[1]+buzz[1]) # string concatenation ## The next two conditionals are mutually exclusive and order ## doesn't really matter. elif mod_fizz == 0: print(fizz[1]) elif mod_buzz == 0: print(buzz[1]) ## The default (hence: else) is to print the number itself. else: print(nn) ~~~~~ END fizzbuzz.py ~~~~~ 11 Jan 2016 #We closed the FizzBuzz challenge but reminded everyone my full solution in this log #We discussed/review the nature of the comments for those who were not in attendance last time --there's the header block that shows up as the Description when using the Python help() function --the comments in triple-quote blocks also show up beneath each function --comments can be anywhere after the pound-sign/hashtag (#) #Students are encouraged to take their notes in the codes we're working on by using pound-sign/hashtag (#) #To start sorting, we opened a new file bubble_sort.py (bubble sort is the name for the type of algorithm we will write) --I recommend putting in a header, so I cut and paste from fizzbuzz.py ~~~~~ BEGIN bubble_sort.py ~~~~~ ## ######### ## Written by Kathy Cooksey ## November 2015 ## for Kamehameha Coding Academy ## ## To use this package, in a python or ipython session, compile: ## In [1]: import bubble_sort as bs ## ## Then run a function: ## In [2]: bs.sort() ## ## If changes are made to this file (fizzbuzz.py), re-compile: ## In [3]: reload(bs) ## ## Then re-run as in line [2] above. ## ## To see information about the functions (and this header): ## In [4]: help(bs) ## ######### ~~~~~ END bubble_sort.py ~~~~~ #We discussed what we needed to have to sort a set of random numbers --answer: a set of random numbers #To do this, we worked with functions from the Python random package --thus, we added the following after the header: ~~~~~ BEGIN bubble_sort.py ~~~~~ import numpy as np # allows array operations from random import randrange, seed # functions ~~~~~ END bubble_sort.py ~~~~~ #We also entered these commands into a Python or iPython session to test what they do In [1]: from random import randrange #This enables us to use the randrange() function --we made predictions what would happen and tested it In [2]: randrange(50) Out[2]: 27 #It produces one number #But since we're trying to understand the function (and we are dealing with randomness), we called it several times In [3]: randrange(50) Out[3]: 39 In [4]: randrange(50) Out[4]: 44 In [5]: randrange(50) Out[5]: 0 #From this we can guess that we get positive integers (whole numbers) up to (an including) zero (0) up to but not including the number we input (50 in this case) #The group of us doing this on the various computers came up with different sequences of numbers --because the "seed" for a (pseudo)random number generator is likely unique to the machine (e.g., the clock time and the IP address) #Since we don't necessarily want to keep changing our random numbers while we're writing and testing code (and since we may all want to have the same set of numbers) we learned to set the seed #So first we need to import the function seed() from the random package In [6]: from random import seed #I had us set the seed to my favorite number In [7]: seed(17) #Then we manually generated a series of random numbers: In [8]: randrange(50) Out[8]: 26 In [9]: randrange(50) Out[9]: 40 In [10]: randrange(50) Out[10]: 48 In [11]: randrange(50) Out[11]: 14 #We all go the same series #And we can always get the same number my just resetting the seed In [12]: seed(17) In [13]: randrange(50) Out[13]: 26 In [14]: randrange(50) Out[14]: 40 In [15]: randrange(50) Out[15]: 48 In [16]: randrange(50) Out[16]: 14 #And after class I played to figure out how to return the seed to the default so we could get random numbers without reliance on our seed --the solution was just to call seed() without arguments In [17]: seed() In [18]: randrange(50) Out[18]: 2 In [19]: randrange(50) Out[19]: 25 In [20]: randrange(50) Out[20]: 25 In [21]: randrange(50) Out[21]: 7 #And just to prove calling just seed() does something (pseudo)random, we can do it again and see different numbers In [22]: seed() In [23]: randrange(50) Out[23]: 36 In [24]: randrange(50) Out[24]: 45 In [25]: randrange(50) Out[25]: 46 In [26]: randrange(50) Out[26]: 14 #We talked about how these are pseudo-random numbers, where the "pseudo" modifiers reminds us that the computer is just doing what we ask it to do --it relies on a seed we may not know but eventually the random numbers will repeat itself --and if we're using a poor pseudo-random number generator, we could figure out the seed and the pattern of random numbers to predict the next ones --random numbers have uses in games (not just computer games but also the lottery) and encryption/cryptography -needless to say, they're very important in modern society #Back to bubble_sort.py: we now have a way of making a random draw from (and including) zero (0) and some number so we used that to make a series of random numbers --for this we looked at the function count() in our fizzbuzz.py and generated the following function ~~~~~ BEGIN bubble_sort.py ~~~~~ def make_randnum(N, nseed=False): """ Generate array of random numbers from 1 to N (inclusive) """ if nseed: seed(nseed) else: seed() # to undo any previous seed-setting rnum_list = [] # this is by list (could be rnum_list = range(N)) for ii in range(N): rnum = randrange(N) + 1 rnum_list.append(rnum) # if used rnum_list = range(N) then this is rnum_list[ii] = rnum) return rnum_list ~~~~~ END bubble_sort.py ~~~~~ #So we made sure to put a description block in the triple-quotes (though it could be better and describe what nseed does) #The if-else statement handles the optional argument nseed to see whether the user wants to define a seed to make a completely repeatable series of random numbers --after class, I added the else component to undo any previous seed-setting (as the comment describes) #We introduced the concept of lists in Python. --lists are a container for several data types. In Python they can hold many things (and a mix of things) but we are just using it for our series of random integers --we made an empty list with the rnum_list = [] syntax -but we could have used the range() function to make a list with the right number of elements (it would be from 0 up-to-but-not-including N and we have to make sure to overwrite each element with a random number) --then we entered our loop to repeat a block of codes N times and each time the iterator ii would be set to the elements of the iterator produced by range(N) (which I mentioned, is actually a list from 0 up-to-but-not-including N) -each iteration of the loop, we just draw a random number with randrange(N) which produces a random integer from 0 up-to-but-not-including N -and since we decided we wanted our code to behave like human counting, we actually want the random numbers to be from 1 to N (inclusive) so we add 1 to the result of randrange(N) -then we append it to the list #We can then import the code and use our function In [27]: import bubble_sort as bs In [28]: bs.make_randnum(10) Out[28]: [ 8, 9, 4, 6, 9, 4, 2, 10, 1, 5] In [29]: bs.make_randnum(10,nseed=17) Out[29]: [ 6, 9, 10, 3, 8, 8, 7, 2, 1, 4] In [30]: bs.make_randnum(10) Out[30]: [ 7, 7, 3, 4, 1, 9, 10, 3, 4, 4] #All of which shows that we get a list (literal Python list) of numbers from 1 to 10 (inclusive), in random order and duplicates allowed --the probability of duplicates will decrease the larger N is #Right now we're letting Python just spit our list to the screen but we want to assign it to a variable we can use In [31]: rnum_list=bs.make_randnum(10) In [34]: rnum_list Out[34]: [ 2, 7, 10, 4, 4, 4, 5, 10, 8, 8] #And now rnum_list which exists in our Python or iPython session is unchanged by whatever happens in our function make_randnum() In [35]: bs.make_randnum(10) Out[35]: [2, 8, 5, 4, 9, 7, 9, 5, 2, 5] In [36]: rnum_list Out[36]: [ 2, 7, 10, 4, 4, 4, 5, 10, 8, 8] #So rnum_list can be an input to a function that actually does the bubble sort #But before that, I introduced NumPy arrays which are a different kind of container than Python lists --primarily they are only for numbers (integers, floats, complex numbers) where lists can be nearly anything and a mix thereof (strings, lists,...) --NumPy arrays are used a lot in scientific computing because they make calculations easier so I introduce them #For that we need to import NumPy to our code --I actually put the import statement with the other import statement (for randrange() and seed()) but below I show it and the changes ~~~~~ BEGIN bubble_sort.py ~~~~~ import numpy as np # allows array operations def make_randnum(N, nseed=False): """ Generate array of random numbers from 1 to N (inclusive) """ if nseed: seed(nseed) else: seed() # to undo any previous seed-setting rnum_list = np.empty(N,int) # this is by array for ii in range(N): rnum = randrange(N) + 1 rnum_list[ii] = rnum return rnum_list ~~~~~ END bubble_sort.py ~~~~~ #Just a few changes but this means rnum_list is actually an array --so technically the "list" part of the variable name isn't good #Let's look at how this does or does not change the output In [37]: reload(bs) Out[37]: In [38]: bs.make_randnum(10) Out[38]: array([ 3, 10, 1, 7, 1, 5, 9, 7, 7, 1]) In [39]: bs.make_randnum(10,nseed=17) Out[39]: array([ 6, 9, 10, 3, 8, 8, 7, 2, 1, 4]) In [40]: rnum_list=bs.make_randnum(10,nseed=17) In [41]: rnum_list Out[41]: array([ 6, 9, 10, 3, 8, 8, 7, 2, 1, 4]) #Python is telling us the type when it prints (it now says array) --but when we use nseed=17, we still get the same series of numbers as when we did it with a list... all good #So we started writing the actual bubble_sort() function --I brought up a funny aspect of Python after we had worked on bubble_sort() for awhile but I wanted to clear it up: we need to make sure our Python function isn't going to affect our variables so we need to copy right away -for that, I used NumPy copy() function which automatically converts the input to a NumPy array so it doesn't matter whether we input a Python list (or tuple or NumPy array) --but since I also wanted to use the copy() function from the copy package, I import that (placing it with the other import statements) --also, we want to generically know how long the input series of numbers is so we use the built-in len() function #The first task we did was to look at having the program compare neighbors from the series of numbers --note the range() call in the for-statement. We don't want to overflow the array rnum_list so we loop over range(N-1) -and we use a for-loop because the program needs to "look" at every number to sort them just like how we sort the numbers by scanning over them --the syntax rnum_list[ii] is indexing... rnum_list has several elements and the term in the square bracket is the index (or address) of that element -this is one of those things to play with #All of this looked like ~~~~~ BEGIN bubble_sort.py ~~~~~ from copy import copy def bubble_sort(rnum_list0): rnum_list = np.copy(rnum_list0) N = len(rnum_list) for ii in range(N-1): if rnum_list[ii] > rnum_list[ii+1]: print(rnum_list[ii+1],rnum_list[ii]) else: print(rnum_list[ii],rnum_list[ii+1]) ~~~~~ END bubble_sort.py ~~~~~ #Then we can run it on our saved list in the Python or iPython session In [42]: rnum_list Out[42]: array([ 6, 9, 10, 3, 8, 8, 7, 2, 1, 4]) In [43]: reload(bs) Out[43]: In [44]: bs.bubble_sort(rnum_list) (6, 9) (9, 10) (3, 10) (3, 8) (8, 8) (7, 8) (2, 7) (1, 2) (1, 4) #And we can see that our bubble_sort() properly prints the lower number #The trick to sorting is the ability to move the numbers --swapping is tricky because we have to be careful not to delete the information before we properly store it -Python actually makes it easy but not transparent so I leave the single-line copy syntax commented out --and we use the copy() function to be careful (Python passes by reference as opposed to by value which can cause subtle problems and I frankly don't know when it causes problems) ~~~~~ BEGIN bubble_sort.py ~~~~~ def bubble_sort(rnum_list0): rnum_list = np.copy(rnum_list0) N = len(rnum_list) for ii in range(N-1): if rnum_list[ii] > rnum_list[ii+1]: #rnum_list[ii+1],rnum_list[ii] = rnum_list[ii],rnum_list[ii+1] ## very carefully swapping numbers with no loss tmp_num = copy(rnum_list[ii]) rnum_list[ii] = copy(rnum_list[ii+1]) rnum_list[ii+1] = copy(tmp_num) print(rnum_list) ~~~~~ END bubble_sort.py ~~~~~ #We have the print() statement to see out our sorting evolves with every loop (and compare to the original) In [45]: reload(bs) Out[45]: In [46]: rnum_list Out[46]: array([ 6, 9, 10, 3, 8, 8, 7, 2, 1, 4]) In [47]: bs.bubble_sort(rnum_list) [ 6 9 10 3 8 8 7 2 1 4] [ 6 9 10 3 8 8 7 2 1 4] [ 6 9 3 10 8 8 7 2 1 4] [ 6 9 3 8 10 8 7 2 1 4] [ 6 9 3 8 8 10 7 2 1 4] [ 6 9 3 8 8 7 10 2 1 4] [ 6 9 3 8 8 7 2 10 1 4] [ 6 9 3 8 8 7 2 1 10 4] [ 6 9 3 8 8 7 2 1 4 10] #No we see how we get more sorted (like the 10 moved all the way to the end since it was always bigger than everything) #This is where we finished and leave it for everyone to think about what we have to do next to continue sorting #Below I repeat the full bubble_sort.py that everyone should have (though there can be alternate forms because this is an evolving code) --everyone should comment their codes to help learning ~~~~~ BEGIN bubble_sort.py ~~~~~ ## ######### ## Written by Kathy Cooksey ## November 2015 ## for Kamehameha Coding Academy ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## To use this package, in a python or ipython session, compile: ## In [1]: import bubble_sort as bs ## ## Then run a function: ## In [2]: bs.bubble_sort() ## ## If changes are made to this file (bubble_sort.py), re-compile: ## In [3]: reload(bs) ## ## Then re-run as in line [2] above. ## ## To see information about the functions (and this header): ## In [4]: help(bs) ## ######### import numpy as np # allows array operations from random import randrange, seed # functions from copy import copy def make_randnum(N, nseed=False): """ Generate array of random numbers from 1 to N (inclusive) """ if nseed: seed(nseed) else: seed() # to undo any previous seed-setting rnum_list = np.empty(N,int) # this is by array for ii in range(N): rnum = randrange(N) + 1 rnum_list[ii] = rnum return rnum_list def bubble_sort(rnum_list0): rnum_list = np.copy(rnum_list0) N = len(rnum_list) for ii in range(N-1): if rnum_list[ii] > rnum_list[ii+1]: #rnum_list[ii+1],rnum_list[ii] = rnum_list[ii],rnum_list[ii+1] ## very carefully swapping numbers with no loss tmp_num = copy(rnum_list[ii]) rnum_list[ii] = copy(rnum_list[ii+1]) rnum_list[ii+1] = copy(tmp_num) print(rnum_list) ~~~~~ END bubble_sort.py ~~~~~ 25 Jan 2016 #One student today so we did work on finishing the bubble sort (bubble_sort.py) but I'm not going to reveal that #Instead I'll highlight some tangential items we covered #First, about the file system. It has commonly happened that students think they are in the KCA/ directory because the prompt on the XQuartz/X11 terminal is: [KCA] ~ $ when it is first started --but the word in the square brackets is just a word -you can change it in your ~/.bashrc file -my laptop says [Haupia] ~ $ because Haupia is the name of my laptop --the tilde/twiddle (~) indicates the directory, which is your home directory when XQuartz/X11 starts --If you actually turn on seeing your home directory in the Finder sidebar (Preferences:Sidebar:Favorites home icon), what is listed in Finder as in your home directory will be a subset of what you see when you list (ls) in XQuartz/X11 when the prompt is [KCA] ~ $ -we see more than Finder lists because I configured our ~/.bashrc to alias ls -a to ls which means I made the shell list (ls) all (-a) --If you change directory (cd) to your directory KCA, the prompt changes [KCA] KCA $ because the text in green (before the dollar sign) is the current directory --I refer the interested reader to the Unix, Emacs, & IDL tutorial, found via the "course" website #Second, I reviewed arrays, indices, and elements --a (NumPy) array is a container of numbers: 5, 32, 42, 110000 --an index is the address of a number in the array container, it runs from 0 up to the number in the array (non-inclusive) --an element is what is stored at the address of a number in the array container (i.e., the number itself) --for example: In [1]: import bubble_sort as bs In [2]: rnum_list = bs.make_randnum(10,nseed=17) In [3]: for ii in range(10): ...: print(ii,rnum_list[ii]) ...: (0, 6) (1, 9) (2, 10) (3, 3) (4, 8) (5, 8) (6, 7) (7, 2) (8, 1) (9, 4) --Indices (tracked by the ii of the for-loop) are the first column and elements are the second, they represent the random numbers we worked last time to generate: In [4]: print(rnum_list) [ 6 9 10 3 8 8 7 2 1 4] #Next time, if there are people who missed today but were at the beginning of the "bubble sort challenge," we'll continue --and CJ was inspired by our progress to wonder if we can sort numbers by even/odd or divisible by 3 or not, etc. This is a good challenge expansion that factors in our FizzBuzz work. 1 Feb 2016 #A single attendee again tonight (though a different one) #We updated comments on bubble_sort.make_randnum() so I'll reproduce the essence of that below: ~~~~~ BEGIN bubble_sort.py ~~~~~ ## ######### ## Written by Kathy Cooksey ## November 2015 ## for Kamehameha Coding Academy ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## To use this package, in a python or ipython session, compile: ## In [1]: import bubble_sort as bs ## ## Then run a function: ## In [2]: bs.bubble_sort() ## ## If changes are made to this file (bubble_sort.py), re-compile: ## In [3]: reload(bs) ## ## Then re-run as in line [2] above. ## ## To see information about the functions (and this header): ## In [4]: help(bs) ## ######### import numpy as np # allows array operations from random import randrange, seed # functions from copy import copy def make_randnum(N, nseed=False): """ Generate array of random numbers from 1 to N (inclusive) """ if nseed: # if nseed non-zero seed(nseed) # fix the random-number generator to make repeatable random-number sequence else: seed() # to undo any previous seed-setting (Python default method) rnum_list = np.empty(N,int) # an empty array of length N for storage, assigned to variable rnum_list for ii in range(N): # each iteration, set ii equal to the next value in range(N), which is from 0 to N-1 rnum = randrange(N) + 1 # draw a random number from 0 to N-1, but add 1 to behave like "counting" rnum_list[ii] = rnum # store the random number in the rnum_list container (array) return rnum_list # return the list of N random numbers between 1 and N def bubble_sort(rnum_list0): rnum_list = np.copy(rnum_list0) # completely copy the input rnum_list0 to a local variable rnum_list N = len(rnum_list) # determine the length of the array to sort ## First step in coding a bubble sort: ## brute force swapping pairs for ii in range(N-1): # loop over the 1st to next-to-last elements of rnum_list array if rnum_list[ii] > rnum_list[ii+1]: # compare "current" element to "next-in-line" ## very carefully swapping numbers with no loss tmp_num = copy(rnum_list[ii]) # copy "current" element to temporary variable rnum_list[ii] = copy(rnum_list[ii+1]) # copy "next-in-line" variable to "current" location rnum_list[ii+1] = copy(tmp_num) # copy what was "current" to "next-in-line" location ## or streamlined swapping method allowed by Python # rnum_list[ii+1],rnum_list[ii] = rnum_list[ii],rnum_list[ii+1] print(rnum_list) # return the slightly-more-sorted from low-to-high array ~~~~~ END bubble_sort.py ~~~~~ 8 February 2016 #No attendees today. I demoralized the class with my bubble-sort activity #So that's gone for the next class (Feb 22 since Feb 15 is a holiday) #But I wanted to motivated the bubble-sort activity better today so let me explain how I was going to try #Basically, I wanted to introduce everyone to the concept of an "algorithm" #We started the class talking about how a computer program will do exactly what it's told --algorithms are the instructions --if you want your friend to do you a favor and you need that favored executed exactly, what would you write down? -how would you test whether your instructions were specific and complete enough? #So I was going to give everyone a random 10 cards from a deck of playing cards --if the rules we have so far programmed into bubble_sort.py are mapped onto this step, this is what make_randnum() was for #Then everyone was to follow the explicit rules we had so far programmed: with all the cards in a stack, face up 1. examine the card on top and the next in line. If the current card (i) is larger than the next card (i+1), then swap their positions 2. take the card that is now on top and set it face down. This signifies incrementing the iterator i 3. repeat steps 1 and 2 until at the last card, where there is no "next" with which to compare #This is as far we've programmed. So the questions were going to be: --looking at the order now (remembering that we were aiming to go from lowest to highest), how did we do? --what if you had a different random set of cards? or just shuffled the ones you have? How would our three-step algorithm above work? --what is still left to do? What are the explicit instructions we could add to our algorithm? --how would we code this addition in our bubble_sort.py? #I have a plan to bring our incomplete bubble sort back into our lives via a "science project" (still programming) after spring break #Next week we will use our understanding of random numbers to code up a simple game (inspired by Mrs. Correia!) 22 Feb 2016 #I learned that 8 Feb 2016 was never on the class schedule so there's that #There was only one student today and we opted to proceed to programming the game: Rock, Paper, Scissors! #We had a discussion about what a human computer (i.e., a person) does when playing Rock, Paper, Scissors so we identify what we would have to program a computer to do #We know it's a random process --yeah, yeah, some people try to psychoanalyze who s/he is playing to figure out what s/he is going to do on the count-of-3 --but really, it's just a random draw #So the first step is drawing a random number and assigning it to a variable that can be used --we discussed the difference between the function randrange() (used previously) and random(), both from the random package --randrange(N) returns a random integer (i.e., whole number) greater-than-or-equal-to zero (i.e., >= 0) and less-than (but not equal-to) the argument N (i.e., < N) -e.g., randrange(100) might return 0 or 17 or 99, but never 100 -or in more mathematical terms: for n = randrange(N) 0 <= n < N --random() which requires no argument (hence the empty parentheses) returns a random float (i.e., number with decimal places) greater-than-or-equal-to zero (>= 0.0) and less-than one (< 1.0) -e.g., random() might return 0.6202428658873076 or 0.0 or 0.9999999999999999, but never 1.0 -again in mathematical terms, for n = random() 0.0 <= n < 1.0 --random numbers typically start off >= 0 and < 1 and then are "scaled-up" by the range desired -for example, if we want an integer >= 0 and < 100 (like randrange(100)) we could use the following syntax: n = int(random()*100) (in the library, I used the round() function instead of the int() function, which returned a float) #Ok, now we have some idea of drawing random numbers, either integers or floats, and how to control the range in which the random number is drawn #Next is to think about probabilities --for example, what is the probability a normal coin flipped will land heads-up? 50% because there are only two choices (heads or tails) and the total probability of any event must be 100% --for Rock, Paper, Scissors, there are three choices -if we want them to be equally likely (i.e., probable) then each is worth 1/3 of 100% -note: the fraction 1/3 is equivalent to 33.333333...% -also note: in Python 2.7, 1/3 evaluates to zero while 1./3 or 1/3. evaluates to 0.3333333333333333 --and we want the random choice to result in Rock or Paper or Scissors with no gaps --we turned to a series of if-elif-else statements to make this work -where a block of code in an if-statement is only executed if the conditional is true -if the conditional is false, the conditional of the first elif-statement is evaluated and only executed if true -etc for any subsequent elif-statements -the block of code after the else-statement is only executed if all previous if- and elif-statements are false #So with all this information, here's the basic Rock, Paper, Scissors game rolled into a program RockPaperScissors.py (with header info and notes) ~~~~~ BEGIN RockPaperScissors.py ~~~~~ ## ######### ## Copyright (C) 2016 ## Written by Kathy Cooksey ## Spring 2016 ## for Kamehameha Coding Academy ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## To use this package, in a python or ipython session, compile: ## In [1]: import RockPaperScissors as rps ## ## Then run a function: ## In [2]: rps.go() ## ## If changes are made to this file (RockPaperScissors.py), re-compile: ## In [3]: reload(rps) ## ## Then re-run as in line [2] above. ## ## To see information about the functions (and this header): ## In [4]: help(rps) ## ## ######### ## Load required modules from random import random, seed def go(P_rock=0.33,P_paper=0.67,nseed=False): """ On `go' choose Rock, Paper, or Scissors (rock beats scissors, paper beats rock, and scissors beat paper) Probabilities: P = random() 0.0 <= P < P_rock --> Rock! P_rock <= P < P_paper --> Paper! P_paper <= P < 1.0 --> Scissors! """ if nseed: seed(nseed) # make deterministic else: seed() # reset prob = random() # draw random probability >= 0 and < 1 ## Determine which to "choose" to play if prob < P_rock: # 0. <= prob < P_rock play = 'Rock!' elif prob >= P_rock and prob < P_paper: # P_rock <= prob < P_paper play = 'Paper!' elif prob >= P_paper: # P_paper <= prob < 1 play = 'Scissors!' else: print('go(): probabilities do not span space; exiting') return ## Print answer to screen print('I choose '+play) ~~~~~ END RockPaperScissors.py ~~~~~ #I made variables for the limits of the probabilities (P_rock and P_paper) and used the else-statement to catch any mistakes --but this allows me to give more or less probability to Rock, Paper, and/or Scissors (in case I think it'll help me win!) #Next time we learn to plot so we can have the Rock, Paper, or Scissors hand-sign displayed to the screen instead of the dinky little print statement 11 Apr 2016 #We were to resume after a long hiatus (spring break) last Monday (4 Apr) but there was no student interest #Since there has been only one attendee for several previous sessions, Mrs. Correia has ceased the class until next fall #If there's any input on how to do this better, please let one of us know #I find the most difficult part to be that students don't practice in-between sessions (largely because only the library computers are set up with the requisite infrastructure) --it's a very inefficient way to learn anything #The coding topics I've selected don't seem to motivate students either --if they were more interesting, perhaps the students would find time to work on the library computers during the week --this is what I'll try to do better next time #--------------------------------------------------------------------------