Python Number Guesser

Last year, I gave a problem in JAVA to create a number guesser. The idea was that the computer would randomly select a number and the user had to guess the number the computer had picked. http://funmultiplies.com/semester-review-computer-science

This year, in Computer Science 1, we have done a similar assignment in Python. However, in this version, the user is selecting the number and the computer has to “guess” the number the user selected.

On the first day of this project, students had to first choose a solving strategy. The two best strategies were called Hi/Lo Average and Hi/Lo Random.

The idea with both of these is that we ask the user to pick an integer (whole number) between 1 and 100.

With Hi/Lo Average, we take the average of the highest and lowest numbers, in this case 100 and 1 and we get 49. So, our first guess will be 49. If that is too low, then we move the lowest value up from 1 to 48. If 49 was too high, then we would move the highest value down from 100 to 50. We then make our second guess by taking the average of the new highest and lowest numbers. We repeat this process until we get to the number the user selected. The key advantage to this process is that we are guaranteed to solve the problem in 7 or fewer questions.

With Hi/Lo Random, we move the highest and lowest numbers identically to how we did in Hi/Lo Average after each incorrect guess, but we don’t take the average – we just select a random number between the highest and lowest numbers. This can potentially solve the problem very quickly or take considerably longer than Hi/Lo Average since you are entirely dependent upon what integers are selected by a random number generator.

Here is what a possible Hi/Lo Average solution looks like:

#Programmer Name: Eric Evans, M.Ed.
#Program Name: Number Guesser (Hi/Lo Average)
#Program Description: Uses a Hi/Lo Average algorithm to determine the number chosen the user.
#Algorithm: Starts with hi/lo or 100/1. Calculates average of hi/lo. Adjusts hi/lo accordingly after guess. Repeat calculation of average between new hi/lo. Repeat hi/lo adjustment...
#
correct = "N"
#Creates a variable named "correct" and sets the initial value as N
high = 100
#Creates a variable named "high" and sets the initial value as 100
low = 1
#Creates a variable named "low" and sets the initial value as 1
guessCount = 1
#Creates a variable named "guessCount" and sets the initial value as 1
guess = (high + low) / 2
#Creates a variable named "guess" and sets the initial value as the average of high and low
while (correct == "N"):
#Starts a loop that runs as long as the variable "correct" has a value of "N".
  guess = int(guess)
  #Casts the value of the variable "guess" as an integer. This truncates any decimals.
  guessAsString = str(guess)
  #Creates a variable named "guessAsString" and sets the initial value as the value of the variable named "guess" as a string.
  print ("Is Your Number " + guessAsString + "?")
  #Outputs the current "guess" for the user to see.
  response = input("[C]orrect  /  Too [L]ow  /  Too [H]igh")
  #Creates a variable named "response" and sets the initial value as the input from the keyboard.
  if (response == "C"):
  #Start of a conditional statement if the keyboard input is "C".
    guessCountAsString = str(guessCount)
    #Creates a variable named "guessCountAsString" and sets the initial value as the value of the variable named "guessCount" as a string.
    print("Yay! I got it in " + guessCountAsString + " guesses!")
    #Outputs the line displayed when the correct number is guessed.
    correct = "Y"
    #Changes the value of the variable named "correct" to "Y".
  elif (response == "L"):
  #Start of a conditional statement if the keyboard input is "L".
    print ("Too Low Huh?")
    #Outputs an acknowledgement to the user of their input.
    low = guess + 1
    #Changes the value of the variable named "low" to the value of the current guess + 1.
    guess = (high + low) / 2
    #Changes the value of the variable named "guess" to the value of the average of high and low.
    guessCount = guessCount + 1
    #Changes the value of the variable named "guessCount" by adding 1 to its existing value.
  elif (response == "H"):
  #Start of a conditional statement if the keyboard inputs is "H".
    print ("Too High Huh?")
    #Outputs an acknowledgement to the user of their input.
    high = guess - 1
    #Changes the value of the variable named "high" to the value of the current guess - 1.
    guess = (high + low) / 2
    #Changes the value of the variable named "guess" to the value of the average of high and low.
    guessCount = guessCount + 1
    #Changes the value of the variable named "guessCount" by adding 1 to its existing value.
print ("Exiting Program")
#Outputs a message letting the user they are exiting the program.

At the time of the first writing, I omitted the Hi/Lo Random solution as I wanted to see if my students could identify a key weakness inherent in that strategy. Here is a possible Hi/Lo Random solution (I discuss the weakness below):

#Programmer Name: Eric Evans, M.Ed.
#Program Name: Number Guesser (Hi/Lo Random)
#Program Description: Uses a Hi/Lo Random algorithm to determine the number chosen the user.
#Algorithm: Starts with hi/lo or 100/1. Selects a random number between hi/lo. Adjusts hi/lo accordingly after guess. Repeat selection of a random number between new hi/lo. Repeat hi/lo adjustment...
#
import random
correct = "N"
high = 100
low = 1
guessCount = 1
guess = random.randint(low, high)
while (correct == "N"):
  guess = int(guess)
  guessAsString = str(guess)
  print ("Is Your Number " + guessAsString + "?")
  response = input("[C]orrect  /  Too [L]ow  /  Too [H]igh")
  if (response == "C"):
    guessCountAsString = str(guessCount)
    print("Yay! I got it in " + guessCountAsString + " guesses!")
    correct = "Y"
  elif (response == "L"):
    print ("Too Low Huh?")
    low = guess + 1
    guess = random.randint(low, high)
    guessCount = guessCount + 1
  elif (response == "H"):
    print ("Too High Huh?")
    high = guess - 1
    guess = random.randint(low, high)
    guessCount = guessCount + 1
print ("Exiting Program")

If you played the Hi/Lo Random version of the game, you realized that there is nothing in the program to prevent the computer from randomly guessing the same number multiple times. This would need to be addressed by using a data structure to store the guesses and compare them as each subsequent guess was being made.

In addition, the odds are not “favorable” with a Hi/Lo Random game when compared to a Hi/Lo Average game.

Let’s say that the user has selected the number 21 as their number. Now, let’s look at the odds through each run compared side-by-side. I am going to use the random number generator from Google to generate the guesses for this example:

Run # Hi/Lo Average Hi/Lo Random
Guess Odds Guess Odds
1 50 1:100 16 1:100
2 25 1:49 48 1:30
3 12 1:23 17 1:29
4 18 1:11 27 1:8
5 21 1:1 25 1:6
6 N/A N/A 21 1:1

As you can see, with Hi/Lo Random, you are completely at the mercy of the numbers that are randomly generated whereas with Hi/Lo Average, you are guaranteed that your odds are twice as good after each guess.

Grade Calculator Programming – Day 1

Today, we started development of the minimum grade calculator in Computer Science 1.

#Programmer Name: Eric Evans, M.Ed.
#Program Name: Grade Calculator
#Program Description: Provides a minimum grade needed to get a C, B, or A in a given course for the semester and for the year.
#
print ("*********************************************************")
print ("** Welcome to the Grade Calculator                     **")
print ("**                                                     **")
print ("** You will need the following information to proceed: **")
print ("** - Fall Semester (S1) Grade                          **")
print ("** - 3rd Quarter (Q3) Grade                            **")
print ("**                                                     **")
print ("*********************************************************")
print ("")

Here, we started with our generic header and then a welcome screen that lets the user know what to expect and what they will need to proceed.

minC = 68.5
#Minimum average grade for "C" per Ferris ISD
minB = 79.5
#Minimum average grade for "B" per Ferris ISD 
minA = 89.5
#Minimum average grade for "A" per Ferris ISD

Here, are establishing the minimum graded needed to pass (minC), and get a B (minB) and an A (minA) according to our current grading guidelines.

s1 = float(input("What is your Fall Semester (S1) Grade? "))
#Ask for S1 input and cast as float
q3 = float(input("What is your 3rd Quarter (Q3) Grade? "))
#Ask for Q3 input and cast as float

Here, we are creating a variable named s1, which is going to hold the data entered by the user for their fall semester grade. We then create a variable named q3which is going to hold the data entered by the user for their 3rd quarter grade.

semMinC = ( ( ( 5 * minC ) - ( q3 * 2 ) ) / 3 )
#C Algorithm - Developed on 19-March-2018
semMinB = ( ( ( 5 * minB ) - ( q3 * 2 ) ) / 3 )
#B Algorithm - Developed on 19-March-2018
semMinA = ( ( ( 5 * minA ) - ( q3 * 2 ) ) / 3 )
#A Algorithm - Developed on 19-March-2018

Here is where we get to use the algorithm that was developed in the previous class ( Grade Calculator Algorithm Development ).

You will notice that it is being used 3 different times. Each case is separate to address the 3 different grade breaks (68.5, 79.5, and 89.5).

semMinCRounded = round(semMinC,2)
#Rounds minimum "C" output to 2 decimal points
semMinBRounded = round(semMinB,2)
#Rounds minimum "B" output to 2 decimal points
semMinARounded = round(semMinA,2)
#Rounds minimum "A" output to 2 decimal points

Here, we take the solution for each case and then round it to 2 decimal points.

semMinCString = str(semMinCRounded)
#Casts minimum "C" output as string
semMinBString = str(semMinBRounded)
#Casts minimum "B" output as string
semMinAString = str(semMinARounded)
#Casts minimum "A" output as string

Here, we are casting the rounded output as a string so we can use it in our output.

print("")
print("***********Q4 & SE2 MINIMUMS (SEMESTER)***********")
print("Min for C for Semester = " + semMinCString)
#Outputs minimum for "C" for semester
print("Min for B for Semester = " + semMinBString)
#Outputs minimum for "B" for semester
print("Min for A for Semester = " + semMinAString)
#Outputs minimum for "A" for semester

Here we finally provide our output for the use to see.

This code is deliberately broken-up so the students can see and manipulate the various components. (e.g., lines 24, 30, and 36).

Here is a consolidated version of the code that combines multiple steps:

#Programmer Name: Eric Evans, M.Ed.
#Program Name: Grade Calculator
#Program Description: Provides a minimum Grade
#
print ("*********************************************************")
print ("** Welcome to the Grade Calculator                     **")
print ("**                                                     **")
print ("** You will need the following information to proceed: **")
print ("** - Fall Semester (S1) Grade                          **")
print ("** - 3rd Quarter (Q3) Grade                            **")
print ("**                                                     **")
print ("*********************************************************")
print("")
minC = 68.5
#Minimum average grade for "C" per Ferris ISD
minB = 79.5
#Minimum average grade for "B" per Ferris ISD 
minA = 89.5
#Minimum average grade for "A" per Ferris ISD
s1 = float(input("What is your Fall Semester (S1) Grade? "))
#Ask for S1 input and cast as float
q3 = float(input("What is your 3rd Quarter (Q3) Grade? "))
#Ask for Q3 input and cast as float
semMinC = str ( round ( ( ( ( 5 * minC ) - ( q3 * 2 ) ) / 3 ), 2) )
#C Algorithm - Developed on 19-March-2018 rounded to 2 decimal places and cast as a string
semMinB = str ( round ( ( ( ( 5 * minB ) - ( q3 * 2 ) ) / 3 ), 2) )
#B Algorithm - Developed on 19-March-2018 rounded to 2 decimal places and cast as a string
semMinA = str ( round ( ( ( ( 5 * minA ) - ( q3 * 2 ) ) / 3 ), 2) )
#A Algorithm - Developed on 19-March-2018 rounded to 2 decimal places and cast as a string
print("")
print("***********Q4 & SE2 MINIMUMS (SEMESTER)***********")
print("Min for C for Semester = " + semMinC)
#Outputs minimum for "C" for semester
print("Min for B for Semester = " + semMinB)
#Outputs minimum for "B" for semester
print("Min for A for Semester = " + semMinA)
#Outputs minimum for "A" for semester

You can see that lines 24 through 29 are compressed versions of lines 24 through 41 of the original code. Let’s take a quick look at how this was accomplished:

semMinC = str ( round ( ( ( ( 5 * minC ) - ( q3 * 2 ) ) / 3 ), 2) )

Here is line 24 of the compressed version. You can see that we have a math problem in the middle that is rounded to 2 decimal points that is cast as a string.

The original (expanded) code took the following lines to accomplish the same thing:

semMinC = ( ( ( 5 * minC ) - ( q3 * 2 ) ) / 3 )
semMinCRounded = round(semMinC,2)
semMinCString = str(semMinCRounded)

When we return next class, the students will be developing the second part of the program, which addresses the minimums needed for the 3 cases for the year.

For reference, here is a link to the IDE of the code at this checkpoint:

Coding Bat Logic Problems – Day 2

Last class we looked at the first of 4 logic problems on Coding Bat in Computer Science 1 ( http://funmultiplies.com/coding-bat-logic-problems-day-1 ). We’re now looking at the last 4 logic problems of that Coding Bat set in CS1 as we get ready to depart for Spring Break.

alarm clock

http://codingbat.com/prob/p119867

Here is the setup of this problem:

Given a day of the week encoded as 0=Sun, 1=Mon, 2=Tue, …6=Sat, and a boolean indicating if we are on vacation, return a string of the form “7:00” indicating when the alarm clock should ring. Weekdays, the alarm should be “7:00” and on the weekend it should be “10:00”. Unless we are on vacation — then on weekdays it should be “10:00” and weekends it should be “off”.

def alarm_clock(day, vacation):
  if (day == 0 or day == 6) and vacation == True:
    return "off"
  elif (day == 0 or day == 6) and vacation == False:
    return "10:00"
  elif (day == 1 or day == 2 or day == 3 or day == 4 or day == 5) and vacation == False:
    return "7:00"
  else:
    return "10:00"

This one is not hard, but just involved with conditional statements. The major things to keep an eye out for are the spelling of the return “off” is all lower-case and the week starts on day 0 with Sunday.

love 6

http://codingbat.com/prob/p100958

Here is the setup for this problem:

The number 6 is a truly great number. Given two int values, a and b, return True if either one is 6. Or if their sum or difference is 6. Note: the function abs(num) computes the absolute value of a number.

def love6(a, b):
  if (a) == 6 or (b) == 6:
    return True
  elif (a) + (b) == 6 or (b) + (a) == 6:
    return True
  elif (a) - (b) == 6 or (b) - (a) == 6:
    return True
  else:
    return False

I personally do not like this problem because of the “Note” at the end. It throws many programmers off. Yes, you can solve this using absolute values, but it’s not necessary.

Once you get other that “distractor”, this is a simple conditional logic problem.

In 1 to 10

http://codingbat.com/prob/p158497

Here is the setup for this problem:

Given a number n, return True if n is in the range 1..10, inclusive. Unless outside_mode is True, in which case return True if the number is less or equal to 1, or greater or equal to 10.

def in1to10(n, outside_mode):
  if outside_mode == False and (n >= 1 and n <= 10):
    return True
  elif outside_mode == True and (n <= 1 or n >= 10):
    return True
  else:
    return False

This is a pretty simple conditional logic problem. If the Boolean flag is False, we are looking for numbers between 1 and 10 (inclusive) and if the Boolean flag is True, we are looking for numbers outside of 1 and 10 (inclusive).

On this particular question, I awarded extra credit if my students could explain mathematically why when the outside_mode Boolean flag is True, the Boolean operator must be OR.

The reason is that while the Boolean flag is False, num is to be between 1 and 10 inclusive. A number can be simultaneously between 1 and 10. As such, the Boolean AND is used in this statement.

Conversely, when the Boolean flag is True, num is to be outside of 1 and 10 inclusive. A number CANNOT be simultaneously less than 1 and greater than 10. As such, the Boolean OR is needed for this statement.

near ten

http://codingbat.com/prob/p165321

Here is the setup for this problem:

Given a non-negative number “num”, return True if num is within 2 of a multiple of 10. Note: (a % b) is the remainder of dividing a by b, so (7 % 5) is 2.

def near_ten(num):
  if num % 10 == 0 or num % 10 == 1 or num % 10 == 2 or num % 10 == 8 or num % 10 == 9:
    return True
  else:
    return False

This particular one needs a little bit of explanation on the algorithm that was used. The general concept is pretty straightforward, but the formula may not be.

Here, we are looking at the modulus of num by 10. In this case, that will always return a 0, 1, or 2 if the number is a multiple of 10, or 1 greater than a multiple of 10, or 2 greater than a multiple of 10 respectively.

On the other side, we will always return an 8 or 9 if the number is 2 less than a multiple of 10, or 1 less than a multiple of 10 respectively.

Beyond the algorithm, the problem is a simple logic conditional program.

Finishing the Matrix

Today, we finished the assignment over a matrix (2-dimensional array) in Python by calculating the ranking points for the teams in the FIRST Tech Challenge El Dorado League of North Texas for the 2017/2018 season.

As you may recall from the previous post titled “Continuing the Matrix“, when there is a tie in the qualifying points, the 3 highest ranking points for each team are summed together to break the tie. The team with the higher sum wins the tie-break.

I am going to remove lines 147 to 157 from last class, which was a test print and am going to replace them with the following to calculate the sum of the 3 highest ranking points.

teams[0][13] = (teams[0][5] + teams[0][7] + teams[0][9] + teams[0][11]) - min(teams[0][5], teams[0][7], teams[0][9], teams[0][11])
teams[1][13] = (teams[1][5] + teams[1][7] + teams[1][9] + teams[1][11]) - min(teams[1][5], teams[1][7], teams[1][9], teams[1][11])
teams[2][13] = (teams[2][5] + teams[2][7] + teams[2][9] + teams[2][11]) - min(teams[2][5], teams[2][7], teams[2][9], teams[2][11])
teams[3][13] = (teams[3][5] + teams[3][7] + teams[3][9] + teams[3][11]) - min(teams[3][5], teams[3][7], teams[3][9], teams[3][11])
teams[4][13] = (teams[4][5] + teams[4][7] + teams[4][9] + teams[4][11]) - min(teams[4][5], teams[4][7], teams[4][9], teams[4][11])
teams[5][13] = (teams[5][5] + teams[5][7] + teams[5][9] + teams[5][11]) - min(teams[5][5], teams[5][7], teams[5][9], teams[5][11])
teams[6][13] = (teams[6][5] + teams[6][7] + teams[6][9] + teams[6][11]) - min(teams[6][5], teams[6][7], teams[6][9], teams[6][11])
teams[7][13] = (teams[7][5] + teams[7][7] + teams[7][9] + teams[7][11]) - min(teams[7][5], teams[7][7], teams[7][9], teams[7][11])
teams[8][13] = (teams[8][5] + teams[8][7] + teams[8][9] + teams[8][11]) - min(teams[8][5], teams[8][7], teams[8][9], teams[8][11])
teams[9][13] = (teams[9][5] + teams[9][7] + teams[9][9] + teams[9][11]) - min(teams[9][5], teams[9][7], teams[9][9], teams[9][11])
teams[10][13] = (teams[10][5] + teams[10][7] + teams[10][9] + teams[10][11]) - min(teams[10][5], teams[10][7], teams[10][9], teams[10][11])

Let’s take a look at what we have going on here by just taking a look at the first line in this code segment:

teams[0][13] = (teams[0][5] + teams[0][7] + teams[0][9] + teams[0][11]) - min(teams[0][5], teams[0][7], teams[0][9], teams[0][11])

As you can see, we start by saying that we are going to populate column with 13 with some data. That data is the value of columns 5, 7, 9, & 11 added together and then the smallest of those values subtracted from that sum.

Remember, only the top 3 scores are used in the calculation and it we add the 4 scores together and then subtract the smallest (min) from that total, we get the data we need.

We now need to display our data.

print(teams[0][0] + " - " + teams[0][1] + " - " + str(teams[0][12]) + " (" + str(teams[0][13]) + ")")
print(teams[1][0] + " - " + teams[1][1]  + " - " + str(teams[1][12]) + " (" + str(teams[1][13]) + ")")
print(teams[2][0] + " - " + teams[2][1]  + " - " + str(teams[2][12]) + " (" + str(teams[2][13]) + ")")
print(teams[3][0] + " - " + teams[3][1]  + " - " + str(teams[3][12]) + " (" + str(teams[3][13]) + ")")
print(teams[4][0] + " - " + teams[4][1]  + " - " + str(teams[4][12]) + " (" + str(teams[4][13]) + ")")
print(teams[5][0] + " - " + teams[5][1]  + " - " + str(teams[5][12]) + " (" + str(teams[5][13]) + ")")
print(teams[6][0] + " - " + teams[6][1]  + " - " + str(teams[6][12]) + " (" + str(teams[6][13]) + ")")
print(teams[7][0] + " - " + teams[7][1]  + " - " + str(teams[7][12]) + " (" + str(teams[7][13]) + ")")
print(teams[8][0] + " - " + teams[8][1]  + " - " + str(teams[8][12]) + " (" + str(teams[8][13]) + ")")
print(teams[9][0] + " - " + teams[9][1]  + " - " + str(teams[9][12]) + " (" + str(teams[9][13]) + ")")
print(teams[10][0] + " - " + teams[10][1]  + " - " + str(teams[10][12]) + " (" + str(teams[10][13]) + ")")

Let’s take a look at what we have going on here by just taking a look at the first line in this code segment:

print(teams[0][0] + " - " + teams[0][1] + " - " + str(teams[0][12]) + " (" + str(teams[0][13]) + ")")

Here, we are displaying a concatenation of the team number from column 0, with a space/hyphen/space, with the team name from column 1, with a space/hyphen/space, with the sum of the qualifying points for the team from column 12, with a space, with the sum of the three highest ranking points in parenthesis from column 13.

The output should look like the following:

Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux

127 - The Fighting Pickles - 23 (867)
5443 - Synergy - 18 (737)
9402 - Hive of Steel - 15 (739)
9403 - CyberSwarm - 29 (932)
10143 - Bits & Bots - 14 (763)
11085 - Mad Hackers - 16 (718)
11242 - ERROR 451 - 28 (812)
12645 - S.C.R.E.W. Ups - 19 (874)
12650 - Cannot Compute - 12 (673)
12992 - Vindicators - 6 (316)
13915 - Eagles Robotics - 14 (407)

Following is a complete overview of the code that was created over the 3 days of this lesson:

w = 14 #Width of matrix
h = 11 #Height of matrix
teams = [[0 for x in range(w)] for y in range(h)]
teams[0][0] = "127"
teams[1][0] = "5443"
teams[2][0] = "9402"
teams[3][0] = "9403"
teams[4][0] = "10143"
teams[5][0] = "11085"
teams[6][0] = "11242"
teams[7][0] = "12645"
teams[8][0] = "12650"
teams[9][0] = "12992"
teams[10][0] = "13915"
teams[0][1] = "The Fighting Pickles"
teams[1][1] = "Synergy"
teams[2][1] = "Hive of Steel"
teams[3][1] = "CyberSwarm"
teams[4][1] = "Bits & Bots"
teams[5][1] = "Mad Hackers"
teams[6][1] = "ERROR 451"
teams[7][1] = "S.C.R.E.W. Ups"
teams[8][1] = "Cannot Compute"
teams[9][1] = "Vindicators"
teams[10][1] = "Eagles Robotics"
teams[0][2] = "Ben Barber Innovation Academy"
teams[1][2] = "Harmony School of Innovation"
teams[2][2] = "Henderson Junior High School"
teams[3][2] = "Henderson Junior High School"
teams[4][2] = "Harmony School of Innovation"
teams[5][2] = "Mansfield High School"
teams[6][2] = "Ferris High School"
teams[7][2] = "Ferris High School"
teams[8][2] = "Ferris Junior High School"
teams[9][2] = "Italy High School"
teams[10][2] = "Faith Family Academy"
teams[0][3] = "Mansfield, TX"
teams[1][3] = "Ft. Worth, TX"
teams[2][3] = "Stephenville, TX"
teams[3][3] = "Stephenville, TX"
teams[4][3] = "Ft. Worth, TX"
teams[5][3] = "Mansfield, TX"
teams[6][3] = "Ferris, TX"
teams[7][3] = "Ferris, TX"
teams[8][3] = "Ferris, TX"
teams[9][3] = "Italy, TX"
teams[10][3] = "Waxahachie, TX"
teams[0][4] = 6
teams[1][4] = 0
teams[2][4] = 2
teams[3][4] = 6
teams[4][4] = 6
teams[5][4] = 4
teams[6][4] = 10
teams[7][4] = 6
teams[8][4] = 6
teams[9][4] = 4
teams[10][4] = 0
teams[0][5] = 210
teams[1][5] = 105
teams[2][5] = 132
teams[3][5] = 183
teams[4][5] = 212
teams[5][5] = 184
teams[6][5] = 220
teams[7][5] = 156
teams[8][5] = 160
teams[9][5] = 164
teams[10][5] = 0
teams[0][6] = 6
teams[1][6] = 4
teams[2][6] = 4
teams[3][6] = 10
teams[4][6] = 2
teams[5][6] = 0
teams[6][6] = 6
teams[7][6] = 4
teams[8][6] = 4
teams[9][6] = 0
teams[10][6] = 0
teams[0][7] = 257
teams[1][7] = 257
teams[2][7] = 220
teams[3][7] = 314
teams[4][7] = 205
teams[5][7] = 0
teams[6][7] = 238
teams[7][7] = 277
teams[8][7] = 224
teams[9][7] = 0
teams[10][7] = 0
teams[0][8] = 6
teams[1][8] = 6
teams[2][8] = 6
teams[3][8] = 6
teams[4][8] = 4
teams[5][8] = 6
teams[6][8] = 6
teams[7][8] = 6
teams[8][8] = 0
teams[9][8] = 2
teams[10][8] = 6
teams[0][9] = 188
teams[1][9] = 168
teams[2][9] = 156
teams[3][9] = 218
teams[4][9] = 160
teams[5][9] = 202
teams[6][9] = 244
teams[7][9] = 184
teams[8][9] = 156
teams[9][9] = 152
teams[10][9] = 140
teams[0][10] = 5
teams[1][10] = 8
teams[2][10] = 3
teams[3][10] = 7
teams[4][10] = 2
teams[5][10] = 6
teams[6][10] = 6
teams[7][10] = 3
teams[8][10] = 2
teams[9][10] = 0
teams[10][10] = 8
teams[0][11] = 400
teams[1][11] = 312
teams[2][11] = 363
teams[3][11] = 400
teams[4][11] = 346
teams[5][11] = 332
teams[6][11] = 330
teams[7][11] = 413
teams[8][11] = 289
teams[9][11] = 0
teams[10][11] = 267
teams[0][12] = teams[0][4] + teams[0][6] + teams[0][8] + teams [0][10]
teams[1][12] = teams[1][4] + teams[1][6] + teams[1][8] + teams [1][10]
teams[2][12] = teams[2][4] + teams[2][6] + teams[2][8] + teams [2][10]
teams[3][12] = teams[3][4] + teams[3][6] + teams[3][8] + teams [3][10]
teams[4][12] = teams[4][4] + teams[4][6] + teams[4][8] + teams [4][10]
teams[5][12] = teams[5][4] + teams[5][6] + teams[5][8] + teams [5][10]
teams[6][12] = teams[6][4] + teams[6][6] + teams[6][8] + teams [6][10]
teams[7][12] = teams[7][4] + teams[7][6] + teams[7][8] + teams [7][10]
teams[8][12] = teams[8][4] + teams[8][6] + teams[8][8] + teams [8][10]
teams[9][12] = teams[9][4] + teams[9][6] + teams[9][8] + teams [9][10]
teams[10][12] = teams[10][4] + teams[10][6] + teams[10][8] + teams [10][10]
teams[0][13] = (teams[0][5] + teams[0][7] + teams[0][9] + teams[0][11]) - min(teams[0][5], teams[0][7], teams[0][9], teams[0][11])
teams[1][13] = (teams[1][5] + teams[1][7] + teams[1][9] + teams[1][11]) - min(teams[1][5], teams[1][7], teams[1][9], teams[1][11])
teams[2][13] = (teams[2][5] + teams[2][7] + teams[2][9] + teams[2][11]) - min(teams[2][5], teams[2][7], teams[2][9], teams[2][11])
teams[3][13] = (teams[3][5] + teams[3][7] + teams[3][9] + teams[3][11]) - min(teams[3][5], teams[3][7], teams[3][9], teams[3][11])
teams[4][13] = (teams[4][5] + teams[4][7] + teams[4][9] + teams[4][11]) - min(teams[4][5], teams[4][7], teams[4][9], teams[4][11])
teams[5][13] = (teams[5][5] + teams[5][7] + teams[5][9] + teams[5][11]) - min(teams[5][5], teams[5][7], teams[5][9], teams[5][11])
teams[6][13] = (teams[6][5] + teams[6][7] + teams[6][9] + teams[6][11]) - min(teams[6][5], teams[6][7], teams[6][9], teams[6][11])
teams[7][13] = (teams[7][5] + teams[7][7] + teams[7][9] + teams[7][11]) - min(teams[7][5], teams[7][7], teams[7][9], teams[7][11])
teams[8][13] = (teams[8][5] + teams[8][7] + teams[8][9] + teams[8][11]) - min(teams[8][5], teams[8][7], teams[8][9], teams[8][11])
teams[9][13] = (teams[9][5] + teams[9][7] + teams[9][9] + teams[9][11]) - min(teams[9][5], teams[9][7], teams[9][9], teams[9][11])
teams[10][13] = (teams[10][5] + teams[10][7] + teams[10][9] + teams[10][11]) - min(teams[10][5], teams[10][7], teams[10][9], teams[10][11])
print(teams[0][0] + " - " + teams[0][1] + " - " + str(teams[0][12]) + " (" + str(teams[0][13]) + ")")
print(teams[1][0] + " - " + teams[1][1]  + " - " + str(teams[1][12]) + " (" + str(teams[1][13]) + ")")
print(teams[2][0] + " - " + teams[2][1]  + " - " + str(teams[2][12]) + " (" + str(teams[2][13]) + ")")
print(teams[3][0] + " - " + teams[3][1]  + " - " + str(teams[3][12]) + " (" + str(teams[3][13]) + ")")
print(teams[4][0] + " - " + teams[4][1]  + " - " + str(teams[4][12]) + " (" + str(teams[4][13]) + ")")
print(teams[5][0] + " - " + teams[5][1]  + " - " + str(teams[5][12]) + " (" + str(teams[5][13]) + ")")
print(teams[6][0] + " - " + teams[6][1]  + " - " + str(teams[6][12]) + " (" + str(teams[6][13]) + ")")
print(teams[7][0] + " - " + teams[7][1]  + " - " + str(teams[7][12]) + " (" + str(teams[7][13]) + ")")
print(teams[8][0] + " - " + teams[8][1]  + " - " + str(teams[8][12]) + " (" + str(teams[8][13]) + ")")
print(teams[9][0] + " - " + teams[9][1]  + " - " + str(teams[9][12]) + " (" + str(teams[9][13]) + ")")
print(teams[10][0] + " - " + teams[10][1]  + " - " + str(teams[10][12]) + " (" + str(teams[10][13]) + ")")

 

Continuing the Matrix

Today, we continued the matrix (2-dimensional array) in Python in Computer Science 1. We added an additional 88 data points to the existing 44 we started with. This brings the total number of points to 132.

See the post entitled “Starting a Matrix in Python” for the first part of the program code.

Now, we are going to remove lines 48 through 58 of the code to continue entering data.

teams[0][4] = 6
teams[1][4] = 0
teams[2][4] = 2
teams[3][4] = 6
teams[4][4] = 6
teams[5][4] = 4
teams[6][4] = 10
teams[7][4] = 6
teams[8][4] = 6
teams[9][4] = 4
teams[10][4] = 0
teams[0][5] = 210
teams[1][5] = 105
teams[2][5] = 132
teams[3][5] = 183
teams[4][5] = 212
teams[5][5] = 184
teams[6][5] = 220
teams[7][5] = 156
teams[8][5] = 160
teams[9][5] = 164
teams[10][5] = 0

Here, we are adding the scores for each team from the first league meet of the 2017/2018 season as new columns 4 and 5 to the array. You can see these are being entered as integers as we will be doing some math with them later.

teams[0][6] = 6
teams[1][6] = 4
teams[2][6] = 4
teams[3][6] = 10
teams[4][6] = 2
teams[5][6] = 0
teams[6][6] = 6
teams[7][6] = 4
teams[8][6] = 4
teams[9][6] = 0
teams[10][6] = 0
teams[0][7] = 257
teams[1][7] = 257
teams[2][7] = 220
teams[3][7] = 314
teams[4][7] = 205
teams[5][7] = 0
teams[6][7] = 238
teams[7][7] = 277
teams[8][7] = 224
teams[9][7] = 0
teams[10][7] = 0

We are now adding the scores from each team from the second league meet of the 2017/2018 season as new columns 6 and 7 to the array.

teams[0][8] = 6
teams[1][8] = 6
teams[2][8] = 6
teams[3][8] = 6
teams[4][8] = 4
teams[5][8] = 6
teams[6][8] = 6
teams[7][8] = 6
teams[8][8] = 0
teams[9][8] = 2
teams[10][8] = 6
teams[0][9] = 188
teams[1][9] = 168
teams[2][9] = 156
teams[3][9] = 218
teams[4][9] = 160
teams[5][9] = 202
teams[6][9] = 244
teams[7][9] = 184
teams[8][9] = 156
teams[9][9] = 152
teams[10][9] = 140

We are now adding the scores from each teams from the third league meet of the 2017/2018 season as new columns 8 and 9 to the array.

teams[0][10] = 5
teams[1][10] = 8
teams[2][10] = 3
teams[3][10] = 7
teams[4][10] = 2
teams[5][10] = 6
teams[6][10] = 6
teams[7][10] = 3
teams[8][10] = 2
teams[9][10] = 0
teams[10][10] = 8
teams[0][11] = 400
teams[1][11] = 312
teams[2][11] = 363
teams[3][11] = 400
teams[4][11] = 346
teams[5][11] = 332
teams[6][11] = 330
teams[7][11] = 413
teams[8][11] = 289
teams[9][11] = 0
teams[10][11] = 267

We now add the results from the league tournament final qualifying rounds of the 2017/2018 season as new columns 10 and 11 to the array.

Now, what we need to do is calculate the total qualifying points, which determines placement. This is done by calculating the sum of all qualifying points for each team individually. This was stored in columns 4, 6, 8, & 10 in the array.

In the event of a tie in the qualifying points, we take the sum of the 3 highest ranking points scores for each team. The team with the higher ranking points wins the tie-break. The ranking points are stored in columns 5, 7, 9, & 11 in the array.

Calculating the qualifying points for each team is somewhat easy and can be done using simple arithmetic functions.

teams[0][12] = teams[0][4] + teams[0][6] + teams[0][8] + teams [0][10]
teams[1][12] = teams[1][4] + teams[1][6] + teams[1][8] + teams [1][10]
teams[2][12] = teams[2][4] + teams[2][6] + teams[2][8] + teams [2][10]
teams[3][12] = teams[3][4] + teams[3][6] + teams[3][8] + teams [3][10]
teams[4][12] = teams[4][4] + teams[4][6] + teams[4][8] + teams [4][10]
teams[5][12] = teams[5][4] + teams[5][6] + teams[5][8] + teams [5][10]
teams[6][12] = teams[6][4] + teams[6][6] + teams[6][8] + teams [6][10]
teams[7][12] = teams[7][4] + teams[7][6] + teams[7][8] + teams [7][10]
teams[8][12] = teams[8][4] + teams[8][6] + teams[8][8] + teams [8][10]
teams[9][12] = teams[9][4] + teams[9][6] + teams[9][8] + teams [9][10]
teams[10][12] = teams[10][4] + teams[10][6] + teams[10][8] + teams [10][10]

As you can see, we have added column 12 to the array and it holds the sum of columns 4, 6, 8, & 10 for the given row. This is the total qualifying points.

We can add a “test-print” using the following:

print(teams[0][0] + " - " + str(teams[0][12]))
print(teams[1][0] + " - " + str(teams[1][12]))
print(teams[2][0] + " - " + str(teams[2][12]))
print(teams[3][0] + " - " + str(teams[3][12]))
print(teams[4][0] + " - " + str(teams[4][12]))
print(teams[5][0] + " - " + str(teams[5][12]))
print(teams[6][0] + " - " + str(teams[6][12]))
print(teams[7][0] + " - " + str(teams[7][12]))
print(teams[8][0] + " - " + str(teams[8][12]))
print(teams[9][0] + " - " + str(teams[9][12]))
print(teams[10][0] + " - " + str(teams[10][12]))

You can see that we are displaying the team number from column 0, concatenated with a space a hyphen and space, which is then concatenated with the values from column 12 cast as a string.

The output looks similar to the following:

Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux

127 - 23
5443 - 18
9402 - 15
9403 - 29
10143 - 14
11085 - 16
11242 - 28
12645 - 19
12650 - 12
12992 - 6
13915 - 14

Next class, we will take a look at how to calculate the tie-breaker. As you can see, it will be needed as there is a tie between FTC 10143 and FTC 13915.

Starting a Matrix in Python

I started working with a 2-dimensional array in Python with my students today. We first covered a basic table on paper with the letters of the alphabet populating the cells so they could read index coordinates.

We then moved to the problem. On the first day of this assignment, we worked to create an 11 X 4 table that holds information of the teams that formed the FIRST Tech Challenge El Dorado League of North Texas for the 2017/2018 Relic Recovery season.

26-February-2018 – Matrix Day 1 Data – Sheet1

This is a visual representation of the data we worked with today.

w = 4
h = 11
teams = [[0 for x in range(w)] for y in range(h)]

Here, we declared an integer variable named “w” and another named “h” and assigned the values 4 and 11 respectively. This represents the width and height of the array we are building.

On line 3, we create the array named teams and using a nested for loop, create the array that is 4 columns wide and 11 rows tall. The table is currently populated with zeros.

teams[0][0] = "127"
teams[1][0] = "5443"
teams[2][0] = "9402"
teams[3][0] = "9403"
teams[4][0] = "10143"
teams[5][0] = "11085"
teams[6][0] = "11242"
teams[7][0] = "12645"
teams[8][0] = "12650"
teams[9][0] = "12992"
teams[10][0] = "13915"

These lines are populating column 0 (first column) of the array with the team numbers of the 11 different FTC teams in the league. Please note that it only goes up to 10 since we start counting at 0.

teams[0][1] = "The Fighting Pickles"
teams[1][1] = "Synergy"
teams[2][1] = "Hive of Steel"
teams[3][1] = "CyberSwarm"
teams[4][1] = "Bit & Bots"
teams[5][1] = "Mad Hackers"
teams[6][1] = "ERROR 451"
teams[7][1] = "S.C.R.E.W. Ups"
teams[8][1] = "Cannot Compute"
teams[9][1] = "Vindicators"
teams[10][1] = "Eagles Robotics"

These lines are populating column 1 (second column) of the array with the team names.

teams[0][2] = "Ben Barber Innovation Academy"
teams[1][2] = "Harmony School of Innovation"
teams[2][2] = "Henderson Junior High School"
teams[3][2] = "Henderson Junior High School"
teams[4][2] = "Harmony School of Innovation"
teams[5][2] = "Mansfield High School"
teams[6][2] = "Ferris High School"
teams[7][2] = "Ferris High School"
teams[8][2] = "Ferris Junior High School"
teams[9][2] = "Italy High School"
teams[10}[2] = "Faith Family Academy"

These lines are populating column 2 (third column) of the array with the schools each team represents.

teams[0][3] = "Mansfield, TX"
teams[1][3] = "Ft. Worth, TX"
teams[2][3] = "Stephenville, TX"
teams[3][3] = "Stephenville, TX"
teams[4][3] = "Ft. Worth, TX"
teams[5][3] = "Mansfield, TX"
teams[6][3] = "Ferris, TX"
teams[7][3] = "Ferris, TX"
teams[8][3] = "Ferris, TX"
teams[9][3] = "Italy, TX"
teams[10][3] = "Waxahachie, TX"

These lines are populating column 3 (fourth column) of the array with the hometowns of each team.

print(teams[0])
print(teams[1])
print(teams[2])
print(teams[3])
print(teams[4])
print(teams[5])
print(teams[6])
print(teams[7])
print(teams[8])
print(teams[9])
print(teams[10])

These lines will print each of the 11 rows on a separate line. There is no formatting, so the output will look similar to the following:

Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
['127', 'The Fighting Pickles', 'Ben Barber Innovation Academy', 'Mansfield, TX']
['5443', 'Synergy', 'Harmony School of Innovation', 'Ft. Worth, TX']
['9402', 'Hive of Steel', 'Henderson Junior High School', 'Stephenville, TX']
['9403', 'CyberSwarm', 'Henderson Junior High School', 'Stephenville, TX']
['10143', 'Bits & Bots', 'Harmony School of Innovation', 'Ft. Worth, TX']
['11085', 'Mad Hackers', 'Mansfield High School', 'Mansfield, TX']
['11242', 'ERROR 451', 'Ferris High School', 'Ferris, TX']
['12645', 'S.C.R.E.W. Ups', 'Ferris High School', 'Ferris, TX']
['12650', 'Cannot Compute', 'Ferris Junior High School', 'Ferris, TX']
['12992', 'Vindicators', 'Italy High School', 'Italy, TX']
['13915', 'Eagles Robotics', 'Faith Family Academy', 'Waxahachie, TX']

In the next class, we’ll discuss how to display an individual index and use concatenation to format a better output. We’ll then move into adding additional data to the existing array for each team that will involve basic math.

Deques of Python Stories

I was introducing deques in my Computer Science 1 class today in Python and decided to tell a story around the lesson. I figured I would share as this seemed to sink-in with my classes.

Zara loves Computer Science and using technology. She is hosting a party with several of her friends and wants to have their names displayed on the screen in the order they arrived and then remove them when they depart.

The friends of Zara are:

  • Alice
  • Betty
  • Christy
  • Darla
  • Elizabeth
  • Fran
  • Ginger
  • Holly

Alice, Betty and Christy arrive at the party at the same time and enter in that order.

from collections import deque
myGuestList = deque(["Alice", "Betty", "Christy"])
print(myGuestList)

At this point, we have 3 guests at the party: Alice in index 0, Betty in index 1, and Christy in index 2.

Darla and Elizabeth arrive at the party at the same time and enter in that order.

myGuestList.append("Darla")
myGuestList.append("Elizabeth")
print(myGuestList)

We now have 5 guests at the party: Alice in index 0, Betty in index 1, Christy in index 2, Darla in index 3, and Elizabeth in index 4.

Alice and Betty H-A-T-E Elizabeth. Almost instantly upon seeing her name on the screen, they both leave the party.

myGuestList.popleft()
myGuestList.popleft()
print(myGuestList)

We now have 3 guests at the party: Christy has now moved to index 0, Darla has moved to index 1, and Elizabeth has moved to index 2.

Ginger and Holly arrive at the party at the same time and enter in that order.

myGuestList.append("Ginger")
myGuestList.append("Holly")
print(myGuestList)

We now have 5 guests at the party: Christy is in index 0, Darla is in index 1, Elizabeth is in index 2, Ginger is in index 3, and Holly is in index 4.

Regretfully, Holly had been to another party before coming to Zara’s party and gets sick when she gets inside and has to leave.

myGuestList.pop()
print(myGuestList)

We now have 4 guests at the party: Christy is in index 0, Darla is in index 1, Elizabeth is in index 2, and Ginger is in index 3.

Elizabeth is Holly’s sister and leaves to take care of her sister and possibly ridicule her for her choice of the day.

del myGuestList[2]
print(myGuestList)

We now have 3 guests at the party: Christy is in index 0, Darla is in index 1, and Ginger who has moved to index 2.

Zara realizes that while the computer shows 3 guests at the party, there are 4 guests there. Somehow, Fran came in right after Elizabeth and did not get entered into the computer during the “drama” between Alice and Betty with Elizabeth. Fran needs to be entered into the correct location.

myGuestList.insert(2,"Fran")
print(myGuestList)

We now have 4 guests at the party: Christy is in index 0, Darla is in index 1, Fran in index 2, and Ginger who has moved to index 3.

Zara realizes that there is one person who has been there the entire time, but is not on the list – herself. Since she has been there the entire time, she should be placed at the bottom of the deque.

myGuestList.appendleft("Zara")
print(myGuestList)

We now have 5 people at the party: Zara is in index 0, Christy moves index 1, Darla moves to index 2, Fran moves to index 3, and Ginger moves to index 4.

Everyone, including Zara agrees that the party is pretty lame and that there is a better party down the street. So, everyone is going to leave the party.

myGuestList.clear()
print(myGuestList)

We now have nobody at the party and the deque is empty!

A Real Final Exam: Computer Science

Well, since entering K-12 education in the 2004/2005 school year, I have now written and administered my first “real” semester exams!

While I have always given exams at the conclusion of the semesters, I have never really given a genuine exam “experience”. There would be a test. That test usually consisted of 50 questions. 25 of the questions were True/False and 25 were Multiple Choice. The students were given a single sentence review guide of “Always Be True to Yourself”.

Now, with that as the review guide, I think you could safely guess that the answers were “B” and “True”. Your guess would be correct. Sadly, I did have students fail that test.

The test was not a “give-me grade” since there was usually a major end-of-year project that the majority of their semester grade was based upon. This final was created so we could simply check a box that said we gave a paper final.

This year, I opted to write and administer a genuine rigorous exam as I was not using any major end-of-year projects.

Computer Science (EOY) Final Exam – Test

Computer Science (EOY) Final Exam – Answer Key

As you can see, this is a bit more rigorous of a test. In fact, all of the questions require a calculated answer.

Once the tests are completed, I will analyze student performance in another post.

Python Recursion and Factorial

As the final Computer Science lesson of the 2016/2017 academic year, I reviewed the somewhat concept of recursion in the Python programming language. In this review, I used the mathematical concept of factorial to discuss recursion.

#Program Name: Recursion Sample
#Programmer Name: Eric Evans, M.Ed.
#Program Description: Provide a functional example of a recursion problem in Computer Science using the mathematical concept of factorial.
#
#Define function named factorial which will have an input value of n.
def factorial(n):
    print("Factorial has been called with n = " + str(n))
    if n == 1:
        return 1
    else:
        result = n * factorial(n-1)
        print(n,"! = ",result)
        return result
#Output the function factorial with an input value of 4.
print(factorial(4))

Let’s pull this concept apart line-by-line.

Lines 1 through 5 and line 14 are comment lines and have no real bearing on the program. They simply exist for documentation purposes.

At line 6, we declare a new function named “factorial” that will receive an input of “n”. This is done using the def or define call in Python. The “factorial” function occupies lines 6 through 13.

On line 7, we output the text “Factorial has been called with n = ” concatenated with the value of “n” cast as a string.

On lines 8 and 9, we enter the first part of a conditional statement. At line 8, we use a Boolean equals to see if “n” is equal to 1. If “n” is equal to 1, then line 8 executes and returns the value “1”.

Line 10 begins the process of addressing what to do if “n” does not equal 1.

On line 11, we declare a variable named “result”, which is defined as the value of “n” multiplied by the value of the “factorial” function with an input value that is one less than the current value of “n”.

Line 12 is simply allowing us to see the factorial value of the current “n” value each time through the loop.

Line 13 returns the value of the variable named “result”.

Line 15 calls the “factorial” function and provides it the necessary input to process. In this case, it is a 4.

Now, let’s see what happens when we run this code:

Factorial has been called with n = 4
Factorial has been called with n = 3
Factorial has been called with n = 2
Factorial has been called with n = 1
2 ! =  2
3 ! =  6
4 ! =  24
24

So, let’s see what’s going on with this output.

Lines 1 through 4 of the output are generated by line 7 of the code. That code displays the static words with the dynamic output of the value of “n”. Notice that each time through the loop, it decremented by 1.

Looking at lines 5 through 7 of the output, we see that the calculations actually start with the lowest factorial number of 2 and increment by 1.

Now, if you notice, the way the calculation was coded on line 11, we are performing the following:

  • (Step 1)  4! = 4 X 3!
    • This is the original problem. Solve for 4!, but it is defined needing to know the value of 3!, which is defined in step 2.
  • (Step 2)  3! = 3 X 2!
    • To solve step 1, we need to know the value of 3!. However, it is defined needing to know the value of 2!, which is defined in step 3.
  • (Step 3)  2! = 2 X 1!
    • To solve step 2, we need to know the value of 2!. However, it is defined needing to know the value of 1!, which is defined in step 4.
  • (Step 4)  1! = 1
    • To solve 3, we need to know the value of 1!. It has a given value of 1.
  • (Step 5)  2! = 2 X 1 = 2
    • Now, that we know the value of 1!, we can calculate the value of 2!.
  • (Step 6)  3! = 3 X 2 = 6
    • Now that we know the value of 2!, we can calculate the value of 3!.
  • (Step 7)  4! = 4 X 6 = 24
    • Now that we know the value of 3!, we can calculate the value of 4!, which was the original problem.

As you can see, the final solution is dependent upon the solution of a previous step, which was dependent upon the solution of a previous step, which was dependent upon the solution of a previous step, which – well you get the idea. This is the basic concept of recursion.